From e0fcbf7a4628e5553ace4373aafa99916a3cd0e2 Mon Sep 17 00:00:00 2001 From: Radovan Sroka Date: Tue, 5 Dec 2023 14:39:21 +0100 Subject: [PATCH] RHEL 9.3.0.Z ERRATUM --- .sudo.metadata | 1 + linker.patch | 79 +++ sudo-1.9.13-CVE-2023-28486-7-1.patch | 31 + sudo-1.9.13-CVE-2023-28486-7-2.patch | 187 ++++++ sudo-1.9.13-CVE-2023-28486-7-3.patch | 884 ++++++++++++++++++++++++++ sudo-1.9.13-CVE-2023-28486-7-4.patch | 66 ++ sudo-1.9.13-CVE-2023-28486-7-5.patch | 559 ++++++++++++++++ sudo-1.9.13-CVE-2023-28486-7-6.patch | 39 ++ sudo-1.9.13-CVE-2023-28486-7-7.patch | 42 ++ sudo-1.9.13-CVE-2023-28486-7-8.patch | 56 ++ sudo-1.9.13-CVE-2023-28486-7-9.patch | 910 +++++++++++++++++++++++++++ sudo-1.9.15-CVE-2023-42465.patch | 598 ++++++++++++++++++ sudo.spec | 56 +- 13 files changed, 3499 insertions(+), 9 deletions(-) create mode 100644 .sudo.metadata create mode 100644 linker.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-1.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-2.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-3.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-4.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-5.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-6.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-7.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-8.patch create mode 100644 sudo-1.9.13-CVE-2023-28486-7-9.patch create mode 100644 sudo-1.9.15-CVE-2023-42465.patch diff --git a/.sudo.metadata b/.sudo.metadata new file mode 100644 index 0000000..e05f83e --- /dev/null +++ b/.sudo.metadata @@ -0,0 +1 @@ +08bde247a1e08bc881eec43e09733f7ca06408f5 sudo-1.9.5p2.tar.gz diff --git a/linker.patch b/linker.patch new file mode 100644 index 0000000..84ee434 --- /dev/null +++ b/linker.patch @@ -0,0 +1,79 @@ +From ecaa9cd08d25870ec89fec82cf17c6cdaa4c7912 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Sat, 6 Feb 2021 08:36:01 -0700 +Subject: [PATCH] Add libsudo_eventlog.la as a dependency of libsudo_iolog.la + No longer need to link against libsudo_eventlog.la in sudoers. + +--- + lib/iolog/Makefile.in | 7 ++++--- + plugins/sudoers/Makefile.in | 8 ++++---- + 2 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/lib/iolog/Makefile.in b/lib/iolog/Makefile.in +index 2ae9c1b42..8fbc76c98 100644 +--- a/lib/iolog/Makefile.in ++++ b/lib/iolog/Makefile.in +@@ -1,7 +1,7 @@ + # + # SPDX-License-Identifier: ISC + # +-# Copyright (c) 2011-2020 Todd C. Miller ++# Copyright (c) 2011-2021 Todd C. Miller + # + # Permission to use, copy, modify, and distribute this software for any + # purpose with or without fee is hereby granted, provided that the above +@@ -36,7 +36,8 @@ CC = @CC@ + LIBTOOL = @LIBTOOL@ + + # Libraries +-LT_LIBS = $(top_builddir)/lib/util/libsudo_util.la ++LT_LIBS = $(top_builddir)/lib/eventlog/libsudo_eventlog.la \ ++ $(top_builddir)/lib/util/libsudo_util.la + LIBS = @LIBS@ @ZLIB@ $(LT_LIBS) + + # C preprocessor flags +@@ -76,7 +77,7 @@ PVS_LOG_OPTS = -a 'GA:1,2' -e -t errorfile -d $(PVS_IGNORE) + + # Regression tests + TEST_PROGS = check_iolog_json check_iolog_mkpath check_iolog_path check_iolog_util host_port_test +-TEST_LIBS = @LIBS@ $(top_builddir)/lib/eventlog/libsudo_eventlog.la ++TEST_LIBS = @LIBS@ + TEST_LDFLAGS = @LDFLAGS@ + + # Set to non-empty for development mode +diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in +index 77d54553b..8eadf479d 100644 +--- a/plugins/sudoers/Makefile.in ++++ b/plugins/sudoers/Makefile.in +@@ -1,7 +1,7 @@ + # + # SPDX-License-Identifier: ISC + # +-# Copyright (c) 1996, 1998-2005, 2007-2020 ++# Copyright (c) 1996, 1998-2005, 2007-2021 + # Todd C. Miller + # + # Permission to use, copy, modify, and distribute this software for any +@@ -61,8 +61,8 @@ LIBLOGSRV = @LIBLOGSRV@ + LIBUTIL = $(top_builddir)/lib/util/libsudo_util.la + LIBS = $(LIBUTIL) + NET_LIBS = @NET_LIBS@ +-SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ @LIBTLS@ $(NET_LIBS) $(LIBIOLOG) $(LIBEVENTLOG) $(LIBLOGSRV) +-REPLAY_LIBS = @REPLAY_LIBS@ $(LIBEVENTLOG) $(LIBIOLOG) ++SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ @LIBTLS@ $(NET_LIBS) $(LIBIOLOG) $(LIBLOGSRV) ++REPLAY_LIBS = @REPLAY_LIBS@ $(LIBIOLOG) + VISUDO_LIBS = $(NET_LIBS) + CVTSUDOERS_LIBS = $(NET_LIBS) + TESTSUDOERS_LIBS = $(NET_LIBS) +@@ -323,7 +323,7 @@ check_hexchar: $(CHECK_HEXCHAR_OBJS) $(LIBUTIL) + $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_HEXCHAR_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) + + check_iolog_plugin: $(CHECK_IOLOG_PLUGIN_OBJS) $(LIBUTIL) $(LIBIOLOG) $(LIBLOGSRV) +- $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PLUGIN_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBIOLOG) $(LIBEVENTLOG) $(LIBLOGSRV) @LIBTLS@ ++ $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PLUGIN_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBIOLOG) $(LIBLOGSRV) @LIBTLS@ + + check_starttime: $(CHECK_STARTTIME_OBJS) $(LIBUTIL) + $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_STARTTIME_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-1.patch b/sudo-1.9.13-CVE-2023-28486-7-1.patch new file mode 100644 index 0000000..6f2c614 --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-1.patch @@ -0,0 +1,31 @@ +From e5c1778e7dd32ff3ed8cf969540404c9c0e6d5a1 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Thu, 18 Feb 2021 08:32:13 -0700 +Subject: [PATCH] When logging JSON to syslog, wrap the contents in a "sudo" + object. This makes it easier for log parsers to identify what is a sudo log + entry. + +--- + lib/eventlog/eventlog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c +index 1f0183b1b..e6f744da5 100644 +--- a/lib/eventlog/eventlog.c ++++ b/lib/eventlog/eventlog.c +@@ -950,10 +950,10 @@ do_syslog_json(int pri, int event_type, const char *reason, + if (json_str == NULL) + debug_return_bool(false); + +- /* Syslog it with a @cee: prefix */ ++ /* Syslog it in a sudo object with a @cee: prefix. */ + /* TODO: use evl_conf.syslog_maxlen to break up long messages. */ + evl_conf.open_log(EVLOG_SYSLOG, NULL); +- syslog(pri, "@cee:{%s}", json_str); ++ syslog(pri, "@cee:{\"sudo\":{%s}}", json_str); + evl_conf.close_log(EVLOG_SYSLOG, NULL); + free(json_str); + debug_return_bool(true); +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-2.patch b/sudo-1.9.13-CVE-2023-28486-7-2.patch new file mode 100644 index 0000000..bf3ea04 --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-2.patch @@ -0,0 +1,187 @@ +From f399c449ad6fc7412588998aa92b52323ef63ee5 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Wed, 24 Feb 2021 13:59:17 -0700 +Subject: [PATCH] Move eventlog_free() into its own file. + +--- + MANIFEST | 1 + + lib/eventlog/Makefile.in | 14 ++++++- + lib/eventlog/eventlog.c | 37 ------------------ + lib/eventlog/eventlog_free.c | 73 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 87 insertions(+), 38 deletions(-) + create mode 100644 lib/eventlog/eventlog_free.c + +diff --git a/MANIFEST b/MANIFEST +index 8c5a57ae8..a2bed131d 100644 +--- a/MANIFEST ++++ b/MANIFEST +@@ -104,6 +104,7 @@ include/sudo_util.h + install-sh + lib/eventlog/Makefile.in + lib/eventlog/eventlog.c ++lib/eventlog/eventlog_free.c + lib/eventlog/logwrap.c + lib/eventlog/regress/logwrap/check_wrap.c + lib/eventlog/regress/logwrap/check_wrap.in +diff --git a/lib/eventlog/Makefile.in b/lib/eventlog/Makefile.in +index 8790ac1ae..24c2dbce9 100644 +--- a/lib/eventlog/Makefile.in ++++ b/lib/eventlog/Makefile.in +@@ -82,7 +82,7 @@ SHELL = @SHELL@ + + TEST_PROGS = check_wrap + +-LIBEVENTLOG_OBJS = eventlog.lo logwrap.lo ++LIBEVENTLOG_OBJS = eventlog.lo eventlog_free.lo logwrap.lo + + IOBJS = $(LIBEVENTLOG_OBJS:.lo=.i) + +@@ -213,6 +213,18 @@ eventlog.i: $(srcdir)/eventlog.c $(incdir)/compat/stdbool.h \ + $(CC) -E -o $@ $(CPPFLAGS) $< + eventlog.plog: eventlog.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/eventlog.c --i-file $< --output-file $@ ++eventlog_free.lo: $(srcdir)/eventlog_free.c $(incdir)/compat/stdbool.h \ ++ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ ++ $(incdir)/sudo_eventlog.h $(incdir)/sudo_queue.h \ ++ $(incdir)/sudo_util.h $(top_builddir)/config.h ++ $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/eventlog_free.c ++eventlog_free.i: $(srcdir)/eventlog_free.c $(incdir)/compat/stdbool.h \ ++ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ ++ $(incdir)/sudo_eventlog.h $(incdir)/sudo_queue.h \ ++ $(incdir)/sudo_util.h $(top_builddir)/config.h ++ $(CC) -E -o $@ $(CPPFLAGS) $< ++eventlog_free.plog: eventlog_free.i ++ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/eventlog_free.c --i-file $< --output-file $@ + logwrap.lo: $(srcdir)/logwrap.c $(incdir)/compat/stdbool.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_eventlog.h $(incdir)/sudo_queue.h \ +diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c +index e6f744da5..c8c9b7ba5 100644 +--- a/lib/eventlog/eventlog.c ++++ b/lib/eventlog/eventlog.c +@@ -1256,43 +1256,6 @@ eventlog_alert(const struct eventlog *evlog, int flags, + debug_return_bool(ret); + } + +-/* +- * Free the strings in a struct eventlog. +- */ +-void +-eventlog_free(struct eventlog *evlog) +-{ +- int i; +- debug_decl(eventlog_free, SUDO_DEBUG_UTIL); +- +- if (evlog != NULL) { +- free(evlog->iolog_path); +- free(evlog->command); +- free(evlog->cwd); +- free(evlog->runchroot); +- free(evlog->runcwd); +- free(evlog->rungroup); +- free(evlog->runuser); +- free(evlog->submithost); +- free(evlog->submituser); +- free(evlog->submitgroup); +- free(evlog->ttyname); +- if (evlog->argv != NULL) { +- for (i = 0; evlog->argv[i] != NULL; i++) +- free(evlog->argv[i]); +- free(evlog->argv); +- } +- if (evlog->envp != NULL) { +- for (i = 0; evlog->envp[i] != NULL; i++) +- free(evlog->envp[i]); +- free(evlog->envp); +- } +- free(evlog); +- } +- +- debug_return; +-} +- + static FILE * + eventlog_stub_open_log(int type, const char *logfile) + { +diff --git a/lib/eventlog/eventlog_free.c b/lib/eventlog/eventlog_free.c +new file mode 100644 +index 000000000..49583b61c +--- /dev/null ++++ b/lib/eventlog/eventlog_free.c +@@ -0,0 +1,73 @@ ++/* ++ * SPDX-License-Identifier: ISC ++ * ++ * Copyright (c) 2020 Todd C. Miller ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ * ++ * Sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F39502-99-1-0512. ++ */ ++ ++/* ++ * This is an open source non-commercial project. Dear PVS-Studio, please check it. ++ * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com ++ */ ++ ++#include ++ ++#include ++#include ++ ++#include "sudo_compat.h" ++#include "sudo_debug.h" ++#include "sudo_eventlog.h" ++#include "sudo_util.h" ++ ++/* ++ * Free the strings in a struct eventlog. ++ */ ++void ++eventlog_free(struct eventlog *evlog) ++{ ++ int i; ++ debug_decl(eventlog_free, SUDO_DEBUG_UTIL); ++ ++ if (evlog != NULL) { ++ free(evlog->iolog_path); ++ free(evlog->command); ++ free(evlog->cwd); ++ free(evlog->runchroot); ++ free(evlog->runcwd); ++ free(evlog->rungroup); ++ free(evlog->runuser); ++ free(evlog->submithost); ++ free(evlog->submituser); ++ free(evlog->submitgroup); ++ free(evlog->ttyname); ++ if (evlog->argv != NULL) { ++ for (i = 0; evlog->argv[i] != NULL; i++) ++ free(evlog->argv[i]); ++ free(evlog->argv); ++ } ++ if (evlog->envp != NULL) { ++ for (i = 0; evlog->envp[i] != NULL; i++) ++ free(evlog->envp[i]); ++ free(evlog->envp); ++ } ++ free(evlog); ++ } ++ ++ debug_return; ++} +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-3.patch b/sudo-1.9.13-CVE-2023-28486-7-3.patch new file mode 100644 index 0000000..b7bfbce --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-3.patch @@ -0,0 +1,884 @@ +From 412858272365f0e6d6f8873e794f64374da8fa06 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Wed, 24 Feb 2021 14:25:39 -0700 +Subject: [PATCH] Move eventlog config code into eventlog_conf.c + +--- + MANIFEST | 1 + + include/sudo_eventlog.h | 3 +- + lib/eventlog/Makefile.in | 20 ++- + lib/eventlog/eventlog.c | 292 +++++++---------------------------- + lib/eventlog/eventlog_conf.c | 226 +++++++++++++++++++++++++++ + 5 files changed, 303 insertions(+), 239 deletions(-) + create mode 100644 lib/eventlog/eventlog_conf.c + +diff --git a/MANIFEST b/MANIFEST +index a2bed131d..c960e3e8b 100644 +--- a/MANIFEST ++++ b/MANIFEST +@@ -104,6 +104,7 @@ include/sudo_util.h + install-sh + lib/eventlog/Makefile.in + lib/eventlog/eventlog.c ++lib/eventlog/eventlog_conf.c + lib/eventlog/eventlog_free.c + lib/eventlog/logwrap.c + lib/eventlog/regress/logwrap/check_wrap.c +diff --git a/include/sudo_eventlog.h b/include/sudo_eventlog.h +index 127ee5dd8..e40622a51 100644 +--- a/include/sudo_eventlog.h ++++ b/include/sudo_eventlog.h +@@ -66,7 +66,7 @@ enum eventlog_format { + #define EVENTLOG_INDENT " " + + /* +- * Event log config, used with eventlog_setconf() ++ * Event log config, used with eventlog_getconf() + */ + struct eventlog_config { + int type; +@@ -144,5 +144,6 @@ void eventlog_set_mailto(const char *to_addr); + void eventlog_set_mailsub(const char *subject); + void eventlog_set_open_log(FILE *(*fn)(int type, const char *)); + void eventlog_set_close_log(void (*fn)(int type, FILE *)); ++const struct eventlog_config *eventlog_getconf(void); + + #endif /* SUDO_EVENTLOG_H */ +diff --git a/lib/eventlog/Makefile.in b/lib/eventlog/Makefile.in +index 24c2dbce9..02236f70b 100644 +--- a/lib/eventlog/Makefile.in ++++ b/lib/eventlog/Makefile.in +@@ -82,7 +82,7 @@ SHELL = @SHELL@ + + TEST_PROGS = check_wrap + +-LIBEVENTLOG_OBJS = eventlog.lo eventlog_free.lo logwrap.lo ++LIBEVENTLOG_OBJS = eventlog.lo eventlog_conf.lo eventlog_free.lo logwrap.lo + + IOBJS = $(LIBEVENTLOG_OBJS:.lo=.i) + +@@ -213,6 +213,24 @@ eventlog.i: $(srcdir)/eventlog.c $(incdir)/compat/stdbool.h \ + $(CC) -E -o $@ $(CPPFLAGS) $< + eventlog.plog: eventlog.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/eventlog.c --i-file $< --output-file $@ ++eventlog_conf.lo: $(srcdir)/eventlog_conf.c $(incdir)/compat/stdbool.h \ ++ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ ++ $(incdir)/sudo_eventlog.h $(incdir)/sudo_fatal.h \ ++ $(incdir)/sudo_gettext.h $(incdir)/sudo_json.h \ ++ $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ ++ $(incdir)/sudo_util.h $(top_builddir)/config.h \ ++ $(top_builddir)/pathnames.h ++ $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/eventlog_conf.c ++eventlog_conf.i: $(srcdir)/eventlog_conf.c $(incdir)/compat/stdbool.h \ ++ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ ++ $(incdir)/sudo_eventlog.h $(incdir)/sudo_fatal.h \ ++ $(incdir)/sudo_gettext.h $(incdir)/sudo_json.h \ ++ $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ ++ $(incdir)/sudo_util.h $(top_builddir)/config.h \ ++ $(top_builddir)/pathnames.h ++ $(CC) -E -o $@ $(CPPFLAGS) $< ++eventlog_conf.plog: eventlog_conf.i ++ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/eventlog_conf.c --i-file $< --output-file $@ + eventlog_free.lo: $(srcdir)/eventlog_free.c $(incdir)/compat/stdbool.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_eventlog.h $(incdir)/sudo_queue.h \ +diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c +index c8c9b7ba5..e7505d9d9 100644 +--- a/lib/eventlog/eventlog.c ++++ b/lib/eventlog/eventlog.c +@@ -75,35 +75,6 @@ + isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \ + (s)[8] == '\0') + +-static FILE *eventlog_stub_open_log(int type, const char *logfile); +-static void eventlog_stub_close_log(int type, FILE *fp); +- +-/* Eventlog config settings (default values). */ +-static struct eventlog_config evl_conf = { +- EVLOG_NONE, /* type */ +- EVLOG_SUDO, /* format */ +- LOG_NOTICE, /* syslog_acceptpri */ +- LOG_ALERT, /* syslog_rejectpri */ +- LOG_ALERT, /* syslog_alertpri */ +- MAXSYSLOGLEN, /* syslog_maxlen */ +- 0, /* file_maxlen */ +- ROOT_UID, /* mailuid */ +- false, /* omit_hostname */ +- _PATH_SUDO_LOGFILE, /* logpath */ +- "%h %e %T", /* time_fmt */ +-#ifdef _PATH_SUDO_SENDMAIL +- _PATH_SUDO_SENDMAIL, /* mailerpath */ +-#else +- NULL, /* mailerpath (disabled) */ +-#endif +- "-t", /* mailerflags */ +- NULL, /* mailfrom */ +- MAILTO, /* mailto */ +- N_(MAILSUBJECT), /* mailsub */ +- eventlog_stub_open_log, /* open_log */ +- eventlog_stub_close_log /* close_log */ +-}; +- + /* + * Allocate and fill in a new logline. + */ +@@ -111,6 +82,7 @@ static char * + new_logline(int flags, const char *message, const char *errstr, + const struct eventlog *evlog) + { ++ const struct eventlog_config *evl_conf = eventlog_getconf(); + char *line = NULL, *evstr = NULL; + const char *iolog_file = evlog->iolog_file; + const char *tty, *tsid = NULL; +@@ -159,7 +131,7 @@ new_logline(int flags, const char *message, const char *errstr, + len += strlen(message) + 3; + if (errstr != NULL) + len += strlen(errstr) + 3; +- if (evlog->submithost != NULL && !evl_conf.omit_hostname) ++ if (evlog->submithost != NULL && !evl_conf->omit_hostname) + len += sizeof(LL_HOST_STR) + 2 + strlen(evlog->submithost); + if (tty != NULL) + len += sizeof(LL_TTY_STR) + 2 + strlen(tty); +@@ -218,7 +190,7 @@ new_logline(int flags, const char *message, const char *errstr, + strlcat(line, " ; ", len) >= len) + goto toobig; + } +- if (evlog->submithost != NULL && !evl_conf.omit_hostname) { ++ if (evlog->submithost != NULL && !evl_conf->omit_hostname) { + if (strlcat(line, LL_HOST_STR, len) >= len || + strlcat(line, evlog->submithost, len) >= len || + strlcat(line, " ; ", len) >= len) +@@ -331,8 +303,9 @@ closefrom_nodebug(int lowfd) + static void __attribute__((__noreturn__)) + exec_mailer(int pipein) + { ++ const struct eventlog_config *evl_conf = eventlog_getconf(); + char *last, *mflags, *p, *argv[MAX_MAILFLAGS + 1]; +- const char *mpath = evl_conf.mailerpath; ++ const char *mpath = evl_conf->mailerpath; + int i; + char * const root_envp[] = { + "HOME=/", +@@ -356,7 +329,7 @@ exec_mailer(int pipein) + } + + /* Build up an argv based on the mailer path and flags */ +- if ((mflags = strdup(evl_conf.mailerflags)) == NULL) { ++ if ((mflags = strdup(evl_conf->mailerflags)) == NULL) { + syslog(LOG_ERR, _("unable to allocate memory")); // -V618 + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); + _exit(127); +@@ -379,14 +352,14 @@ exec_mailer(int pipein) + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to change uid to %u", + ROOT_UID); + } +- if (evl_conf.mailuid != ROOT_UID) { +- if (setuid(evl_conf.mailuid) != 0) { ++ if (evl_conf->mailuid != ROOT_UID) { ++ if (setuid(evl_conf->mailuid) != 0) { + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to change uid to %u", +- (unsigned int)evl_conf.mailuid); ++ (unsigned int)evl_conf->mailuid); + } + } + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); +- if (evl_conf.mailuid == ROOT_UID) ++ if (evl_conf->mailuid == ROOT_UID) + execve(mpath, argv, root_envp); + else + execv(mpath, argv); +@@ -400,7 +373,8 @@ exec_mailer(int pipein) + static bool + send_mail(const struct eventlog *evlog, const char *fmt, ...) + { +- const char *cp, *timefmt = evl_conf.time_fmt; ++ const struct eventlog_config *evl_conf = eventlog_getconf(); ++ const char *cp, *timefmt = evl_conf->time_fmt; + char timebuf[1024]; + struct tm *tm; + time_t now; +@@ -415,11 +389,11 @@ send_mail(const struct eventlog *evlog, const char *fmt, ...) + debug_decl(send_mail, SUDO_DEBUG_UTIL); + + /* If mailer is disabled just return. */ +- if (evl_conf.mailerpath == NULL || evl_conf.mailto == NULL) ++ if (evl_conf->mailerpath == NULL || evl_conf->mailto == NULL) + debug_return_bool(true); + + /* Make sure the mailer exists and is a regular file. */ +- if (stat(evl_conf.mailerpath, &sb) != 0 || !S_ISREG(sb.st_mode)) ++ if (stat(evl_conf->mailerpath, &sb) != 0 || !S_ISREG(sb.st_mode)) + debug_return_bool(false); + + time(&now); +@@ -516,11 +490,11 @@ send_mail(const struct eventlog *evlog, const char *fmt, ...) + + /* Pipes are all setup, send message. */ + (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ", +- evl_conf.mailto, +- evl_conf.mailfrom ? evl_conf.mailfrom : ++ evl_conf->mailto, ++ evl_conf->mailfrom ? evl_conf->mailfrom : + (evlog ? evlog->submituser : "root"), + "auto-generated"); +- for (cp = _(evl_conf.mailsub); *cp; cp++) { ++ for (cp = _(evl_conf->mailsub); *cp; cp++) { + /* Expand escapes in the subject */ + if (*cp == '%' && *(cp+1) != '%') { + switch (*(++cp)) { +@@ -576,7 +550,8 @@ static bool + json_add_timestamp(struct json_container *json, const char *name, + const struct timespec *ts) + { +- const char *timefmt = evl_conf.time_fmt; ++ const struct eventlog_config *evl_conf = eventlog_getconf(); ++ const char *timefmt = evl_conf->time_fmt; + struct json_value json_value; + time_t secs = ts->tv_sec; + char timebuf[1024]; +@@ -880,12 +855,13 @@ bad: + static bool + do_syslog_sudo(int pri, char *logline, const struct eventlog *evlog) + { ++ const struct eventlog_config *evl_conf = eventlog_getconf(); + size_t len, maxlen; + char *p, *tmp, save; + const char *fmt; + debug_decl(do_syslog_sudo, SUDO_DEBUG_UTIL); + +- evl_conf.open_log(EVLOG_SYSLOG, NULL); ++ evl_conf->open_log(EVLOG_SYSLOG, NULL); + + if (evlog == NULL) { + /* Not a command, just log it as-is. */ +@@ -897,7 +873,7 @@ do_syslog_sudo(int pri, char *logline, const struct eventlog *evlog) + * Log the full line, breaking into multiple syslog(3) calls if necessary + */ + fmt = _("%8s : %s"); +- maxlen = evl_conf.syslog_maxlen - ++ maxlen = evl_conf->syslog_maxlen - + (strlen(fmt) - 5 + strlen(evlog->submituser)); + for (p = logline; *p != '\0'; ) { + len = strlen(p); +@@ -926,11 +902,11 @@ do_syslog_sudo(int pri, char *logline, const struct eventlog *evlog) + p += len; + } + fmt = _("%8s : (command continued) %s"); +- maxlen = evl_conf.syslog_maxlen - ++ maxlen = evl_conf->syslog_maxlen - + (strlen(fmt) - 5 + strlen(evlog->submituser)); + } + done: +- evl_conf.close_log(EVLOG_SYSLOG, NULL); ++ evl_conf->close_log(EVLOG_SYSLOG, NULL); + + debug_return_bool(true); + } +@@ -941,6 +917,7 @@ do_syslog_json(int pri, int event_type, const char *reason, + const struct timespec *event_time, + eventlog_json_callback_t info_cb, void *info) + { ++ const struct eventlog_config *evl_conf = eventlog_getconf(); + char *json_str; + debug_decl(do_syslog_json, SUDO_DEBUG_UTIL); + +@@ -951,10 +928,10 @@ do_syslog_json(int pri, int event_type, const char *reason, + debug_return_bool(false); + + /* Syslog it in a sudo object with a @cee: prefix. */ +- /* TODO: use evl_conf.syslog_maxlen to break up long messages. */ +- evl_conf.open_log(EVLOG_SYSLOG, NULL); ++ /* TODO: use evl_conf->syslog_maxlen to break up long messages. */ ++ evl_conf->open_log(EVLOG_SYSLOG, NULL); + syslog(pri, "@cee:{\"sudo\":{%s}}", json_str); +- evl_conf.close_log(EVLOG_SYSLOG, NULL); ++ evl_conf->close_log(EVLOG_SYSLOG, NULL); + free(json_str); + debug_return_bool(true); + } +@@ -967,13 +944,14 @@ do_syslog(int event_type, int flags, const char *reason, const char *errstr, + const struct eventlog *evlog, const struct timespec *event_time, + eventlog_json_callback_t info_cb, void *info) + { ++ const struct eventlog_config *evl_conf = eventlog_getconf(); + char *logline = NULL; + bool ret = false; + int pri; + debug_decl(do_syslog, SUDO_DEBUG_UTIL); + + /* Sudo format logs and mailed logs use the same log line format. */ +- if (evl_conf.format == EVLOG_SUDO || ISSET(flags, EVLOG_MAIL)) { ++ if (evl_conf->format == EVLOG_SUDO || ISSET(flags, EVLOG_MAIL)) { + logline = new_logline(flags, reason, errstr, evlog); + if (logline == NULL) + debug_return_bool(false); +@@ -992,13 +970,13 @@ do_syslog(int event_type, int flags, const char *reason, const char *errstr, + + switch (event_type) { + case EVLOG_ACCEPT: +- pri = evl_conf.syslog_acceptpri; ++ pri = evl_conf->syslog_acceptpri; + break; + case EVLOG_REJECT: +- pri = evl_conf.syslog_rejectpri; ++ pri = evl_conf->syslog_rejectpri; + break; + case EVLOG_ALERT: +- pri = evl_conf.syslog_alertpri; ++ pri = evl_conf->syslog_alertpri; + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +@@ -1012,7 +990,7 @@ do_syslog(int event_type, int flags, const char *reason, const char *errstr, + debug_return_bool(true); + } + +- switch (evl_conf.format) { ++ switch (evl_conf->format) { + case EVLOG_SUDO: + ret = do_syslog_sudo(pri, logline, evlog); + break; +@@ -1022,7 +1000,7 @@ do_syslog(int event_type, int flags, const char *reason, const char *errstr, + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +- "unexpected eventlog format %d", evl_conf.format); ++ "unexpected eventlog format %d", evl_conf->format); + break; + } + free(logline); +@@ -1034,9 +1012,10 @@ static bool + do_logfile_sudo(const char *logline, const struct eventlog *evlog, + const struct timespec *event_time) + { ++ const struct eventlog_config *evl_conf = eventlog_getconf(); + char *full_line, timebuf[8192], *timestr = NULL; +- const char *timefmt = evl_conf.time_fmt; +- const char *logfile = evl_conf.logpath; ++ const char *timefmt = evl_conf->time_fmt; ++ const char *logfile = evl_conf->logpath; + time_t tv_sec = event_time->tv_sec; + struct tm *timeptr; + bool ret = false; +@@ -1044,7 +1023,7 @@ do_logfile_sudo(const char *logline, const struct eventlog *evlog, + int len; + debug_decl(do_logfile_sudo, SUDO_DEBUG_UTIL); + +- if ((fp = evl_conf.open_log(EVLOG_FILE, logfile)) == NULL) ++ if ((fp = evl_conf->open_log(EVLOG_FILE, logfile)) == NULL) + debug_return_bool(false); + + if (!sudo_lock_file(fileno(fp), SUDO_LOCK)) { +@@ -1067,7 +1046,7 @@ do_logfile_sudo(const char *logline, const struct eventlog *evlog, + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + goto done; + } +- eventlog_writeln(fp, full_line, len, evl_conf.file_maxlen); ++ eventlog_writeln(fp, full_line, len, evl_conf->file_maxlen); + (void)fflush(fp); + if (ferror(fp)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, +@@ -1078,7 +1057,7 @@ do_logfile_sudo(const char *logline, const struct eventlog *evlog, + + done: + (void)sudo_lock_file(fileno(fp), SUDO_UNLOCK); +- evl_conf.close_log(EVLOG_FILE, fp); ++ evl_conf->close_log(EVLOG_FILE, fp); + debug_return_bool(ret); + } + +@@ -1087,14 +1066,15 @@ do_logfile_json(int event_type, const char *reason, const char *errstr, + const struct eventlog *evlog, const struct timespec *event_time, + eventlog_json_callback_t info_cb, void *info) + { +- const char *logfile = evl_conf.logpath; ++ const struct eventlog_config *evl_conf = eventlog_getconf(); ++ const char *logfile = evl_conf->logpath; + struct stat sb; + char *json_str; + int ret = false; + FILE *fp; + debug_decl(do_logfile_json, SUDO_DEBUG_UTIL); + +- if ((fp = evl_conf.open_log(EVLOG_FILE, logfile)) == NULL) ++ if ((fp = evl_conf->open_log(EVLOG_FILE, logfile)) == NULL) + debug_return_bool(false); + + json_str = format_json(event_type, reason, errstr, evlog, event_time, +@@ -1135,7 +1115,7 @@ do_logfile_json(int event_type, const char *reason, const char *errstr, + done: + free(json_str); + (void)sudo_lock_file(fileno(fp), SUDO_UNLOCK); +- evl_conf.close_log(EVLOG_FILE, fp); ++ evl_conf->close_log(EVLOG_FILE, fp); + debug_return_bool(ret); + } + +@@ -1144,12 +1124,13 @@ do_logfile(int event_type, int flags, const char *reason, const char *errstr, + const struct eventlog *evlog, const struct timespec *event_time, + eventlog_json_callback_t info_cb, void *info) + { ++ const struct eventlog_config *evl_conf = eventlog_getconf(); + bool ret = false; + char *logline = NULL; + debug_decl(do_logfile, SUDO_DEBUG_UTIL); + + /* Sudo format logs and mailed logs use the same log line format. */ +- if (evl_conf.format == EVLOG_SUDO || ISSET(flags, EVLOG_MAIL)) { ++ if (evl_conf->format == EVLOG_SUDO || ISSET(flags, EVLOG_MAIL)) { + logline = new_logline(flags, reason, errstr, evlog); + if (logline == NULL) + debug_return_bool(false); +@@ -1166,7 +1147,7 @@ do_logfile(int event_type, int flags, const char *reason, const char *errstr, + } + } + +- switch (evl_conf.format) { ++ switch (evl_conf->format) { + case EVLOG_SUDO: + ret = do_logfile_sudo(logline ? logline : reason, evlog, event_time); + break; +@@ -1176,7 +1157,7 @@ do_logfile(int event_type, int flags, const char *reason, const char *errstr, + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +- "unexpected eventlog format %d", evl_conf.format); ++ "unexpected eventlog format %d", evl_conf->format); + break; + } + free(logline); +@@ -1188,7 +1169,8 @@ bool + eventlog_accept(const struct eventlog *evlog, int flags, + eventlog_json_callback_t info_cb, void *info) + { +- const int log_type = evl_conf.type; ++ const struct eventlog_config *evl_conf = eventlog_getconf(); ++ const int log_type = evl_conf->type; + bool ret = true; + debug_decl(log_accept, SUDO_DEBUG_UTIL); + +@@ -1214,7 +1196,8 @@ bool + eventlog_reject(const struct eventlog *evlog, int flags, const char *reason, + eventlog_json_callback_t info_cb, void *info) + { +- const int log_type = evl_conf.type; ++ const struct eventlog_config *evl_conf = eventlog_getconf(); ++ const int log_type = evl_conf->type; + bool ret = true; + debug_decl(log_reject, SUDO_DEBUG_UTIL); + +@@ -1237,7 +1220,8 @@ bool + eventlog_alert(const struct eventlog *evlog, int flags, + struct timespec *alert_time, const char *reason, const char *errstr) + { +- const int log_type = evl_conf.type; ++ const struct eventlog_config *evl_conf = eventlog_getconf(); ++ const int log_type = evl_conf->type; + bool ret = true; + debug_decl(log_alert, SUDO_DEBUG_UTIL); + +@@ -1255,169 +1239,3 @@ eventlog_alert(const struct eventlog *evlog, int flags, + + debug_return_bool(ret); + } +- +-static FILE * +-eventlog_stub_open_log(int type, const char *logfile) +-{ +- debug_decl(eventlog_stub_open_log, SUDO_DEBUG_UTIL); +- sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, +- "open_log not set, using stub"); +- debug_return_ptr(NULL); +-} +- +-static void +-eventlog_stub_close_log(int type, FILE *fp) +-{ +- debug_decl(eventlog_stub_close_log, SUDO_DEBUG_UTIL); +- sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, +- "close_log not set, using stub"); +- debug_return; +-} +- +-/* +- * Set eventlog config settings. +- */ +- +-void +-eventlog_set_type(int type) +-{ +- evl_conf.type = type; +-} +- +-void +-eventlog_set_format(enum eventlog_format format) +-{ +- evl_conf.format = format; +-} +- +-void +-eventlog_set_syslog_acceptpri(int pri) +-{ +- evl_conf.syslog_acceptpri = pri; +-} +- +-void +-eventlog_set_syslog_rejectpri(int pri) +-{ +- evl_conf.syslog_rejectpri = pri; +-} +- +-void +-eventlog_set_syslog_alertpri(int pri) +-{ +- evl_conf.syslog_alertpri = pri; +-} +- +-void +-eventlog_set_syslog_maxlen(int len) +-{ +- evl_conf.syslog_maxlen = len; +-} +- +-void +-eventlog_set_file_maxlen(int len) +-{ +- evl_conf.file_maxlen = len; +-} +- +-void +-eventlog_set_mailuid(uid_t uid) +-{ +- evl_conf.mailuid = uid; +-} +- +-void +-eventlog_set_omit_hostname(bool omit_hostname) +-{ +- evl_conf.omit_hostname = omit_hostname; +-} +- +-void +-eventlog_set_logpath(const char *path) +-{ +- evl_conf.logpath = path; +-} +- +-void +-eventlog_set_time_fmt(const char *fmt) +-{ +- evl_conf.time_fmt = fmt; +-} +- +-void +-eventlog_set_mailerpath(const char *path) +-{ +- evl_conf.mailerpath = path; +-} +- +-void +-eventlog_set_mailerflags(const char *mflags) +-{ +- evl_conf.mailerflags = mflags; +-} +- +-void +-eventlog_set_mailfrom(const char *from_addr) +-{ +- evl_conf.mailfrom = from_addr; +-} +- +-void +-eventlog_set_mailto(const char *to_addr) +-{ +- evl_conf.mailto = to_addr; +-} +- +-void +-eventlog_set_mailsub(const char *subject) +-{ +- evl_conf.mailsub = subject; +-} +- +-void +-eventlog_set_open_log(FILE *(*fn)(int type, const char *)) +-{ +- evl_conf.open_log = fn; +-} +- +-void +-eventlog_set_close_log(void (*fn)(int type, FILE *)) +-{ +- evl_conf.close_log = fn; +-} +- +-bool +-eventlog_setconf(struct eventlog_config *conf) +-{ +- debug_decl(eventlog_setconf, SUDO_DEBUG_UTIL); +- +- if (conf != NULL) { +- memcpy(&evl_conf, conf, sizeof(evl_conf)); +- } else { +- memset(&evl_conf, 0, sizeof(evl_conf)); +- } +- +- /* Apply default values where possible. */ +- if (evl_conf.syslog_maxlen == 0) +- evl_conf.syslog_maxlen = MAXSYSLOGLEN; +- if (evl_conf.logpath == NULL) +- evl_conf.logpath = _PATH_SUDO_LOGFILE; +- if (evl_conf.time_fmt == NULL) +- evl_conf.time_fmt = "%h %e %T"; +-#ifdef _PATH_SUDO_SENDMAIL +- if (evl_conf.mailerpath == NULL) +- evl_conf.mailerpath = _PATH_SUDO_SENDMAIL; +-#endif +- if (evl_conf.mailerflags == NULL) +- evl_conf.mailerflags = "-t"; +- if (evl_conf.mailto == NULL) +- evl_conf.mailto = MAILTO; +- if (evl_conf.mailsub == NULL) +- evl_conf.mailsub = N_(MAILSUBJECT); +- if (evl_conf.open_log == NULL) +- evl_conf.open_log = eventlog_stub_open_log; +- if (evl_conf.close_log == NULL) +- evl_conf.close_log = eventlog_stub_close_log; +- +- debug_return_bool(true); +-} +diff --git a/lib/eventlog/eventlog_conf.c b/lib/eventlog/eventlog_conf.c +new file mode 100644 +index 000000000..8ad03851f +--- /dev/null ++++ b/lib/eventlog/eventlog_conf.c +@@ -0,0 +1,226 @@ ++/* ++ * SPDX-License-Identifier: ISC ++ * ++ * Copyright (c) 1994-1996, 1998-2020 Todd C. Miller ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ * ++ * Sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F39502-99-1-0512. ++ */ ++ ++/* ++ * This is an open source non-commercial project. Dear PVS-Studio, please check it. ++ * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pathnames.h" ++#include "sudo_compat.h" ++#include "sudo_debug.h" ++#include "sudo_eventlog.h" ++#include "sudo_fatal.h" ++#include "sudo_gettext.h" ++#include "sudo_json.h" ++#include "sudo_queue.h" ++#include "sudo_util.h" ++ ++static FILE *eventlog_stub_open_log(int type, const char *logfile); ++static void eventlog_stub_close_log(int type, FILE *fp); ++ ++/* Eventlog config settings (default values). */ ++static struct eventlog_config evl_conf = { ++ EVLOG_NONE, /* type */ ++ EVLOG_SUDO, /* format */ ++ LOG_NOTICE, /* syslog_acceptpri */ ++ LOG_ALERT, /* syslog_rejectpri */ ++ LOG_ALERT, /* syslog_alertpri */ ++ MAXSYSLOGLEN, /* syslog_maxlen */ ++ 0, /* file_maxlen */ ++ ROOT_UID, /* mailuid */ ++ false, /* omit_hostname */ ++ _PATH_SUDO_LOGFILE, /* logpath */ ++ "%h %e %T", /* time_fmt */ ++#ifdef _PATH_SUDO_SENDMAIL ++ _PATH_SUDO_SENDMAIL, /* mailerpath */ ++#else ++ NULL, /* mailerpath (disabled) */ ++#endif ++ "-t", /* mailerflags */ ++ NULL, /* mailfrom */ ++ MAILTO, /* mailto */ ++ N_(MAILSUBJECT), /* mailsub */ ++ eventlog_stub_open_log, /* open_log */ ++ eventlog_stub_close_log /* close_log */ ++}; ++ ++static FILE * ++eventlog_stub_open_log(int type, const char *logfile) ++{ ++ debug_decl(eventlog_stub_open_log, SUDO_DEBUG_UTIL); ++ sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, ++ "open_log not set, using stub"); ++ debug_return_ptr(NULL); ++} ++ ++static void ++eventlog_stub_close_log(int type, FILE *fp) ++{ ++ debug_decl(eventlog_stub_close_log, SUDO_DEBUG_UTIL); ++ sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, ++ "close_log not set, using stub"); ++ debug_return; ++} ++ ++/* ++ * eventlog config setters. ++ */ ++ ++void ++eventlog_set_type(int type) ++{ ++ evl_conf.type = type; ++} ++ ++void ++eventlog_set_format(enum eventlog_format format) ++{ ++ evl_conf.format = format; ++} ++ ++void ++eventlog_set_syslog_acceptpri(int pri) ++{ ++ evl_conf.syslog_acceptpri = pri; ++} ++ ++void ++eventlog_set_syslog_rejectpri(int pri) ++{ ++ evl_conf.syslog_rejectpri = pri; ++} ++ ++void ++eventlog_set_syslog_alertpri(int pri) ++{ ++ evl_conf.syslog_alertpri = pri; ++} ++ ++void ++eventlog_set_syslog_maxlen(int len) ++{ ++ evl_conf.syslog_maxlen = len; ++} ++ ++void ++eventlog_set_file_maxlen(int len) ++{ ++ evl_conf.file_maxlen = len; ++} ++ ++void ++eventlog_set_mailuid(uid_t uid) ++{ ++ evl_conf.mailuid = uid; ++} ++ ++void ++eventlog_set_omit_hostname(bool omit_hostname) ++{ ++ evl_conf.omit_hostname = omit_hostname; ++} ++ ++void ++eventlog_set_logpath(const char *path) ++{ ++ evl_conf.logpath = path; ++} ++ ++void ++eventlog_set_time_fmt(const char *fmt) ++{ ++ evl_conf.time_fmt = fmt; ++} ++ ++void ++eventlog_set_mailerpath(const char *path) ++{ ++ evl_conf.mailerpath = path; ++} ++ ++void ++eventlog_set_mailerflags(const char *mflags) ++{ ++ evl_conf.mailerflags = mflags; ++} ++ ++void ++eventlog_set_mailfrom(const char *from_addr) ++{ ++ evl_conf.mailfrom = from_addr; ++} ++ ++void ++eventlog_set_mailto(const char *to_addr) ++{ ++ evl_conf.mailto = to_addr; ++} ++ ++void ++eventlog_set_mailsub(const char *subject) ++{ ++ evl_conf.mailsub = subject; ++} ++ ++void ++eventlog_set_open_log(FILE *(*fn)(int type, const char *)) ++{ ++ evl_conf.open_log = fn; ++} ++ ++void ++eventlog_set_close_log(void (*fn)(int type, FILE *)) ++{ ++ evl_conf.close_log = fn; ++} ++ ++/* ++ * get eventlog config. ++ */ ++const struct eventlog_config * ++eventlog_getconf(void) ++{ ++ return &evl_conf; ++} +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-4.patch b/sudo-1.9.13-CVE-2023-28486-7-4.patch new file mode 100644 index 0000000..be5bc2c --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-4.patch @@ -0,0 +1,66 @@ +From d452678787683da6498668cd1f1cbb8000d63178 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Tue, 2 Mar 2021 18:37:35 -0700 +Subject: [PATCH] Log peer address in sudo_logsrvd JSON-format logs. The peer + that connected to us might not be the same host where the log entry + originated. + +--- + include/sudo_eventlog.h | 3 ++- + lib/eventlog/eventlog.c | 9 ++++++++- + logsrvd/iolog_writer.c | 8 ++++++-- + logsrvd/logsrvd.c | 9 +++++---- + logsrvd/logsrvd.h | 4 ++-- + 5 files changed, 23 insertions(+), 10 deletions(-) + +diff --git a/include/sudo_eventlog.h b/include/sudo_eventlog.h +index e40622a51..49153e173 100644 +--- a/include/sudo_eventlog.h ++++ b/include/sudo_eventlog.h +@@ -1,7 +1,7 @@ + /* + * SPDX-License-Identifier: ISC + * +- * Copyright (c) 2020 Todd C. Miller ++ * Copyright (c) 2020-2021 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -101,6 +101,7 @@ struct eventlog { + char *runcwd; + char *rungroup; + char *runuser; ++ char *peeraddr; + char *submithost; + char *submituser; + char *submitgroup; +diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c +index e7505d9d9..0c1e74e38 100644 +--- a/lib/eventlog/eventlog.c ++++ b/lib/eventlog/eventlog.c +@@ -1,7 +1,7 @@ + /* + * SPDX-License-Identifier: ISC + * +- * Copyright (c) 1994-1996, 1998-2020 Todd C. Miller ++ * Copyright (c) 1994-1996, 1998-2021 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -825,6 +825,13 @@ format_json(int event_type, const char *reason, const char *errstr, + + /* Event log info may be missing for alert messages. */ + if (evlog != NULL) { ++ if (evlog->peeraddr != NULL) { ++ json_value.type = JSON_STRING; ++ json_value.u.string = evlog->peeraddr; ++ if (!sudo_json_add_value(&json, "peeraddr", &json_value)) ++ goto bad; ++ } ++ + if (evlog->iolog_path != NULL) { + json_value.type = JSON_STRING; + json_value.u.string = evlog->iolog_path; +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-5.patch b/sudo-1.9.13-CVE-2023-28486-7-5.patch new file mode 100644 index 0000000..d2c99d9 --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-5.patch @@ -0,0 +1,559 @@ +From b54a16e1749fc53e4ed047da72f97b8f99bf4d6a Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Fri, 9 Jul 2021 11:08:44 -0600 +Subject: [PATCH] Add support for logging exit status events. For + sudo-formatted logs, this is a record with "EXIT=number" and potentially + "SIGNAL=name" after the command. For JSON-format logs, a new "exit" record + is logged which contains an "exit_value" and potentially "signal" and + "core_dumped". JSON-format logs now incude a UUID to associate the "exit" + record with the "accept" record. + +--- + include/sudo_eventlog.h | 2 + + lib/eventlog/eventlog.c | 255 +++++++++++++++++++++++++++------------- + 2 files changed, 175 insertions(+), 82 deletions(-) + +diff --git a/include/sudo_eventlog.h b/include/sudo_eventlog.h +index 49153e173..07ef9dcbe 100644 +--- a/include/sudo_eventlog.h ++++ b/include/sudo_eventlog.h +@@ -31,6 +31,7 @@ + enum event_type { + EVLOG_ACCEPT, + EVLOG_REJECT, ++ EVLOG_EXIT, + EVLOG_ALERT + }; + +@@ -122,6 +123,7 @@ struct json_container; + typedef bool (*eventlog_json_callback_t)(struct json_container *, void *); + + bool eventlog_accept(const struct eventlog *evlog, int flags, eventlog_json_callback_t info_cb, void *info); ++bool eventlog_exit(const struct eventlog *evlog, int flags, struct timespec *run_time, int exit_value, const char *signal_name, bool core_dumped, eventlog_json_callback_t info_cb, void *info); + bool eventlog_alert(const struct eventlog *evlog, int flags, struct timespec *alert_time, const char *reason, const char *errstr); + bool eventlog_reject(const struct eventlog *evlog, int flags, const char *reason, eventlog_json_callback_t info_cb, void *info); + bool eventlog_store_json(struct json_container *json, const struct eventlog *evlog); +diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c +index 0c1e74e38..efcd6859d 100644 +--- a/lib/eventlog/eventlog.c ++++ b/lib/eventlog/eventlog.c +@@ -66,6 +66,8 @@ + #define LL_ENV_STR "ENV=" + #define LL_CMND_STR "COMMAND=" + #define LL_TSID_STR "TSID=" ++#define LL_EXIT_STR "EXIT=" ++#define LL_SIGNAL_STR "SIGNAL=" + + #define IS_SESSID(s) ( \ + isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \ +@@ -75,28 +77,40 @@ + isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \ + (s)[8] == '\0') + ++struct eventlog_args { ++ const char *reason; ++ const char *errstr; ++ const char *signal_name; ++ const struct timespec *event_time; ++ int exit_value; ++ bool core_dumped; ++ eventlog_json_callback_t json_info_cb; ++ void *json_info; ++}; ++ + /* + * Allocate and fill in a new logline. + */ + static char * +-new_logline(int flags, const char *message, const char *errstr, ++new_logline(int event_type, int flags, struct eventlog_args *args, + const struct eventlog *evlog) + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + char *line = NULL, *evstr = NULL; + const char *iolog_file = evlog->iolog_file; + const char *tty, *tsid = NULL; ++ char exit_str[(((sizeof(int) * 8) + 2) / 3) + 2]; + char sessid[7]; + size_t len = 0; + int i; + debug_decl(new_logline, SUDO_DEBUG_UTIL); + + if (ISSET(flags, EVLOG_RAW)) { +- if (errstr != NULL) { +- if (asprintf(&line, "%s: %s", message, errstr) == -1) ++ if (args->errstr != NULL) { ++ if (asprintf(&line, "%s: %s", args->reason, args->errstr) == -1) + goto oom; + } else { +- if ((line = strdup(message)) == NULL) ++ if ((line = strdup(args->reason)) == NULL) + goto oom; + } + debug_return_str(line); +@@ -127,10 +141,10 @@ new_logline(int flags, const char *message, const char *errstr, + /* + * Compute line length + */ +- if (message != NULL) +- len += strlen(message) + 3; +- if (errstr != NULL) +- len += strlen(errstr) + 3; ++ if (args->reason != NULL) ++ len += strlen(args->reason) + 3; ++ if (args->errstr != NULL) ++ len += strlen(args->errstr) + 3; + if (evlog->submithost != NULL && !evl_conf->omit_hostname) + len += sizeof(LL_HOST_STR) + 2 + strlen(evlog->submithost); + if (tty != NULL) +@@ -171,6 +185,12 @@ new_logline(int flags, const char *message, const char *errstr, + for (i = 1; evlog->argv[i] != NULL; i++) + len += strlen(evlog->argv[i]) + 1; + } ++ if (event_type == EVLOG_EXIT) { ++ if (args->signal_name != NULL) ++ len += sizeof(LL_SIGNAL_STR) + 2 + strlen(args->signal_name); ++ (void)snprintf(exit_str, sizeof(exit_str), "%d", args->exit_value); ++ len += sizeof(LL_EXIT_STR) + 2 + strlen(exit_str); ++ } + } + + /* +@@ -180,13 +200,13 @@ new_logline(int flags, const char *message, const char *errstr, + goto oom; + line[0] = '\0'; + +- if (message != NULL) { +- if (strlcat(line, message, len) >= len || +- strlcat(line, errstr ? " : " : " ; ", len) >= len) ++ if (args->reason != NULL) { ++ if (strlcat(line, args->reason, len) >= len || ++ strlcat(line, args->errstr ? " : " : " ; ", len) >= len) + goto toobig; + } +- if (errstr != NULL) { +- if (strlcat(line, errstr, len) >= len || ++ if (args->errstr != NULL) { ++ if (strlcat(line, args->errstr, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } +@@ -252,6 +272,18 @@ new_logline(int flags, const char *message, const char *errstr, + goto toobig; + } + } ++ if (event_type == EVLOG_EXIT) { ++ if (args->signal_name != NULL) { ++ if (strlcat(line, " ; ", len) >= len || ++ strlcat(line, LL_SIGNAL_STR, len) >= len || ++ strlcat(line, args->signal_name, len) >= len) ++ goto toobig; ++ } ++ if (strlcat(line, " ; ", len) >= len || ++ strlcat(line, LL_EXIT_STR, len) >= len || ++ strlcat(line, exit_str, len) >= len) ++ goto toobig; ++ } + } + + debug_return_str(line); +@@ -369,7 +401,7 @@ exec_mailer(int pipein) + _exit(127); + } + +-/* Send a message to MAILTO user */ ++/* Send a message to the mailto user */ + static bool + send_mail(const struct eventlog *evlog, const char *fmt, ...) + { +@@ -548,19 +580,11 @@ send_mail(const struct eventlog *evlog, const char *fmt, ...) + + static bool + json_add_timestamp(struct json_container *json, const char *name, +- const struct timespec *ts) ++ const struct timespec *ts, bool format_timestamp) + { +- const struct eventlog_config *evl_conf = eventlog_getconf(); +- const char *timefmt = evl_conf->time_fmt; + struct json_value json_value; +- time_t secs = ts->tv_sec; +- char timebuf[1024]; +- struct tm *tm; + debug_decl(json_add_timestamp, SUDO_DEBUG_PLUGIN); + +- if ((tm = gmtime(&secs)) == NULL) +- debug_return_bool(false); +- + if (!sudo_json_open_object(json, name)) + goto oom; + +@@ -574,17 +598,27 @@ json_add_timestamp(struct json_container *json, const char *name, + if (!sudo_json_add_value(json, "nanoseconds", &json_value)) + goto oom; + +- strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", tm); +- json_value.type = JSON_STRING; +- json_value.u.string = timebuf; +- if (!sudo_json_add_value(json, "iso8601", &json_value)) +- goto oom; ++ if (format_timestamp) { ++ const struct eventlog_config *evl_conf = eventlog_getconf(); ++ const char *timefmt = evl_conf->time_fmt; ++ time_t secs = ts->tv_sec; ++ char timebuf[1024]; ++ struct tm *tm; + +- strftime(timebuf, sizeof(timebuf), timefmt, tm); +- json_value.type = JSON_STRING; +- json_value.u.string = timebuf; +- if (!sudo_json_add_value(json, "localtime", &json_value)) +- goto oom; ++ if ((tm = gmtime(&secs)) != NULL) { ++ strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", tm); ++ json_value.type = JSON_STRING; ++ json_value.u.string = timebuf; ++ if (!sudo_json_add_value(json, "iso8601", &json_value)) ++ goto oom; ++ ++ strftime(timebuf, sizeof(timebuf), timefmt, tm); ++ json_value.type = JSON_STRING; ++ json_value.u.string = timebuf; ++ if (!sudo_json_add_value(json, "localtime", &json_value)) ++ goto oom; ++ } ++ } + + if (!sudo_json_close_object(json)) + goto oom; +@@ -741,14 +775,15 @@ default_json_cb(struct json_container *json, void *v) + } + + static char * +-format_json(int event_type, const char *reason, const char *errstr, +- const struct eventlog *evlog, const struct timespec *event_time, +- eventlog_json_callback_t info_cb, void *info, bool compact) ++format_json(int event_type, struct eventlog_args *args, ++ const struct eventlog *evlog, bool compact) + { +- const char *type_str; +- const char *time_str; ++ eventlog_json_callback_t info_cb = args->json_info_cb; ++ void *info = args->json_info; + struct json_container json = { 0 }; + struct json_value json_value; ++ const char *time_str, *type_str; ++ bool format_timestamp = true; + struct timespec now; + debug_decl(format_json, SUDO_DEBUG_UTIL); + +@@ -776,6 +811,11 @@ format_json(int event_type, const char *reason, const char *errstr, + type_str = "alert"; + time_str = "alert_time"; + break; ++ case EVLOG_EXIT: ++ type_str = "exit"; ++ time_str = "run_time"; ++ format_timestamp = false; ++ break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unexpected event type %d", event_type); +@@ -788,18 +828,20 @@ format_json(int event_type, const char *reason, const char *errstr, + goto bad; + + /* Reject and Alert events include a reason and optional error string. */ +- if (reason != NULL) { ++ if (args->reason != NULL) { + char *ereason = NULL; + +- if (errstr != NULL) { +- if (asprintf(&ereason, _("%s: %s"), reason, errstr) == -1) { ++ if (args->errstr != NULL) { ++ const int len = asprintf(&ereason, _("%s: %s"), args->reason, ++ args->errstr); ++ if (len == -1) { + sudo_warnx(U_("%s: %s"), __func__, + U_("unable to allocate memory")); + goto bad; + } + } + json_value.type = JSON_STRING; +- json_value.u.string = ereason ? ereason : reason; ++ json_value.u.string = ereason ? ereason : args->reason; + if (!sudo_json_add_value(&json, "reason", &json_value)) { + free(ereason); + goto bad; +@@ -810,19 +852,37 @@ format_json(int event_type, const char *reason, const char *errstr, + /* XXX - create and log uuid? */ + + /* Log event time on server (set earlier) */ +- if (!json_add_timestamp(&json, "server_time", &now)) { ++ if (!json_add_timestamp(&json, "server_time", &now, true)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, + "unable format timestamp"); + goto bad; + } + + /* Log event time from client */ +- if (!json_add_timestamp(&json, time_str, event_time)) { ++ if (!json_add_timestamp(&json, time_str, args->event_time, format_timestamp)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, + "unable format timestamp"); + goto bad; + } + ++ if (event_type == EVLOG_EXIT) { ++ if (args->signal_name != NULL) { ++ json_value.type = JSON_STRING; ++ json_value.u.string = args->signal_name; ++ if (!sudo_json_add_value(&json, "signal", &json_value)) ++ goto bad; ++ ++ json_value.type = JSON_BOOL; ++ json_value.u.boolean = args->signal_name; ++ if (!sudo_json_add_value(&json, "dumped_core", &json_value)) ++ goto bad; ++ } ++ json_value.type = JSON_NUMBER; ++ json_value.u.number = args->exit_value; ++ if (!sudo_json_add_value(&json, "exit_value", &json_value)) ++ goto bad; ++ } ++ + /* Event log info may be missing for alert messages. */ + if (evlog != NULL) { + if (evlog->peeraddr != NULL) { +@@ -919,18 +979,15 @@ done: + } + + static bool +-do_syslog_json(int pri, int event_type, const char *reason, +- const char *errstr, const struct eventlog *evlog, +- const struct timespec *event_time, +- eventlog_json_callback_t info_cb, void *info) ++do_syslog_json(int pri, int event_type, struct eventlog_args *args, ++ const struct eventlog *evlog) + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + char *json_str; + debug_decl(do_syslog_json, SUDO_DEBUG_UTIL); + + /* Format as a compact JSON message (no newlines) */ +- json_str = format_json(event_type, reason, errstr, evlog, event_time, +- info_cb, info, true); ++ json_str = format_json(event_type, args, evlog, true); + if (json_str == NULL) + debug_return_bool(false); + +@@ -947,9 +1004,8 @@ do_syslog_json(int pri, int event_type, const char *reason, + * Log a message to syslog in either sudo or JSON format. + */ + static bool +-do_syslog(int event_type, int flags, const char *reason, const char *errstr, +- const struct eventlog *evlog, const struct timespec *event_time, +- eventlog_json_callback_t info_cb, void *info) ++do_syslog(int event_type, int flags, struct eventlog_args *args, ++ const struct eventlog *evlog) + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + char *logline = NULL; +@@ -959,7 +1015,7 @@ do_syslog(int event_type, int flags, const char *reason, const char *errstr, + + /* Sudo format logs and mailed logs use the same log line format. */ + if (evl_conf->format == EVLOG_SUDO || ISSET(flags, EVLOG_MAIL)) { +- logline = new_logline(flags, reason, errstr, evlog); ++ logline = new_logline(event_type, flags, args, evlog); + if (logline == NULL) + debug_return_bool(false); + +@@ -977,6 +1033,7 @@ do_syslog(int event_type, int flags, const char *reason, const char *errstr, + + switch (event_type) { + case EVLOG_ACCEPT: ++ case EVLOG_EXIT: + pri = evl_conf->syslog_acceptpri; + break; + case EVLOG_REJECT: +@@ -1002,8 +1059,7 @@ do_syslog(int event_type, int flags, const char *reason, const char *errstr, + ret = do_syslog_sudo(pri, logline, evlog); + break; + case EVLOG_JSON: +- ret = do_syslog_json(pri, event_type, reason, errstr, evlog, +- event_time, info_cb, info); ++ ret = do_syslog_json(pri, event_type, args, evlog); + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +@@ -1069,9 +1125,8 @@ done: + } + + static bool +-do_logfile_json(int event_type, const char *reason, const char *errstr, +- const struct eventlog *evlog, const struct timespec *event_time, +- eventlog_json_callback_t info_cb, void *info) ++do_logfile_json(int event_type, struct eventlog_args *args, ++ const struct eventlog *evlog) + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + const char *logfile = evl_conf->logpath; +@@ -1084,8 +1139,7 @@ do_logfile_json(int event_type, const char *reason, const char *errstr, + if ((fp = evl_conf->open_log(EVLOG_FILE, logfile)) == NULL) + debug_return_bool(false); + +- json_str = format_json(event_type, reason, errstr, evlog, event_time, +- info_cb, info, false); ++ json_str = format_json(event_type, args, evlog, false); + if (json_str == NULL) + goto done; + +@@ -1127,9 +1181,8 @@ done: + } + + static bool +-do_logfile(int event_type, int flags, const char *reason, const char *errstr, +- const struct eventlog *evlog, const struct timespec *event_time, +- eventlog_json_callback_t info_cb, void *info) ++do_logfile(int event_type, int flags, struct eventlog_args *args, ++ const struct eventlog *evlog) + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + bool ret = false; +@@ -1138,7 +1191,7 @@ do_logfile(int event_type, int flags, const char *reason, const char *errstr, + + /* Sudo format logs and mailed logs use the same log line format. */ + if (evl_conf->format == EVLOG_SUDO || ISSET(flags, EVLOG_MAIL)) { +- logline = new_logline(flags, reason, errstr, evlog); ++ logline = new_logline(event_type, flags, args, evlog); + if (logline == NULL) + debug_return_bool(false); + +@@ -1156,11 +1209,11 @@ do_logfile(int event_type, int flags, const char *reason, const char *errstr, + + switch (evl_conf->format) { + case EVLOG_SUDO: +- ret = do_logfile_sudo(logline ? logline : reason, evlog, event_time); ++ ret = do_logfile_sudo(logline ? logline : args->reason, evlog, ++ args->event_time); + break; + case EVLOG_JSON: +- ret = do_logfile_json(event_type, reason, errstr, evlog, +- event_time, info_cb, info); ++ ret = do_logfile_json(event_type, args, evlog); + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +@@ -1178,21 +1231,21 @@ eventlog_accept(const struct eventlog *evlog, int flags, + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + const int log_type = evl_conf->type; ++ struct eventlog_args args = { NULL }; + bool ret = true; + debug_decl(log_accept, SUDO_DEBUG_UTIL); + +- if (log_type == EVLOG_NONE) +- debug_return_bool(true); ++ args.event_time = &evlog->submit_time; ++ args.json_info_cb = info_cb; ++ args.json_info = info; + + if (ISSET(log_type, EVLOG_SYSLOG)) { +- if (!do_syslog(EVLOG_ACCEPT, flags, NULL, NULL, evlog, +- &evlog->submit_time, info_cb, info)) ++ if (!do_syslog(EVLOG_ACCEPT, flags, &args, evlog)) + ret = false; + CLR(flags, EVLOG_MAIL); + } + if (ISSET(log_type, EVLOG_FILE)) { +- if (!do_logfile(EVLOG_ACCEPT, flags, NULL, NULL, evlog, +- &evlog->submit_time, info_cb, info)) ++ if (!do_logfile(EVLOG_ACCEPT, flags, &args, evlog)) + ret = false; + } + +@@ -1205,18 +1258,22 @@ eventlog_reject(const struct eventlog *evlog, int flags, const char *reason, + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + const int log_type = evl_conf->type; ++ struct eventlog_args args = { NULL }; + bool ret = true; + debug_decl(log_reject, SUDO_DEBUG_UTIL); + ++ args.reason = reason; ++ args.event_time = &evlog->submit_time; ++ args.json_info_cb = info_cb; ++ args.json_info = info; ++ + if (ISSET(log_type, EVLOG_SYSLOG)) { +- if (!do_syslog(EVLOG_REJECT, flags, reason, NULL, evlog, +- &evlog->submit_time, info_cb, info)) ++ if (!do_syslog(EVLOG_REJECT, flags, &args, evlog)) + ret = false; + CLR(flags, EVLOG_MAIL); + } + if (ISSET(log_type, EVLOG_FILE)) { +- if (!do_logfile(EVLOG_REJECT, flags, reason, NULL, evlog, +- &evlog->submit_time, info_cb, info)) ++ if (!do_logfile(EVLOG_REJECT, flags, &args, evlog)) + ret = false; + } + +@@ -1229,18 +1286,52 @@ eventlog_alert(const struct eventlog *evlog, int flags, + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + const int log_type = evl_conf->type; ++ struct eventlog_args args = { NULL }; + bool ret = true; + debug_decl(log_alert, SUDO_DEBUG_UTIL); + ++ args.reason = reason; ++ args.errstr = errstr; ++ args.event_time = alert_time; ++ ++ if (ISSET(log_type, EVLOG_SYSLOG)) { ++ if (!do_syslog(EVLOG_ALERT, flags, &args, evlog)) ++ ret = false; ++ CLR(flags, EVLOG_MAIL); ++ } ++ if (ISSET(log_type, EVLOG_FILE)) { ++ if (!do_logfile(EVLOG_ALERT, flags, &args, evlog)) ++ ret = false; ++ } ++ ++ debug_return_bool(ret); ++} ++ ++bool ++eventlog_exit(const struct eventlog *evlog, int flags, ++ struct timespec *run_time, int exit_value, const char *signal_name, ++ bool core_dumped, eventlog_json_callback_t info_cb, void *info) ++{ ++ const struct eventlog_config *evl_conf = eventlog_getconf(); ++ const int log_type = evl_conf->type; ++ struct eventlog_args args = { NULL }; ++ bool ret = true; ++ debug_decl(eventlog_exit, SUDO_DEBUG_UTIL); ++ ++ args.signal_name = signal_name; ++ args.core_dumped = core_dumped; ++ args.exit_value = exit_value; ++ args.event_time = run_time; ++ args.json_info_cb = info_cb; ++ args.json_info = info; ++ + if (ISSET(log_type, EVLOG_SYSLOG)) { +- if (!do_syslog(EVLOG_ALERT, flags, reason, errstr, evlog, alert_time, +- NULL, NULL)) ++ if (!do_syslog(EVLOG_EXIT, flags, &args, evlog)) + ret = false; + CLR(flags, EVLOG_MAIL); + } + if (ISSET(log_type, EVLOG_FILE)) { +- if (!do_logfile(EVLOG_ALERT, flags, reason, errstr, evlog, alert_time, +- NULL, NULL)) ++ if (!do_logfile(EVLOG_EXIT, flags, &args, evlog)) + ret = false; + } + +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-6.patch b/sudo-1.9.13-CVE-2023-28486-7-6.patch new file mode 100644 index 0000000..ba73bd8 --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-6.patch @@ -0,0 +1,39 @@ +From d109cd61d9ff01053f1d43b7d4fc0e5e657c8da3 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Tue, 27 Jul 2021 12:19:53 -0600 +Subject: [PATCH] In new_logline check for NULL args->reason for EVLOG_RAW. + This can't happen in practice since we never set EVLOG_RAW without passing in + a reason. Coverity CID 237142 237143 + +--- + lib/eventlog/eventlog.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c +index 280be7fcf..26c5f6dc7 100644 +--- a/lib/eventlog/eventlog.c ++++ b/lib/eventlog/eventlog.c +@@ -106,12 +106,14 @@ new_logline(int event_type, int flags, struct eventlog_args *args, + debug_decl(new_logline, SUDO_DEBUG_UTIL); + + if (ISSET(flags, EVLOG_RAW)) { +- if (args->errstr != NULL) { +- if (asprintf(&line, "%s: %s", args->reason, args->errstr) == -1) +- goto oom; +- } else { +- if ((line = strdup(args->reason)) == NULL) +- goto oom; ++ if (args->reason != NULL) { ++ if (args->errstr != NULL) { ++ if (asprintf(&line, "%s: %s", args->reason, args->errstr) == -1) ++ goto oom; ++ } else { ++ if ((line = strdup(args->reason)) == NULL) ++ goto oom; ++ } + } + debug_return_str(line); + } +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-7.patch b/sudo-1.9.13-CVE-2023-28486-7-7.patch new file mode 100644 index 0000000..3666553 --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-7.patch @@ -0,0 +1,42 @@ +From babb498c6ebe09723a751127b104f43ab643ee91 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Sat, 14 Aug 2021 09:24:39 -0600 +Subject: [PATCH] new_logline: handle case where evlog is NULL + +--- + lib/eventlog/eventlog.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c +index 255ef1bbf..7f55859b6 100644 +--- a/lib/eventlog/eventlog.c ++++ b/lib/eventlog/eventlog.c +@@ -97,7 +97,7 @@ new_logline(int event_type, int flags, struct eventlog_args *args, + { + const struct eventlog_config *evl_conf = eventlog_getconf(); + char *line = NULL, *evstr = NULL; +- const char *iolog_file = evlog->iolog_file; ++ const char *iolog_file; + const char *tty, *tsid = NULL; + char exit_str[(((sizeof(int) * 8) + 2) / 3) + 2]; + char sessid[7]; +@@ -105,7 +105,7 @@ new_logline(int event_type, int flags, struct eventlog_args *args, + int i; + debug_decl(new_logline, SUDO_DEBUG_UTIL); + +- if (ISSET(flags, EVLOG_RAW)) { ++ if (ISSET(flags, EVLOG_RAW) || evlog == NULL) { + if (args->reason != NULL) { + if (args->errstr != NULL) { + if (asprintf(&line, "%s: %s", args->reason, args->errstr) == -1) +@@ -119,6 +119,7 @@ new_logline(int event_type, int flags, struct eventlog_args *args, + } + + /* A TSID may be a sudoers-style session ID or a free-form string. */ ++ iolog_file = evlog->iolog_file; + if (iolog_file != NULL) { + if (IS_SESSID(iolog_file)) { + sessid[0] = iolog_file[0]; +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-8.patch b/sudo-1.9.13-CVE-2023-28486-7-8.patch new file mode 100644 index 0000000..3aa8e25 --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-8.patch @@ -0,0 +1,56 @@ +From 4e4b506f22006c485c7ce557c9905dae16c5c12e Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Fri, 1 Oct 2021 10:33:55 -0600 +Subject: [PATCH] Sync "sudo -l" output with normal sudo log format. It now + prints runchroot and runcwd (falling back on cwd). As a result, submithost is + now printed first, matching sudo. Also avoid printing NULL pointers and skip + entries that don't have at least command, submituser and runuser set. + +--- + plugins/sudoers/sudoreplay.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c +index f32d44eb5..786aae30d 100644 +--- a/plugins/sudoers/sudoreplay.c ++++ b/plugins/sudoers/sudoreplay.c +@@ -1388,6 +1388,11 @@ list_session(char *log_dir, regex_t *re, const char *user, const char *tty) + if ((evlog = iolog_parse_loginfo(-1, log_dir)) == NULL) + goto done; + ++ if (evlog->command == NULL || evlog->submituser == NULL || ++ evlog->runuser == NULL) { ++ goto done; ++ } ++ + /* Match on search expression if there is one. */ + if (!STAILQ_EMPTY(&search_expr) && !match_expr(&search_expr, evlog, true)) + goto done; +@@ -1409,13 +1414,18 @@ list_session(char *log_dir, regex_t *re, const char *user, const char *tty) + } + /* XXX - print lines + cols? */ + timestr = get_timestr(evlog->submit_time.tv_sec, 1); +- printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ", +- timestr ? timestr : "invalid date", +- evlog->submituser, evlog->ttyname, evlog->cwd, evlog->runuser); +- if (evlog->rungroup) +- printf("GROUP=%s ; ", evlog->rungroup); +- if (evlog->submithost) ++ printf("%s : %s : ", timestr ? timestr : "invalid date", evlog->submituser); ++ if (evlog->submithost != NULL) + printf("HOST=%s ; ", evlog->submithost); ++ if (evlog->ttyname != NULL) ++ printf("TTY=%s ; ", evlog->ttyname); ++ if (evlog->runchroot != NULL) ++ printf("CHROOT=%s ; ", evlog->runchroot); ++ if (evlog->runcwd != NULL || evlog->cwd != NULL) ++ printf("CWD=%s ; ", evlog->runcwd ? evlog->runcwd : evlog->cwd); ++ printf("USER=%s ; ", evlog->runuser); ++ if (evlog->rungroup != NULL) ++ printf("GROUP=%s ; ", evlog->rungroup); + printf("TSID=%s ; COMMAND=%s\n", idstr, evlog->command); + + ret = 0; +-- +2.43.0 + diff --git a/sudo-1.9.13-CVE-2023-28486-7-9.patch b/sudo-1.9.13-CVE-2023-28486-7-9.patch new file mode 100644 index 0000000..84bfd8e --- /dev/null +++ b/sudo-1.9.13-CVE-2023-28486-7-9.patch @@ -0,0 +1,910 @@ +diff -up ./doc/sudoers.man.in.cve ./doc/sudoers.man.in +--- ./doc/sudoers.man.in.cve 2021-01-09 21:12:16.000000000 +0100 ++++ ./doc/sudoers.man.in 2023-12-04 16:52:54.499061280 +0100 +@@ -4978,14 +4978,31 @@ can log events via + syslog(3), + to a local log file, or both. + The log format is almost identical in both cases. ++Any control characters present in the log data are formatted in octal ++with a leading ++\(oq#\(cq ++character. ++For example, a horizontal tab is stored as ++\(oq#011\(cq ++and an embedded carriage return is stored as ++\(oq#015\(cq. ++In addition, space characters in the command path are stored as ++\(oq#040\(cq. ++Command line arguments that contain spaces are enclosed in single quotes ++(''). ++This makes it possible to distinguish multiple command line arguments ++from a single argument that contains spaces. ++Literal single quotes and backslash characters ++(\(oq\e\(cq) ++in command line arguments are escaped with a backslash. + .SS "Accepted command log entries" + Commands that sudo runs are logged using the following format (split + into multiple lines for readability): + .nf + .sp + .RS 4n +-date hostname progname: username : TTY=ttyname ; PWD=cwd ; \e +- USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e ++date hostname progname: username : TTY=ttyname ; CHROOT=chroot ; \e ++ PWD=cwd ; USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e + ENV=env_vars COMMAND=command + .RE + .fi +@@ -5034,6 +5051,9 @@ was run on, or + \(lqunknown\(rq + if there was no terminal present. + .TP 14n ++chroot ++The root directory that the command was run in, if one was specified. ++.TP 14n + cwd + The current working directory that + \fBsudo\fR +@@ -5058,7 +5078,7 @@ A list of environment variables specifie + if specified. + .TP 14n + command +-The actual command that was executed. ++The actual command that was executed, including any command line arguments. + .PP + Messages are logged using the locale specified by + \fIsudoers_locale\fR, +@@ -5294,17 +5314,21 @@ with a few important differences: + 1.\& + The + \fIprogname\fR +-and +-\fIhostname\fR +-fields are not present. ++field is not present. + .TP 5n + 2.\& +-If the +-\fIlog_year\fR +-option is enabled, +-the date will also include the year. ++The ++\fIhostname\fR ++is only logged if the ++\fIlog_host\fR ++option is enabled. + .TP 5n + 3.\& ++The date does not include the year unless the ++\fIlog_year\fR ++option is enabled. ++.TP 5n ++4.\& + Lines that are longer than + \fIloglinelen\fR + characters (80 by default) are word-wrapped and continued on the +diff -up ./doc/sudoers.mdoc.in.cve ./doc/sudoers.mdoc.in +--- ./doc/sudoers.mdoc.in.cve 2021-01-09 21:12:16.000000000 +0100 ++++ ./doc/sudoers.mdoc.in 2023-12-04 16:52:54.500061266 +0100 +@@ -4649,12 +4649,29 @@ can log events via + .Xr syslog 3 , + to a local log file, or both. + The log format is almost identical in both cases. ++Any control characters present in the log data are formatted in octal ++with a leading ++.Ql # ++character. ++For example, a horizontal tab is stored as ++.Ql #011 ++and an embedded carriage return is stored as ++.Ql #015 . ++In addition, space characters in the command path are stored as ++.Ql #040 . ++Command line arguments that contain spaces are enclosed in single quotes ++.Pq '' . ++This makes it possible to distinguish multiple command line arguments ++from a single argument that contains spaces. ++Literal single quotes and backslash characters ++.Pq Ql \e ++in command line arguments are escaped with a backslash. + .Ss Accepted command log entries + Commands that sudo runs are logged using the following format (split + into multiple lines for readability): + .Bd -literal -offset 4n +-date hostname progname: username : TTY=ttyname ; PWD=cwd ; \e +- USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e ++date hostname progname: username : TTY=ttyname ; CHROOT=chroot ; \e ++ PWD=cwd ; USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e + ENV=env_vars COMMAND=command + .Ed + .Pp +@@ -4697,6 +4714,8 @@ or + was run on, or + .Dq unknown + if there was no terminal present. ++.It chroot ++The root directory that the command was run in, if one was specified. + .It cwd + The current working directory that + .Nm sudo +@@ -4716,7 +4735,7 @@ option is enabled. + A list of environment variables specified on the command line, + if specified. + .It command +-The actual command that was executed. ++The actual command that was executed, including any command line arguments. + .El + .Pp + Messages are logged using the locale specified by +@@ -4938,14 +4957,17 @@ with a few important differences: + .It + The + .Em progname +-and ++field is not present. ++.It ++The + .Em hostname +-fields are not present. ++is only logged if the ++.Em log_host ++option is enabled. + .It +-If the ++The date does not include the year unless the + .Em log_year +-option is enabled, +-the date will also include the year. ++option is enabled. + .It + Lines that are longer than + .Em loglinelen +diff -up ./doc/sudoreplay.man.in.cve ./doc/sudoreplay.man.in +--- ./doc/sudoreplay.man.in.cve 2020-12-17 02:33:43.000000000 +0100 ++++ ./doc/sudoreplay.man.in 2023-12-04 16:52:54.500061266 +0100 +@@ -164,6 +164,15 @@ In this mode, + will list available sessions in a format similar to the + \fBsudo\fR + log file format, sorted by file name (or sequence number). ++Any control characters present in the log data are formated in octal ++with a leading ++\(oq#\(cq ++character. ++For example, a horizontal tab is displayed as ++\(oq#011\(cq ++and an embedded carriage return is displayed as ++\(oq#015\(cq. ++.sp + If a + \fIsearch expression\fR + is specified, it will be used to restrict the IDs that are displayed. +diff -up ./doc/sudoreplay.mdoc.in.cve ./doc/sudoreplay.mdoc.in +--- ./doc/sudoreplay.mdoc.in.cve 2020-12-17 02:33:43.000000000 +0100 ++++ ./doc/sudoreplay.mdoc.in 2023-12-04 16:52:54.500061266 +0100 +@@ -156,6 +156,16 @@ In this mode, + will list available sessions in a format similar to the + .Nm sudo + log file format, sorted by file name (or sequence number). ++Any control characters present in the log data are formatted in octal ++with a leading ++.Ql # ++character. ++For example, a horizontal tab is displayed as ++.Ql #011 ++and an embedded carriage return is displayed as ++.Ql #015 . ++Space characters in the command name and arguments are also formatted in octal. ++.Pp + If a + .Ar search expression + is specified, it will be used to restrict the IDs that are displayed. +diff -up ./include/sudo_lbuf.h.cve ./include/sudo_lbuf.h +--- ./include/sudo_lbuf.h.cve 2020-12-17 02:33:43.000000000 +0100 ++++ ./include/sudo_lbuf.h 2023-12-04 16:52:54.500061266 +0100 +@@ -36,9 +36,15 @@ struct sudo_lbuf { + + typedef int (*sudo_lbuf_output_t)(const char *); + ++/* Flags for sudo_lbuf_append_esc() */ ++#define LBUF_ESC_CNTRL 0x01 ++#define LBUF_ESC_BLANK 0x02 ++#define LBUF_ESC_QUOTE 0x04 ++ + sudo_dso_public void sudo_lbuf_init_v1(struct sudo_lbuf *lbuf, sudo_lbuf_output_t output, int indent, const char *continuation, int cols); + sudo_dso_public void sudo_lbuf_destroy_v1(struct sudo_lbuf *lbuf); + sudo_dso_public bool sudo_lbuf_append_v1(struct sudo_lbuf *lbuf, const char *fmt, ...) __printflike(2, 3); ++sudo_dso_public bool sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...) __printflike(3, 4); + sudo_dso_public bool sudo_lbuf_append_quoted_v1(struct sudo_lbuf *lbuf, const char *set, const char *fmt, ...) __printflike(3, 4); + sudo_dso_public void sudo_lbuf_print_v1(struct sudo_lbuf *lbuf); + sudo_dso_public bool sudo_lbuf_error_v1(struct sudo_lbuf *lbuf); +@@ -47,6 +53,7 @@ sudo_dso_public void sudo_lbuf_clearerr_ + #define sudo_lbuf_init(_a, _b, _c, _d, _e) sudo_lbuf_init_v1((_a), (_b), (_c), (_d), (_e)) + #define sudo_lbuf_destroy(_a) sudo_lbuf_destroy_v1((_a)) + #define sudo_lbuf_append sudo_lbuf_append_v1 ++#define sudo_lbuf_append_esc sudo_lbuf_append_esc_v1 + #define sudo_lbuf_append_quoted sudo_lbuf_append_quoted_v1 + #define sudo_lbuf_print(_a) sudo_lbuf_print_v1((_a)) + #define sudo_lbuf_error(_a) sudo_lbuf_error_v1((_a)) +diff -up ./lib/eventlog/eventlog.c.cve ./lib/eventlog/eventlog.c +--- ./lib/eventlog/eventlog.c.cve 2023-12-04 16:52:54.497061306 +0100 ++++ ./lib/eventlog/eventlog.c 2023-12-04 16:54:09.820048779 +0100 +@@ -51,24 +51,13 @@ + #include "sudo_compat.h" + #include "sudo_debug.h" + #include "sudo_eventlog.h" ++#include "sudo_lbuf.h" + #include "sudo_fatal.h" + #include "sudo_gettext.h" + #include "sudo_json.h" + #include "sudo_queue.h" + #include "sudo_util.h" + +-#define LL_HOST_STR "HOST=" +-#define LL_TTY_STR "TTY=" +-#define LL_CHROOT_STR "CHROOT=" +-#define LL_CWD_STR "PWD=" +-#define LL_USER_STR "USER=" +-#define LL_GROUP_STR "GROUP=" +-#define LL_ENV_STR "ENV=" +-#define LL_CMND_STR "COMMAND=" +-#define LL_TSID_STR "TSID=" +-#define LL_EXIT_STR "EXIT=" +-#define LL_SIGNAL_STR "SIGNAL=" +- + #define IS_SESSID(s) ( \ + isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \ + (s)[2] == '/' && \ +@@ -96,26 +85,28 @@ new_logline(int event_type, int flags, s + const struct eventlog *evlog) + { + const struct eventlog_config *evl_conf = eventlog_getconf(); +- char *line = NULL, *evstr = NULL; + const char *iolog_file; + const char *tty, *tsid = NULL; + char exit_str[(((sizeof(int) * 8) + 2) / 3) + 2]; + char sessid[7]; +- size_t len = 0; ++ struct sudo_lbuf lbuf; + int i; + debug_decl(new_logline, SUDO_DEBUG_UTIL); + ++ sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0); ++ + if (ISSET(flags, EVLOG_RAW) || evlog == NULL) { + if (args->reason != NULL) { + if (args->errstr != NULL) { +- if (asprintf(&line, "%s: %s", args->reason, args->errstr) == -1) +- goto oom; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s: %s", ++ args->reason, args->errstr); + } else { +- if ((line = strdup(args->reason)) == NULL) +- goto oom; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s", args->reason); + } ++ if (sudo_lbuf_error(&lbuf)) ++ goto oom; + } +- debug_return_str(line); ++ debug_return_str(lbuf.buf); + } + + /* A TSID may be a sudoers-style session ID or a free-form string. */ +@@ -142,163 +133,92 @@ new_logline(int event_type, int flags, s + } + + /* +- * Compute line length ++ * Format the log line as an lbuf, escaping control characters is ++ * octal form (#0nn). Error checking (ENOMEM) is done at the end + */ +- if (args->reason != NULL) +- len += strlen(args->reason) + 3; +- if (args->errstr != NULL) +- len += strlen(args->errstr) + 3; +- if (evlog->submithost != NULL && !evl_conf->omit_hostname) +- len += sizeof(LL_HOST_STR) + 2 + strlen(evlog->submithost); +- if (tty != NULL) +- len += sizeof(LL_TTY_STR) + 2 + strlen(tty); +- if (evlog->runchroot != NULL) +- len += sizeof(LL_CHROOT_STR) + 2 + strlen(evlog->runchroot); +- if (evlog->runcwd != NULL) +- len += sizeof(LL_CWD_STR) + 2 + strlen(evlog->runcwd); +- if (evlog->runuser != NULL) +- len += sizeof(LL_USER_STR) + 2 + strlen(evlog->runuser); +- if (evlog->rungroup != NULL) +- len += sizeof(LL_GROUP_STR) + 2 + strlen(evlog->rungroup); +- if (tsid != NULL) +- len += sizeof(LL_TSID_STR) + 2 + strlen(tsid); +- if (evlog->env_add != NULL) { +- size_t evlen = 0; +- char * const *ep; +- +- for (ep = evlog->env_add; *ep != NULL; ep++) +- evlen += strlen(*ep) + 1; +- if (evlen != 0) { +- if ((evstr = malloc(evlen)) == NULL) +- goto oom; +- ep = evlog->env_add; +- if (strlcpy(evstr, *ep, evlen) >= evlen) +- goto toobig; +- while (*++ep != NULL) { +- if (strlcat(evstr, " ", evlen) >= evlen || +- strlcat(evstr, *ep, evlen) >= evlen) +- goto toobig; +- } +- len += sizeof(LL_ENV_STR) + 2 + evlen; +- } +- } +- if (evlog->command != NULL) { +- len += sizeof(LL_CMND_STR) - 1 + strlen(evlog->command); +- if (evlog->argv != NULL) { +- for (i = 1; evlog->argv[i] != NULL; i++) +- len += strlen(evlog->argv[i]) + 1; +- } +- if (event_type == EVLOG_EXIT) { +- if (args->signal_name != NULL) +- len += sizeof(LL_SIGNAL_STR) + 2 + strlen(args->signal_name); +- (void)snprintf(exit_str, sizeof(exit_str), "%d", args->exit_value); +- len += sizeof(LL_EXIT_STR) + 2 + strlen(exit_str); +- } +- } +- +- /* +- * Allocate and build up the line. +- */ +- if ((line = malloc(++len)) == NULL) +- goto oom; +- line[0] = '\0'; +- + if (args->reason != NULL) { +- if (strlcat(line, args->reason, len) >= len || +- strlcat(line, args->errstr ? " : " : " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s", args->reason, ++ args->errstr ? " : " : " ; "); + } + if (args->errstr != NULL) { +- if (strlcat(line, args->errstr, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s ; ", args->errstr); + } + if (evlog->submithost != NULL && !evl_conf->omit_hostname) { +- if (strlcat(line, LL_HOST_STR, len) >= len || +- strlcat(line, evlog->submithost, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "HOST=%s ; ", ++ evlog->submithost); + } + if (tty != NULL) { +- if (strlcat(line, LL_TTY_STR, len) >= len || +- strlcat(line, tty, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "TTY=%s ; ", tty); + } + if (evlog->runchroot != NULL) { +- if (strlcat(line, LL_CHROOT_STR, len) >= len || +- strlcat(line, evlog->runchroot, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "CHROOT=%s ; ", ++ evlog->runchroot); + } + if (evlog->runcwd != NULL) { +- if (strlcat(line, LL_CWD_STR, len) >= len || +- strlcat(line, evlog->runcwd, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "PWD=%s ; ", ++ evlog->runcwd); + } + if (evlog->runuser != NULL) { +- if (strlcat(line, LL_USER_STR, len) >= len || +- strlcat(line, evlog->runuser, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "USER=%s ; ", ++ evlog->runuser); + } + if (evlog->rungroup != NULL) { +- if (strlcat(line, LL_GROUP_STR, len) >= len || +- strlcat(line, evlog->rungroup, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; +- } ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "GROUP=%s ; ", ++ evlog->rungroup); ++ } + if (tsid != NULL) { +- if (strlcat(line, LL_TSID_STR, len) >= len || +- strlcat(line, tsid, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; +- } +- if (evstr != NULL) { +- if (strlcat(line, LL_ENV_STR, len) >= len || +- strlcat(line, evstr, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; +- free(evstr); +- evstr = NULL; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "TSID=%s ; ", tsid); ++ } ++ if (evlog->env_add != NULL && evlog->env_add[0] != NULL) { ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "ENV=%s", ++ evlog->env_add[0]); ++ for (i = 1; evlog->env_add[i] != NULL; i++) { ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " %s", ++ evlog->env_add[i]); ++ } + } + if (evlog->command != NULL) { +- if (strlcat(line, LL_CMND_STR, len) >= len) +- goto toobig; +- if (strlcat(line, evlog->command, len) >= len) +- goto toobig; +- if (evlog->argv != NULL) { ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, ++ "COMMAND=%s", evlog->command); ++ if (evlog->argv != NULL && evlog->argv[0] != NULL) { + for (i = 1; evlog->argv[i] != NULL; i++) { +- if (strlcat(line, " ", len) >= len || +- strlcat(line, evlog->argv[i], len) >= len) +- goto toobig; ++ sudo_lbuf_append(&lbuf, " "); ++ if (strchr(evlog->argv[i], ' ') != NULL) { ++ /* Wrap args containing spaces in single quotes. */ ++ sudo_lbuf_append(&lbuf, "'"); ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_QUOTE, ++ "%s", evlog->argv[i]); ++ sudo_lbuf_append(&lbuf, "'"); ++ } else { ++ /* Escape quotes here too for consistency. */ ++ sudo_lbuf_append_esc(&lbuf, ++ LBUF_ESC_CNTRL|LBUF_ESC_BLANK|LBUF_ESC_QUOTE, ++ "%s", evlog->argv[i]); ++ } + } + } ++/* + if (event_type == EVLOG_EXIT) { + if (args->signal_name != NULL) { +- if (strlcat(line, " ; ", len) >= len || +- strlcat(line, LL_SIGNAL_STR, len) >= len || +- strlcat(line, args->signal_name, len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " ; SIGNAL=%s", ++ evlog->signal_name); + } +- if (strlcat(line, " ; ", len) >= len || +- strlcat(line, LL_EXIT_STR, len) >= len || +- strlcat(line, exit_str, len) >= len) +- goto toobig; ++ if (evlog->exit_value != -1) { ++ (void)snprintf(exit_str, sizeof(exit_str), "%d", ++ evlog->exit_value); ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " ; EXIT=%s", ++ exit_str); ++ } + } ++*/ + } + +- debug_return_str(line); ++ if (!sudo_lbuf_error(&lbuf)) ++ debug_return_str(lbuf.buf); + oom: +- free(evstr); ++ sudo_lbuf_destroy(&lbuf); + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + debug_return_str(NULL); +-toobig: +- free(evstr); +- free(line); +- sudo_warnx(U_("internal error, %s overflow"), __func__); +- debug_return_str(NULL); + } + + static void +diff -up ./lib/iolog/iolog_json.c.cve ./lib/iolog/iolog_json.c +--- ./lib/iolog/iolog_json.c.cve 2020-12-17 02:33:43.000000000 +0100 ++++ ./lib/iolog/iolog_json.c 2023-12-04 16:52:54.500061266 +0100 +@@ -443,35 +443,6 @@ iolog_parse_json_object(struct json_obje + } + } + +- /* Merge cmd and argv as sudoreplay expects. */ +- if (evlog->command != NULL && evlog->argv != NULL) { +- size_t len = strlen(evlog->command) + 1; +- char *newcmd; +- int ac; +- +- /* Skip argv[0], we use evlog->command instead. */ +- for (ac = 1; evlog->argv[ac] != NULL; ac++) +- len += strlen(evlog->argv[ac]) + 1; +- +- if ((newcmd = malloc(len)) == NULL) { +- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); +- goto done; +- } +- +- /* TODO: optimize this. */ +- if (strlcpy(newcmd, evlog->command, len) >= len) +- sudo_fatalx(U_("internal error, %s overflow"), __func__); +- for (ac = 1; evlog->argv[ac] != NULL; ac++) { +- if (strlcat(newcmd, " ", len) >= len) +- sudo_fatalx(U_("internal error, %s overflow"), __func__); +- if (strlcat(newcmd, evlog->argv[ac], len) >= len) +- sudo_fatalx(U_("internal error, %s overflow"), __func__); +- } +- +- free(evlog->command); +- evlog->command = newcmd; +- } +- + ret = true; + + done: +diff -up ./lib/util/lbuf.c.cve ./lib/util/lbuf.c +--- ./lib/util/lbuf.c.cve 2020-12-17 02:33:43.000000000 +0100 ++++ ./lib/util/lbuf.c 2023-12-04 16:52:54.501061253 +0100 +@@ -85,6 +85,112 @@ sudo_lbuf_expand(struct sudo_lbuf *lbuf, + } + + /* ++ * Escape a character in octal form (#0n) and store it as a string ++ * in buf, which must have at least 6 bytes available. ++ * Returns the length of buf, not counting the terminating NUL byte. ++ */ ++static int ++escape(unsigned char ch, char *buf) ++{ ++ const int len = ch < 0100 ? (ch < 010 ? 3 : 4) : 5; ++ ++ /* Work backwards from the least significant digit to most significant. */ ++ switch (len) { ++ case 5: ++ buf[4] = (ch & 7) + '0'; ++ ch >>= 3; ++ FALLTHROUGH; ++ case 4: ++ buf[3] = (ch & 7) + '0'; ++ ch >>= 3; ++ FALLTHROUGH; ++ case 3: ++ buf[2] = (ch & 7) + '0'; ++ buf[1] = '0'; ++ buf[0] = '#'; ++ break; ++ } ++ buf[len] = '\0'; ++ ++ return len; ++} ++ ++/* ++ * Parse the format and append strings, only %s and %% escapes are supported. ++ * Any non-printable characters are escaped in octal as #0nn. ++ */ ++bool ++sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...) ++{ ++ unsigned int saved_len = lbuf->len; ++ bool ret = false; ++ const char *s; ++ va_list ap; ++ debug_decl(sudo_lbuf_append_esc, SUDO_DEBUG_UTIL); ++ ++ if (sudo_lbuf_error(lbuf)) ++ debug_return_bool(false); ++ ++#define should_escape(ch) \ ++ ((ISSET(flags, LBUF_ESC_CNTRL) && iscntrl((unsigned char)ch)) || \ ++ (ISSET(flags, LBUF_ESC_BLANK) && isblank((unsigned char)ch))) ++#define should_quote(ch) \ ++ (ISSET(flags, LBUF_ESC_QUOTE) && (ch == '\'' || ch == '\\')) ++ ++ va_start(ap, fmt); ++ while (*fmt != '\0') { ++ if (fmt[0] == '%' && fmt[1] == 's') { ++ if ((s = va_arg(ap, char *)) == NULL) ++ s = "(NULL)"; ++ while (*s != '\0') { ++ if (should_escape(*s)) { ++ if (!sudo_lbuf_expand(lbuf, sizeof("#0177") - 1)) ++ goto done; ++ lbuf->len += escape(*s++, lbuf->buf + lbuf->len); ++ continue; ++ } ++ if (should_quote(*s)) { ++ if (!sudo_lbuf_expand(lbuf, 2)) ++ goto done; ++ lbuf->buf[lbuf->len++] = '\\'; ++ lbuf->buf[lbuf->len++] = *s++; ++ continue; ++ } ++ if (!sudo_lbuf_expand(lbuf, 1)) ++ goto done; ++ lbuf->buf[lbuf->len++] = *s++; ++ } ++ fmt += 2; ++ continue; ++ } ++ if (should_escape(*fmt)) { ++ if (!sudo_lbuf_expand(lbuf, sizeof("#0177") - 1)) ++ goto done; ++ if (*fmt == '\'') { ++ lbuf->buf[lbuf->len++] = '\\'; ++ lbuf->buf[lbuf->len++] = *fmt++; ++ } else { ++ lbuf->len += escape(*fmt++, lbuf->buf + lbuf->len); ++ } ++ continue; ++ } ++ if (!sudo_lbuf_expand(lbuf, 1)) ++ goto done; ++ lbuf->buf[lbuf->len++] = *fmt++; ++ } ++ ret = true; ++ ++done: ++ if (!ret) ++ lbuf->len = saved_len; ++ if (lbuf->size != 0) ++ lbuf->buf[lbuf->len] = '\0'; ++ va_end(ap); ++ ++ debug_return_bool(ret); ++} ++ ++/* + * Parse the format and append strings, only %s and %% escapes are supported. + * Any characters in set are quoted with a backslash. + */ +diff -up ./lib/util/util.exp.in.cve ./lib/util/util.exp.in +--- ./lib/util/util.exp.in.cve 2021-01-09 21:12:16.000000000 +0100 ++++ ./lib/util/util.exp.in 2023-12-04 16:52:54.501061253 +0100 +@@ -95,6 +95,7 @@ sudo_json_get_len_v1 + sudo_json_init_v1 + sudo_json_open_array_v1 + sudo_json_open_object_v1 ++sudo_lbuf_append_esc_v1 + sudo_lbuf_append_quoted_v1 + sudo_lbuf_append_v1 + sudo_lbuf_clearerr_v1 +diff -up ./plugins/sudoers/sudoreplay.c.cve ./plugins/sudoers/sudoreplay.c +--- ./plugins/sudoers/sudoreplay.c.cve 2023-12-04 16:52:54.498061293 +0100 ++++ ./plugins/sudoers/sudoreplay.c 2023-12-04 16:52:54.501061253 +0100 +@@ -62,6 +62,7 @@ + #include "sudo_debug.h" + #include "sudo_event.h" + #include "sudo_eventlog.h" ++#include "sudo_lbuf.h" + #include "sudo_fatal.h" + #include "sudo_gettext.h" + #include "sudo_iolog.h" +@@ -363,6 +364,10 @@ main(int argc, char *argv[]) + if ((evlog = iolog_parse_loginfo(iolog_dir_fd, iolog_dir)) == NULL) + goto done; + printf(_("Replaying sudo session: %s"), evlog->command); ++ if (evlog->argv != NULL && evlog->argv[0] != NULL) { ++ for (i = 1; evlog->argv[i] != NULL; i++) ++ printf(" %s", evlog->argv[i]); ++ } + + /* Setup terminal if appropriate. */ + if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) +@@ -1291,11 +1296,57 @@ parse_expr(struct search_node_list *head + debug_return_int(av - argv); + } + ++static char * ++expand_command(struct eventlog *evlog, char **newbuf) ++{ ++ size_t len, bufsize = strlen(evlog->command) + 1; ++ char *cp, *buf; ++ int ac; ++ debug_decl(expand_command, SUDO_DEBUG_UTIL); ++ ++ if (evlog->argv == NULL || evlog->argv[0] == NULL || evlog->argv[1] == NULL) { ++ /* No arguments, we can use the command as-is. */ ++ *newbuf = NULL; ++ debug_return_str(evlog->command); ++ } ++ ++ /* Skip argv[0], we use evlog->command instead. */ ++ for (ac = 1; evlog->argv[ac] != NULL; ac++) ++ bufsize += strlen(evlog->argv[ac]) + 1; ++ ++ if ((buf = malloc(bufsize)) == NULL) ++ sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); ++ cp = buf; ++ ++ len = strlcpy(cp, evlog->command, bufsize); ++ if (len >= bufsize) ++ sudo_fatalx(U_("internal error, %s overflow"), __func__); ++ cp += len; ++ bufsize -= len; ++ ++ for (ac = 1; evlog->argv[ac] != NULL; ac++) { ++ if (bufsize < 2) ++ sudo_fatalx(U_("internal error, %s overflow"), __func__); ++ *cp++ = ' '; ++ bufsize--; ++ ++ len = strlcpy(cp, evlog->argv[ac], bufsize); ++ if (len >= bufsize) ++ sudo_fatalx(U_("internal error, %s overflow"), __func__); ++ cp += len; ++ bufsize -= len; ++ } ++ ++ *newbuf = buf; ++ debug_return_str(buf); ++} ++ + static bool + match_expr(struct search_node_list *head, struct eventlog *evlog, bool last_match) + { + struct search_node *sn; + bool res = false, matched = last_match; ++ char *tofree; + int rc; + debug_decl(match_expr, SUDO_DEBUG_UTIL); + +@@ -1329,13 +1380,15 @@ match_expr(struct search_node_list *head + res = strcmp(sn->u.user, evlog->submituser) == 0; + break; + case ST_PATTERN: +- rc = regexec(&sn->u.cmdre, evlog->command, 0, NULL, 0); ++ rc = regexec(&sn->u.cmdre, expand_command(evlog, &tofree), ++ 0, NULL, 0); + if (rc && rc != REG_NOMATCH) { + char buf[BUFSIZ]; + regerror(rc, &sn->u.cmdre, buf, sizeof(buf)); + sudo_fatalx("%s", buf); + } + res = rc == REG_NOMATCH ? 0 : 1; ++ free(tofree); + break; + case ST_FROMDATE: + res = sudo_timespeccmp(&evlog->submit_time, &sn->u.tstamp, >=); +@@ -1356,12 +1409,13 @@ match_expr(struct search_node_list *head + } + + static int +-list_session(char *log_dir, regex_t *re, const char *user, const char *tty) ++list_session(struct sudo_lbuf *lbuf, char *log_dir, regex_t *re, ++ const char *user, const char *tty) + { + char idbuf[7], *idstr, *cp; + struct eventlog *evlog = NULL; + const char *timestr; +- int ret = -1; ++ int i, ret = -1; + debug_decl(list_session, SUDO_DEBUG_UTIL); + + if ((evlog = iolog_parse_loginfo(-1, log_dir)) == NULL) +@@ -1393,23 +1447,71 @@ list_session(char *log_dir, regex_t *re, + } + /* XXX - print lines + cols? */ + timestr = get_timestr(evlog->submit_time.tv_sec, 1); +- printf("%s : %s : ", timestr ? timestr : "invalid date", evlog->submituser); +- if (evlog->submithost != NULL) +- printf("HOST=%s ; ", evlog->submithost); +- if (evlog->ttyname != NULL) +- printf("TTY=%s ; ", evlog->ttyname); +- if (evlog->runchroot != NULL) +- printf("CHROOT=%s ; ", evlog->runchroot); +- if (evlog->runcwd != NULL || evlog->cwd != NULL) +- printf("CWD=%s ; ", evlog->runcwd ? evlog->runcwd : evlog->cwd); +- printf("USER=%s ; ", evlog->runuser); +- if (evlog->rungroup != NULL) +- printf("GROUP=%s ; ", evlog->rungroup); +- printf("TSID=%s ; COMMAND=%s\n", idstr, evlog->command); ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "%s : %s : ", ++ timestr ? timestr : "invalid date", evlog->submituser); ++ if (evlog->submithost != NULL) { ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "HOST=%s ; ", ++ evlog->submithost); ++ } ++ if (evlog->ttyname != NULL) { ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TTY=%s ; ", ++ evlog->ttyname); ++ } ++ if (evlog->runchroot != NULL) { ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "CHROOT=%s ; ", ++ evlog->runchroot); ++ } ++ if (evlog->runcwd != NULL || evlog->cwd != NULL) { ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "CWD=%s ; ", ++ evlog->runcwd ? evlog->runcwd : evlog->cwd); ++ } ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "USER=%s ; ", evlog->runuser); ++ if (evlog->rungroup != NULL) { ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "GROUP=%s ; ", ++ evlog->rungroup); ++ } ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TSID=%s ; ", idstr); ++ ++ /* ++ * If we have both command and argv from info.json we can escape ++ * blanks in the the command and arguments. If all we have is a ++ * single string containing both the command and arguments we cannot. ++ */ ++ if (evlog->argv != NULL) { ++ /* Command plus argv from the info.json file. */ ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, ++ "COMMAND=%s", evlog->command); ++ if (evlog->argv[0] != NULL) { ++ for (i = 1; evlog->argv[i] != NULL; i++) { ++ sudo_lbuf_append(lbuf, " "); ++ if (strchr(evlog->argv[i], ' ') != NULL) { ++ /* Wrap args containing spaces in single quotes. */ ++ sudo_lbuf_append(lbuf, "'"); ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL|LBUF_ESC_QUOTE, ++ "%s", evlog->argv[i]); ++ sudo_lbuf_append(lbuf, "'"); ++ } else { ++ /* Escape quotes here too for consistency. */ ++ sudo_lbuf_append_esc(lbuf, ++ LBUF_ESC_CNTRL|LBUF_ESC_BLANK|LBUF_ESC_QUOTE, ++ "%s", evlog->argv[i]); ++ } ++ } ++ } ++ } else { ++ /* Single string from the legacy info file. */ ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "COMMAND=%s", ++ evlog->command); ++ } + +- ret = 0; ++ if (!sudo_lbuf_error(lbuf)) { ++ puts(lbuf->buf); ++ ret = 0; ++ } + + done: ++ lbuf->error = 0; ++ lbuf->len = 0; + eventlog_free(evlog); + debug_return_int(ret); + } +@@ -1429,6 +1531,7 @@ find_sessions(const char *dir, regex_t * + DIR *d; + struct dirent *dp; + struct stat sb; ++ struct sudo_lbuf lbuf; + size_t sdlen, sessions_len = 0, sessions_size = 0; + unsigned int i; + int len; +@@ -1440,6 +1543,8 @@ find_sessions(const char *dir, regex_t * + #endif + debug_decl(find_sessions, SUDO_DEBUG_UTIL); + ++ sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0); ++ + d = opendir(dir); + if (d == NULL) + sudo_fatal(U_("unable to open %s"), dir); +@@ -1500,7 +1605,7 @@ find_sessions(const char *dir, regex_t * + /* Check for dir with a log file. */ + if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) { + pathbuf[sdlen + len - 4] = '\0'; +- list_session(pathbuf, re, user, tty); ++ list_session(&lbuf, pathbuf, re, user, tty); + } else { + /* Strip off "/log" and recurse if a non-log dir. */ + pathbuf[sdlen + len - 4] = '\0'; +@@ -1511,6 +1616,7 @@ find_sessions(const char *dir, regex_t * + } + free(sessions); + } ++ sudo_lbuf_destroy(&lbuf); + + debug_return_int(0); + } diff --git a/sudo-1.9.15-CVE-2023-42465.patch b/sudo-1.9.15-CVE-2023-42465.patch new file mode 100644 index 0000000..f7f8458 --- /dev/null +++ b/sudo-1.9.15-CVE-2023-42465.patch @@ -0,0 +1,598 @@ +diff -up ./plugins/sudoers/auth/passwd.c.rowhammer ./plugins/sudoers/auth/passwd.c +--- ./plugins/sudoers/auth/passwd.c.rowhammer 2020-12-17 02:33:44.000000000 +0100 ++++ ./plugins/sudoers/auth/passwd.c 2024-01-22 16:01:16.331874669 +0100 +@@ -62,7 +62,7 @@ sudo_passwd_verify(struct passwd *pw, ch + char sav, *epass; + char *pw_epasswd = auth->data; + size_t pw_len; +- int matched = 0; ++ int ret; + debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH); + + /* An empty plain-text password must match an empty encrypted password. */ +@@ -85,27 +85,37 @@ sudo_passwd_verify(struct passwd *pw, ch + */ + epass = (char *) crypt(pass, pw_epasswd); + pass[8] = sav; ++ ret = AUTH_FAILURE; + if (epass != NULL) { +- if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN) +- matched = !strncmp(pw_epasswd, epass, DESLEN); +- else +- matched = !strcmp(pw_epasswd, epass); ++ if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN) { ++ if (strncmp(pw_epasswd, epass, DESLEN) == 0) ++ ret = AUTH_SUCCESS; ++ } else { ++ if (strcmp(pw_epasswd, epass) == 0) ++ ret = AUTH_SUCCESS; ++ } + } + +- debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE); ++ explicit_bzero(des_pass, sizeof(des_pass)); ++ ++ debug_return_int(ret); + } + #else + int + sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback) + { + char *pw_passwd = auth->data; +- int matched; ++ int ret; + debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH); + + /* Simple string compare for systems without crypt(). */ + matched = !strcmp(pass, pw_passwd); ++ if (strcmp(pass, pw_passwd) == 0) ++ ret = AUTH_SUCCESS; ++ else ++ ret = AUTH_FAILURE; + +- debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE); ++ debug_return_int(ret); + } + #endif + +diff -up ./plugins/sudoers/auth/sudo_auth.c.rowhammer ./plugins/sudoers/auth/sudo_auth.c +--- ./plugins/sudoers/auth/sudo_auth.c.rowhammer 2020-12-17 02:33:43.000000000 +0100 ++++ ./plugins/sudoers/auth/sudo_auth.c 2024-01-22 16:01:16.331874669 +0100 +@@ -112,10 +112,16 @@ sudo_auth_init(struct passwd *pw) + if (auth->init && !IS_DISABLED(auth)) { + /* Disable if it failed to init unless there was a fatal error. */ + status = (auth->init)(pw, auth); +- if (status == AUTH_FAILURE) +- SET(auth->flags, FLAG_DISABLED); +- else if (status == AUTH_FATAL) +- break; /* assume error msg already printed */ ++ switch (status) { ++ case AUTH_SUCCESS: ++ break; ++ case AUTH_FAILURE: ++ SET(auth->flags, FLAG_DISABLED); ++ break; ++ default: ++ /* Assume error msg already printed. */ ++ debug_return_int(-1); ++ } + } + } + +@@ -161,7 +167,7 @@ sudo_auth_init(struct passwd *pw) + } + } + +- debug_return_int(status == AUTH_FATAL ? -1 : 0); ++ debug_return_int(0); + } + + /* +@@ -202,7 +208,7 @@ sudo_auth_cleanup(struct passwd *pw, boo + for (auth = auth_switch; auth->name; auth++) { + if (auth->cleanup && !IS_DISABLED(auth)) { + int status = (auth->cleanup)(pw, auth, force); +- if (status == AUTH_FATAL) { ++ if (status != AUTH_SUCCESS) { + /* Assume error msg already printed. */ + debug_return_int(-1); + } +@@ -297,7 +303,7 @@ verify_user(struct passwd *pw, char *pro + status = (auth->setup)(pw, &prompt, auth); + if (status == AUTH_FAILURE) + SET(auth->flags, FLAG_DISABLED); +- else if (status == AUTH_FATAL || user_interrupted()) ++ else if (status != AUTH_SUCCESS || user_interrupted()) + goto done; /* assume error msg already printed */ + } + } +@@ -348,7 +354,6 @@ done: + log_auth_failure(validated, ntries); + ret = false; + break; +- case AUTH_FATAL: + default: + log_auth_failure(validated, 0); + ret = -1; +@@ -360,24 +365,32 @@ done: + + /* + * Call authentication method begin session hooks. +- * Returns 1 on success and -1 on error. ++ * Returns true on success, false on failure and -1 on error. + */ + int + sudo_auth_begin_session(struct passwd *pw, char **user_env[]) + { + sudo_auth *auth; ++ int ret = true; + debug_decl(sudo_auth_begin_session, SUDOERS_DEBUG_AUTH); + + for (auth = auth_switch; auth->name; auth++) { + if (auth->begin_session && !IS_DISABLED(auth)) { + int status = (auth->begin_session)(pw, user_env, auth); +- if (status != AUTH_SUCCESS) { +- /* Assume error msg already printed. */ +- debug_return_int(-1); ++ switch (status) { ++ case AUTH_SUCCESS: ++ break; ++ case AUTH_FAILURE: ++ ret = false; ++ break; ++ default: ++ /* Assume error msg already printed. */ ++ ret = -1; ++ break; + } + } + } +- debug_return_int(1); ++ debug_return_int(ret); + } + + bool +@@ -398,25 +411,33 @@ sudo_auth_needs_end_session(void) + + /* + * Call authentication method end session hooks. +- * Returns 1 on success and -1 on error. ++ * Returns true on success, false on failure and -1 on error. + */ + int + sudo_auth_end_session(struct passwd *pw) + { + sudo_auth *auth; ++ int ret = true; + int status; + debug_decl(sudo_auth_end_session, SUDOERS_DEBUG_AUTH); + + for (auth = auth_switch; auth->name; auth++) { + if (auth->end_session && !IS_DISABLED(auth)) { + status = (auth->end_session)(pw, auth); +- if (status == AUTH_FATAL) { +- /* Assume error msg already printed. */ +- debug_return_int(-1); +- } ++ switch (status) { ++ case AUTH_SUCCESS: ++ break; ++ case AUTH_FAILURE: ++ ret = false; ++ break; ++ default: ++ /* Assume error msg already printed. */ ++ ret = -1; ++ break; ++ } + } + } +- debug_return_int(1); ++ debug_return_int(ret); + } + + /* +diff -up ./plugins/sudoers/auth/sudo_auth.h.rowhammer ./plugins/sudoers/auth/sudo_auth.h +--- ./plugins/sudoers/auth/sudo_auth.h.rowhammer 2020-12-17 02:33:43.000000000 +0100 ++++ ./plugins/sudoers/auth/sudo_auth.h 2024-01-22 16:01:16.332874679 +0100 +@@ -19,11 +19,11 @@ + #ifndef SUDO_AUTH_H + #define SUDO_AUTH_H + +-/* Auth function return values. */ +-#define AUTH_SUCCESS 0 +-#define AUTH_FAILURE 1 +-#define AUTH_INTR 2 +-#define AUTH_FATAL 3 ++/* Auth function return values (rowhammer resistent). */ ++#define AUTH_SUCCESS 0x52a2925 /* 0101001010100010100100100101 */ ++#define AUTH_FAILURE 0xad5d6da /* 1010110101011101011011011010 */ ++#define AUTH_INTR 0x69d61fc8 /* 1101001110101100001111111001000 */ ++#define AUTH_FATAL 0x1629e037 /* 0010110001010011110000000110111 */ + + typedef struct sudo_auth { + int flags; /* various flags, see below */ +diff -up ./plugins/sudoers/cvtsudoers.c.rowhammer ./plugins/sudoers/cvtsudoers.c +--- ./plugins/sudoers/cvtsudoers.c.rowhammer 2024-01-22 18:30:09.585081693 +0100 ++++ ./plugins/sudoers/cvtsudoers.c 2024-01-22 18:32:35.238519869 +0100 +@@ -685,7 +685,7 @@ userlist_matches_filter(struct sudoers_p + pw.pw_uid = (uid_t)-1; + pw.pw_gid = (gid_t)-1; + +- if (user_matches(parse_tree, &pw, m) == true) ++ if (user_matches(parse_tree, &pw, m) == ALLOW) + matched = true; + } else { + STAILQ_FOREACH(s, &filters->users, entries) { +@@ -711,7 +711,7 @@ userlist_matches_filter(struct sudoers_p + if (pw == NULL) + continue; + +- if (user_matches(parse_tree, pw, m) == true) ++ if (user_matches(parse_tree, pw, m) == ALLOW) + matched = true; + sudo_pw_delref(pw); + +@@ -787,7 +787,7 @@ hostlist_matches_filter(struct sudoers_p + + /* Only need one host in the filter to match. */ + /* XXX - can't use netgroup_tuple with NULL pw */ +- if (host_matches(parse_tree, NULL, lhost, shost, m) == true) { ++ if (host_matches(parse_tree, NULL, lhost, shost, m) == ALLOW) { + matched = true; + break; + } +diff -up ./plugins/sudoers/match.c.rowhammer ./plugins/sudoers/match.c +--- ./plugins/sudoers/match.c.rowhammer 2020-12-17 02:33:44.000000000 +0100 ++++ ./plugins/sudoers/match.c 2024-01-22 16:01:16.332874679 +0100 +@@ -26,6 +26,7 @@ + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + ++#include "parse.h" + #include + + #include +@@ -70,37 +71,42 @@ user_matches(struct sudoers_parse_tree * + { + const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost; + const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost; +- int matched = UNSPEC; ++ int rc, matched = UNSPEC; + struct alias *a; + debug_decl(user_matches, SUDOERS_DEBUG_MATCH); + + switch (m->type) { + case ALL: +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case NETGROUP: + if (netgr_matches(m->name, + def_netgroup_tuple ? lhost : NULL, + def_netgroup_tuple ? shost : NULL, pw->pw_name)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case USERGROUP: + if (usergr_matches(m->name, pw->pw_name, pw)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + if ((a = alias_get(parse_tree, m->name, USERALIAS)) != NULL) { + /* XXX */ +- int rc = userlist_matches(parse_tree, pw, &a->members); +- if (rc != UNSPEC) +- matched = m->negated ? !rc : rc; ++ rc = userlist_matches(parse_tree, pw, &a->members); ++ if (SPECIFIED(rc)) { ++ if (m->negated) { ++ matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ matched = rc; ++ } ++ } + alias_put(a); + break; + } + FALLTHROUGH; + case WORD: + if (userpw_matches(m->name, pw->pw_name, pw)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + } + debug_return_int(matched); +@@ -119,7 +125,8 @@ userlist_matches(struct sudoers_parse_tr + debug_decl(userlist_matches, SUDOERS_DEBUG_MATCH); + + TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { +- if ((matched = user_matches(parse_tree, pw, m)) != UNSPEC) ++ matched = user_matches(parse_tree, pw, m); ++ if (SPECIFIED(matched)) + break; + } + debug_return_int(matched); +@@ -164,48 +171,53 @@ runaslist_matches(struct sudoers_parse_t + /* If no runas user or runas group listed in sudoers, use default. */ + if (user_list == NULL && group_list == NULL) { + debug_return_int(userpw_matches(def_runas_default, +- runas_pw->pw_name, runas_pw)); ++ runas_pw->pw_name, runas_pw) ? ALLOW : DENY); + } + + if (user_list != NULL) { + TAILQ_FOREACH_REVERSE(m, user_list, member_list, entries) { + switch (m->type) { + case ALL: +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + case NETGROUP: + if (netgr_matches(m->name, + def_netgroup_tuple ? lhost : NULL, + def_netgroup_tuple ? shost : NULL, + runas_pw->pw_name)) +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + case USERGROUP: + if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, RUNASALIAS); + if (a != NULL) { + rc = runaslist_matches(parse_tree, &a->members, + &empty, matching_user, NULL); +- if (rc != UNSPEC) +- user_matched = m->negated ? !rc : rc; ++ if (SPECIFIED(rc)) { ++ if (m->negated) { ++ user_matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ user_matched = rc; ++ } ++ } + alias_put(a); + break; + } + FALLTHROUGH; + case WORD: + if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + case MYSELF: + if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) || + strcmp(user_name, runas_pw->pw_name) == 0) +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + } +- if (user_matched != UNSPEC) { ++ if (SPECIFIED(user_matched)) { + if (matching_user != NULL && m->type != ALIAS) + *matching_user = m; + break; +@@ -226,34 +238,40 @@ runaslist_matches(struct sudoers_parse_t + TAILQ_FOREACH_REVERSE(m, group_list, member_list, entries) { + switch (m->type) { + case ALL: +- group_matched = !m->negated; ++ group_matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, RUNASALIAS); + if (a != NULL) { + rc = runaslist_matches(parse_tree, &empty, + &a->members, NULL, matching_group); +- if (rc != UNSPEC) +- group_matched = m->negated ? !rc : rc; ++ if (SPECIFIED(rc)) { ++ if (m->negated) { ++ group_matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ group_matched = rc; ++ } ++ } + alias_put(a); + break; + } + FALLTHROUGH; + case WORD: + if (group_matches(m->name, runas_gr)) +- group_matched = !m->negated; ++ group_matched = m->negated ? DENY : ALLOW; + break; + } +- if (group_matched != UNSPEC) { ++ if (SPECIFIED(group_matched)) { + if (matching_group != NULL && m->type != ALIAS) + *matching_group = m; + break; + } + } + } +- if (group_matched == UNSPEC) { ++ if (!SPECIFIED(group_matched)) { + struct gid_list *runas_groups; + /* ++ * + * The runas group was not explicitly allowed by sudoers. + * Check whether it is one of the target user's groups. + */ +@@ -295,7 +313,7 @@ hostlist_matches_int(struct sudoers_pars + + TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { + matched = host_matches(parse_tree, pw, lhost, shost, m); +- if (matched != UNSPEC) ++ if (SPECIFIED(matched)) + break; + } + debug_return_int(matched); +@@ -324,37 +342,42 @@ host_matches(struct sudoers_parse_tree * + const char *lhost, const char *shost, const struct member *m) + { + struct alias *a; +- int matched = UNSPEC; ++ int rc, matched = UNSPEC; + debug_decl(host_matches, SUDOERS_DEBUG_MATCH); + + switch (m->type) { + case ALL: +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case NETGROUP: + if (netgr_matches(m->name, lhost, shost, + def_netgroup_tuple ? pw->pw_name : NULL)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case NTWKADDR: + if (addr_matches(m->name)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, HOSTALIAS); + if (a != NULL) { + /* XXX */ +- int rc = hostlist_matches_int(parse_tree, pw, lhost, shost, ++ rc = hostlist_matches_int(parse_tree, pw, lhost, shost, + &a->members); +- if (rc != UNSPEC) +- matched = m->negated ? !rc : rc; ++ if (SPECIFIED(rc)) { ++ if (m->negated) { ++ matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ matched = rc; ++ } ++ } + alias_put(a); + break; + } + FALLTHROUGH; + case WORD: + if (hostname_matches(shost, lhost, m->name)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + } + debug_return_int(matched); +@@ -375,7 +398,7 @@ cmndlist_matches(struct sudoers_parse_tr + + TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { + matched = cmnd_matches(parse_tree, m, runchroot, info); +- if (matched != UNSPEC) ++ if (SPECIFIED(matched)) + break; + } + debug_return_int(matched); +@@ -397,21 +420,26 @@ cmnd_matches(struct sudoers_parse_tree * + switch (m->type) { + case ALL: + if (m->name == NULL) { +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + } + FALLTHROUGH; + case COMMAND: + c = (struct sudo_command *)m->name; + if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, CMNDALIAS); + if (a != NULL) { + rc = cmndlist_matches(parse_tree, &a->members, runchroot, info); +- if (rc != UNSPEC) +- matched = m->negated ? !rc : rc; ++ if (SPECIFIED(rc)) { ++ if (m->negated) { ++ matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ matched = rc; ++ } ++ } + alias_put(a); + } + break; +diff -up ./plugins/sudoers/parse.c.rowhammer ./plugins/sudoers/parse.c +--- ./plugins/sudoers/parse.c.rowhammer 2020-12-17 02:33:43.000000000 +0100 ++++ ./plugins/sudoers/parse.c 2024-01-22 16:01:16.333874689 +0100 +@@ -151,7 +151,7 @@ sudoers_lookup_check(struct sudo_nss *ns + if (runas_match == ALLOW) { + cmnd_match = cmnd_matches(nss->parse_tree, cs->cmnd, + cs->runchroot, info); +- if (cmnd_match != UNSPEC) { ++ if (SPECIFIED(cmnd_match)) { + /* + * If user is running command as himself, + * set runas_pw = sudo_user.pw. +@@ -365,7 +365,7 @@ sudoers_lookup(struct sudo_nss_list *snl + } + + m = sudoers_lookup_check(nss, pw, &validated, &info, &cs, &defs, now); +- if (m != UNSPEC) { ++ if (SPECIFIED(m)) { + match = m; + parse_tree = nss->parse_tree; + } +@@ -373,7 +373,7 @@ sudoers_lookup(struct sudo_nss_list *snl + if (!sudo_nss_can_continue(nss, m)) + break; + } +- if (match != UNSPEC) { ++ if (SPECIFIED(match)) { + if (info.cmnd_path != NULL) { + /* Update user_cmnd, user_stat, cmnd_status from matching entry. */ + free(user_cmnd); +diff -up ./plugins/sudoers/parse.h.rowhammer ./plugins/sudoers/parse.h +--- ./plugins/sudoers/parse.h.rowhammer 2021-01-09 21:12:16.000000000 +0100 ++++ ./plugins/sudoers/parse.h 2024-01-22 16:01:16.333874689 +0100 +@@ -20,6 +20,9 @@ + #ifndef SUDOERS_PARSE_H + #define SUDOERS_PARSE_H + ++#include ++#include ++#include + #include + #include "sudo_queue.h" + +@@ -31,13 +34,26 @@ + + #undef UNSPEC + #define UNSPEC -1 ++ ++/* Denied by policy (rowhammer resistent). */ + #undef DENY +-#define DENY 0 ++#define DENY 0xad5d6da /* 1010110101011101011011011010 */ ++ ++/* Allowed by policy (rowhammer resistent). */ + #undef ALLOW +-#define ALLOW 1 ++#define ALLOW 0x52a2925 /* 0101001010100010100100100101 */ ++ + #undef IMPLIED + #define IMPLIED 2 + ++ ++/* ++ * We must explicitly check against ALLOW and DENY instead testing ++ * that the value is not UNSPEC to avoid potential ROWHAMMER issues. ++ */ ++#define SPECIFIED(_v) ((_v) == ALLOW || (_v) == DENY) ++ ++ + /* + * Initialize all tags to UNSPEC. + */ diff --git a/sudo.spec b/sudo.spec index 8c29268..857e95f 100644 --- a/sudo.spec +++ b/sudo.spec @@ -1,7 +1,7 @@ Summary: Allows restricted root access for specified users Name: sudo Version: 1.9.5p2 -Release: 9%{?dist} +Release: 10%{?dist} License: ISC URL: https://www.sudo.ws @@ -34,6 +34,20 @@ Patch6: covscan.patch Patch7: sha-digest-calc.patch Patch8: sudo-1.9.12-CVE-2023-22809.patch +Patch9: sudo-1.9.13-CVE-2023-28486-7-1.patch +Patch10: sudo-1.9.13-CVE-2023-28486-7-2.patch +Patch11: sudo-1.9.13-CVE-2023-28486-7-3.patch +Patch12: sudo-1.9.13-CVE-2023-28486-7-4.patch +Patch13: sudo-1.9.13-CVE-2023-28486-7-5.patch +Patch14: sudo-1.9.13-CVE-2023-28486-7-6.patch +Patch15: sudo-1.9.13-CVE-2023-28486-7-7.patch +Patch16: sudo-1.9.13-CVE-2023-28486-7-8.patch +Patch17: sudo-1.9.13-CVE-2023-28486-7-9.patch + +Patch18: linker.patch + +Patch19: sudo-1.9.15-CVE-2023-42465.patch + %description Sudo (superuser do) allows a system administrator to give certain users (or groups of users) the ability to run some (or all) commands @@ -65,14 +79,28 @@ BuildRequires: python3-devel %prep %setup -q -%patch1 -p1 -b .sudo-conf -%patch2 -p1 -b .undefined -%patch3 -p1 -b .selinux-t -%patch4 -p1 -b .bad-cond -%patch5 -p1 -b .utmp-leak -%patch6 -p1 -b .covscan -%patch7 -p1 -b .sha-digest -%patch8 -p1 -b .cve-fix +%patch -P 1 -p1 -b .sudo-conf +%patch -P 2 -p1 -b .undefined +%patch -P 3 -p1 -b .selinux-t +%patch -P 4 -p1 -b .bad-cond +%patch -P 5 -p1 -b .utmp-leak +%patch -P 6 -p1 -b .covscan +%patch -P 7 -p1 -b .sha-digest +%patch -P 8 -p1 -b .cve-fix + +%patch -P 9 -p1 -b .cve-escape-1 +%patch -P 10 -p1 -b .cve-escape-2 +%patch -P 11 -p1 -b .cve-escape-3 +%patch -P 12 -p1 -b .cve-escape-4 +%patch -P 13 -p1 -b .cve-escape-5 +%patch -P 14 -p1 -b .cve-escape-6 +%patch -P 15 -p1 -b .cve-escape-7 +%patch -P 16 -p1 -b .cve-escape-8 +%patch -P 17 -p1 -b .cve-escape-9 + +%patch -P 18 -p1 -b .linker +%patch -P 19 -p1 -b .rowhammer + %build # Remove bundled copy of zlib @@ -247,6 +275,16 @@ EOF %attr(0644,root,root) %{_libexecdir}/sudo/python_plugin.so %changelog +* Mon Jan 22 2024 Radovan Sroka - 1.9.5p2-10 +RHEL 9.3.0.Z ERRATUM +- CVE-2023-28487 sudo: Sudo does not escape control characters in sudoreplay output +Resolves: RHEL-21834 +- CVE-2023-28486 sudo: Sudo does not escape control characters in log messages +Resolves: RHEL-21828 +- CVE-2023-42465 sudo: Targeted Corruption of Register and Stack Variables +Resolves: RHEL-21821 + + * Thu Jan 19 2023 Radovan Sroka - 1.9.5p2-9 RHEL 9.2.0 ERRATUM - CVE-2023-22809 sudo: arbitrary file write with privileges of the RunAs user