From f8883a97a048c84ade399f9052a99b4a5d0892b9 Mon Sep 17 00:00:00 2001 From: Radovan Sroka Date: Mon, 22 Jan 2024 22:00:39 +0100 Subject: [PATCH] RHEL 8.9.0.Z ERRATUM - Rebase to 1.9.5p2 - CVE-2023-28486 sudo: Sudo does not escape control characters in log messages Resolves: RHEL-21825 - CVE-2023-28487 sudo: Sudo does not escape control characters in sudoreplay output Resolves: RHEL-21831 - CVE-2023-42465 sudo: Targeted Corruption of Register and Stack Variables Resolves: RHEL-21820 Signed-off-by: Radovan Sroka --- .gitignore | 1 + covscan.patch | 35 + linker.patch | 79 ++ sources | 2 +- sudo-1.6.7p5-strip.patch | 11 - sudo-1.7.2p1-envdebug.patch | 27 - sudo-1.8.23-ldapsearchuidfix.patch | 27 - sudo-1.8.23-legacy-group-processing.patch | 89 -- sudo-1.8.23-nowaitopt.patch | 60 -- sudo-1.8.23-sudoldapconfman.patch | 32 - sudo-1.8.29-CVE-2019-18634.patch | 77 -- sudo-1.8.29-CVE-2019-19232.patch | 169 ---- sudo-1.8.29-CVE-2019-19234.patch | 439 --------- sudo-1.8.29-expired-password-part1.patch | 154 --- sudo-1.8.29-expired-password-part2.patch | 29 - sudo-1.8.31-CVE-2021-3156.patch | 206 ---- sudo-1.8.6p7-logsudouser.patch | 90 -- sudo-1.9.12-CVE-2023-22809-backports.patch | 171 ---- sudo-1.9.12-CVE-2023-22809-whitelist.patch | 57 -- sudo-1.9.12-CVE-2023-22809.patch | 95 +- 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-1.9.5-CVE-2021-23239.patch | 61 -- sudo-1.9.5-CVE-2021-23240-1.patch | 158 --- sudo-1.9.5-CVE-2021-23240-2.patch | 431 --------- sudo-1.9.5-CVE-2021-23240-3.patch | 345 ------- sudo-1.9.5-CVE-2021-23240-4.patch | 380 -------- sudo-1.9.5-CVE-2021-23240-5.patch | 47 - sudo-1.9.5-selinux-t.patch | 74 ++ sudo-1.9.5-sesh-bad-condition.patch | 51 + sudo-1.9.5-sudoedit-selinux.patch | 11 - sudo-1.9.5-undefined-symbol.patch | 19 + ...p-leak.patch => sudo-1.9.5-utmp-leak.patch | 0 sudo-1.9.7-krb5ccname.patch | 54 -- sudo-1.9.7-sigchild.patch | 35 - sudo.spec | 146 ++- 44 files changed, 3744 insertions(+), 3290 deletions(-) create mode 100644 covscan.patch create mode 100644 linker.patch delete mode 100644 sudo-1.6.7p5-strip.patch delete mode 100644 sudo-1.7.2p1-envdebug.patch delete mode 100644 sudo-1.8.23-ldapsearchuidfix.patch delete mode 100644 sudo-1.8.23-legacy-group-processing.patch delete mode 100644 sudo-1.8.23-nowaitopt.patch delete mode 100644 sudo-1.8.23-sudoldapconfman.patch delete mode 100644 sudo-1.8.29-CVE-2019-18634.patch delete mode 100644 sudo-1.8.29-CVE-2019-19232.patch delete mode 100644 sudo-1.8.29-CVE-2019-19234.patch delete mode 100644 sudo-1.8.29-expired-password-part1.patch delete mode 100644 sudo-1.8.29-expired-password-part2.patch delete mode 100644 sudo-1.8.31-CVE-2021-3156.patch delete mode 100644 sudo-1.8.6p7-logsudouser.patch delete mode 100644 sudo-1.9.12-CVE-2023-22809-backports.patch delete mode 100644 sudo-1.9.12-CVE-2023-22809-whitelist.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 delete mode 100644 sudo-1.9.5-CVE-2021-23239.patch delete mode 100644 sudo-1.9.5-CVE-2021-23240-1.patch delete mode 100644 sudo-1.9.5-CVE-2021-23240-2.patch delete mode 100644 sudo-1.9.5-CVE-2021-23240-3.patch delete mode 100644 sudo-1.9.5-CVE-2021-23240-4.patch delete mode 100644 sudo-1.9.5-CVE-2021-23240-5.patch create mode 100644 sudo-1.9.5-selinux-t.patch create mode 100644 sudo-1.9.5-sesh-bad-condition.patch delete mode 100644 sudo-1.9.5-sudoedit-selinux.patch create mode 100644 sudo-1.9.5-undefined-symbol.patch rename sudo-1.9.7-utmp-leak.patch => sudo-1.9.5-utmp-leak.patch (100%) delete mode 100644 sudo-1.9.7-krb5ccname.patch delete mode 100644 sudo-1.9.7-sigchild.patch diff --git a/.gitignore b/.gitignore index 306885f..e2ff536 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ /sudo-1.8.28.tar.gz /sudo-1.8.28p1.tar.gz /sudo-1.8.29.tar.gz +/sudo-1.9.5p2.tar.gz diff --git a/covscan.patch b/covscan.patch new file mode 100644 index 0000000..a67e556 --- /dev/null +++ b/covscan.patch @@ -0,0 +1,35 @@ +diff -up ./lib/eventlog/eventlog.c.covscan ./lib/eventlog/eventlog.c +--- ./lib/eventlog/eventlog.c.covscan 2021-08-26 11:06:35.068915415 +0200 ++++ ./lib/eventlog/eventlog.c 2021-08-26 11:13:32.432472325 +0200 +@@ -1075,10 +1075,13 @@ do_logfile_sudo(const char *logline, con + if (ferror(fp)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "unable to write log file %s", logfile); +- goto done; ++ goto ddone; + } + ret = true; + ++ddone: ++ (void)free(full_line); ++ + done: + (void)sudo_lock_file(fileno(fp), SUDO_UNLOCK); + evl_conf.close_log(EVLOG_FILE, fp); +diff -up ./logsrvd/logsrvd.c.covscan ./logsrvd/logsrvd.c +diff -up ./plugins/audit_json/audit_json.c.covscan ./plugins/audit_json/audit_json.c +diff -up ./plugins/sudoers/ldap.c.covscan ./plugins/sudoers/ldap.c +--- ./plugins/sudoers/ldap.c.covscan 2021-08-26 15:46:11.614179451 +0200 ++++ ./plugins/sudoers/ldap.c 2021-08-26 15:51:40.871812534 +0200 +@@ -443,6 +443,8 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMe + goto done; + } + ++ free(cp); ++ + /* Walk through options, appending to defs. */ + for (p = bv; *p != NULL; p++) { + char *var, *val; +diff -up ./plugins/sudoers/logging.c.covscan ./plugins/sudoers/logging.c +diff -up ./plugins/sudoers/rcstr.c.covscan ./plugins/sudoers/rcstr.c +diff -up ./src/utmp.c.covscan ./src/utmp.c 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/sources b/sources index d6aec86..e39bcb4 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (sudo-1.8.29.tar.gz) = ea780922b2afb47df4df4b533fb355fd916cb18a6bfd13c7ca36a25b03ef585d805648c6fa85692bea363b1f83664ac3bc622f99bcd149b3a86f70522eb4d340 +SHA512 (sudo-1.9.5p2.tar.gz) = f0fe914963c31a6f8ab6c86847ff6cdd125bd5a839b27f46dcae03963f4fc413b3d4cca54c1979feb825c8479b44c7df0642c07345c941eecf6f9f1e03ea0e27 diff --git a/sudo-1.6.7p5-strip.patch b/sudo-1.6.7p5-strip.patch deleted file mode 100644 index f9e2faa..0000000 --- a/sudo-1.6.7p5-strip.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- sudo-1.6.7p5/install-sh.strip 2005-07-21 14:28:25.000000000 +0200 -+++ sudo-1.6.7p5/install-sh 2005-07-21 14:29:18.000000000 +0200 -@@ -138,7 +138,7 @@ - fi - ;; - X-s) -- STRIPIT=true -+ #STRIPIT=true - ;; - X--) - shift diff --git a/sudo-1.7.2p1-envdebug.patch b/sudo-1.7.2p1-envdebug.patch deleted file mode 100644 index 94c719a..0000000 --- a/sudo-1.7.2p1-envdebug.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 44a602b49365969e56c63c9f12eda197e951302f Mon Sep 17 00:00:00 2001 -From: Tomas Sykora -Date: Fri, 19 Aug 2016 14:07:35 +0200 -Subject: [PATCH 02/10] Added "Enviroment debugging" message - -rebased from: -Patch2: sudo-1.7.2p1-envdebug.patch ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 9feddfd..39a2d86 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1390,7 +1390,7 @@ AC_ARG_ENABLE(env_debug, - [AS_HELP_STRING([--enable-env-debug], [Whether to enable environment debugging.])], - [ case "$enableval" in - yes) AC_MSG_RESULT(yes) -- AC_DEFINE(ENV_DEBUG) -+ AC_DEFINE(ENV_DEBUG, [], [Environment debugging.]) - ;; - no) AC_MSG_RESULT(no) - ;; --- -2.7.4 - diff --git a/sudo-1.8.23-ldapsearchuidfix.patch b/sudo-1.8.23-ldapsearchuidfix.patch deleted file mode 100644 index 9698d23..0000000 --- a/sudo-1.8.23-ldapsearchuidfix.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff -up sudo-1.8.23/plugins/sudoers/ldap.c.ldapsearchuidfix sudo-1.8.23/plugins/sudoers/ldap.c ---- sudo-1.8.23/plugins/sudoers/ldap.c.ldapsearchuidfix 2018-04-29 21:59:31.000000000 +0200 -+++ sudo-1.8.23/plugins/sudoers/ldap.c 2018-06-18 08:34:01.202686941 +0200 -@@ -1189,8 +1189,8 @@ sudo_ldap_build_pass1(LDAP *ld, struct p - if (ldap_conf.search_filter) - sz += strlen(ldap_conf.search_filter); - -- /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */ -- sz += 29 + sudo_ldap_value_len(pw->pw_name); -+ /* Then add (|(sudoUser=USERNAME)(sudoUser=#uid)(sudoUser=ALL)) + NUL */ -+ sz += 29 + (12 + MAX_UID_T_LEN) + sudo_ldap_value_len(pw->pw_name); - - /* Add space for primary and supplementary groups and gids */ - if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) { -@@ -1253,6 +1253,12 @@ sudo_ldap_build_pass1(LDAP *ld, struct p - CHECK_LDAP_VCAT(buf, pw->pw_name, sz); - CHECK_STRLCAT(buf, ")", sz); - -+ /* Append user uid */ -+ (void) snprintf(gidbuf, sizeof(gidbuf), "%u", (unsigned int)pw->pw_uid); -+ (void) strlcat(buf, "(sudoUser=#", sz); -+ (void) strlcat(buf, gidbuf, sz); -+ (void) strlcat(buf, ")", sz); -+ - /* Append primary group and gid */ - if (grp != NULL) { - CHECK_STRLCAT(buf, "(sudoUser=%", sz); diff --git a/sudo-1.8.23-legacy-group-processing.patch b/sudo-1.8.23-legacy-group-processing.patch deleted file mode 100644 index aee16eb..0000000 --- a/sudo-1.8.23-legacy-group-processing.patch +++ /dev/null @@ -1,89 +0,0 @@ -diff -up ./plugins/sudoers/cvtsudoers.c.legacy-processing ./plugins/sudoers/cvtsudoers.c ---- ./plugins/sudoers/cvtsudoers.c.legacy-processing 2019-10-28 13:28:52.000000000 +0100 -+++ ./plugins/sudoers/cvtsudoers.c 2019-10-30 13:32:43.309480623 +0100 -@@ -347,6 +347,15 @@ main(int argc, char *argv[]) - sudo_fatalx("error: unhandled input %d", input_format); - } - -+ /* -+ * cvtsudoers group filtering doesn't work if def_match_group_by_gid -+ * is set to true by default (at compile-time). It cannot be set to false -+ * because cvtsudoers doesn't apply the parsed Defaults. -+ * -+ * Related: sudo-1.8.23-legacy-group-processing.patch -+ */ -+ def_match_group_by_gid = def_legacy_group_processing = false; -+ - /* Apply filters. */ - filter_userspecs(&parsed_policy, conf); - filter_defaults(&parsed_policy, conf); -diff -up ./plugins/sudoers/defaults.c.legacy-processing ./plugins/sudoers/defaults.c ---- ./plugins/sudoers/defaults.c.legacy-processing 2019-10-28 13:28:52.000000000 +0100 -+++ ./plugins/sudoers/defaults.c 2019-10-30 13:32:43.309480623 +0100 -@@ -93,6 +93,7 @@ static struct early_default early_defaul - { I_FQDN }, - #endif - { I_MATCH_GROUP_BY_GID }, -+ { I_LEGACY_GROUP_PROCESSING }, - { I_GROUP_PLUGIN }, - { I_RUNAS_DEFAULT }, - { I_SUDOERS_LOCALE }, -@@ -494,6 +495,8 @@ init_defaults(void) - } - - /* First initialize the flags. */ -+ def_legacy_group_processing = true; -+ def_match_group_by_gid = true; - #ifdef LONG_OTP_PROMPT - def_long_otp_prompt = true; - #endif -diff -up ./plugins/sudoers/def_data.c.legacy-processing ./plugins/sudoers/def_data.c ---- ./plugins/sudoers/def_data.c.legacy-processing 2019-10-30 13:32:43.309480623 +0100 -+++ ./plugins/sudoers/def_data.c 2019-10-30 13:37:25.914602825 +0100 -@@ -506,6 +506,10 @@ struct sudo_defs_types sudo_defs_table[] - N_("Log when a command is denied by sudoers"), - NULL, - }, { -+ "legacy_group_processing", T_FLAG, -+ N_("Don't pre-resolve all group names"), -+ NULL, -+ }, { - NULL, 0, NULL - } - }; -diff -up ./plugins/sudoers/def_data.h.legacy-processing ./plugins/sudoers/def_data.h ---- ./plugins/sudoers/def_data.h.legacy-processing 2019-10-30 13:32:43.310480638 +0100 -+++ ./plugins/sudoers/def_data.h 2019-10-30 13:40:59.651713757 +0100 -@@ -232,6 +232,8 @@ - #define def_log_allowed (sudo_defs_table[I_LOG_ALLOWED].sd_un.flag) - #define I_LOG_DENIED 116 - #define def_log_denied (sudo_defs_table[I_LOG_DENIED].sd_un.flag) -+#define I_LEGACY_GROUP_PROCESSING 117 -+#define def_legacy_group_processing (sudo_defs_table[I_LEGACY_GROUP_PROCESSING].sd_un.flag) - - enum def_tuple { - never, -diff -up ./plugins/sudoers/def_data.in.legacy-processing ./plugins/sudoers/def_data.in ---- ./plugins/sudoers/def_data.in.legacy-processing 2019-10-30 13:32:43.310480638 +0100 -+++ ./plugins/sudoers/def_data.in 2019-10-30 13:42:20.915896239 +0100 -@@ -366,3 +366,6 @@ log_allowed - log_denied - T_FLAG - "Log when a command is denied by sudoers" -+legacy_group_processing -+ T_FLAG -+ "Don't pre-resolve all group names" -diff -up ./plugins/sudoers/sudoers.c.legacy-processing ./plugins/sudoers/sudoers.c ---- ./plugins/sudoers/sudoers.c.legacy-processing 2019-10-28 13:28:53.000000000 +0100 -+++ ./plugins/sudoers/sudoers.c 2019-10-30 13:32:43.310480638 +0100 -@@ -221,6 +221,10 @@ sudoers_policy_init(void *info, char * c - if (set_loginclass(runas_pw ? runas_pw : sudo_user.pw)) - ret = true; - -+ if (!def_match_group_by_gid || !def_legacy_group_processing) { -+ def_match_group_by_gid = false; -+ def_legacy_group_processing = false; -+ } - cleanup: - if (!restore_perms()) - ret = -1; diff --git a/sudo-1.8.23-nowaitopt.patch b/sudo-1.8.23-nowaitopt.patch deleted file mode 100644 index 4c3c603..0000000 --- a/sudo-1.8.23-nowaitopt.patch +++ /dev/null @@ -1,60 +0,0 @@ -diff -up ./plugins/sudoers/def_data.c.nowait ./plugins/sudoers/def_data.c ---- ./plugins/sudoers/def_data.c.nowait 2019-10-30 13:43:48.376168944 +0100 -+++ ./plugins/sudoers/def_data.c 2019-10-30 13:43:48.378168973 +0100 -@@ -510,6 +510,10 @@ struct sudo_defs_types sudo_defs_table[] - N_("Don't pre-resolve all group names"), - NULL, - }, { -+ "cmnd_no_wait", T_FLAG, -+ N_("Don't fork and wait for the command to finish, just exec it"), -+ NULL, -+ }, { - NULL, 0, NULL - } - }; -diff -up ./plugins/sudoers/def_data.h.nowait ./plugins/sudoers/def_data.h ---- ./plugins/sudoers/def_data.h.nowait 2019-10-30 13:43:48.378168973 +0100 -+++ ./plugins/sudoers/def_data.h 2019-10-30 13:45:38.425770365 +0100 -@@ -234,6 +234,8 @@ - #define def_log_denied (sudo_defs_table[I_LOG_DENIED].sd_un.flag) - #define I_LEGACY_GROUP_PROCESSING 117 - #define def_legacy_group_processing (sudo_defs_table[I_LEGACY_GROUP_PROCESSING].sd_un.flag) -+#define I_CMND_NO_WAIT 118 -+#define def_cmnd_no_wait (sudo_defs_table[I_CMND_NO_WAIT].sd_un.flag) - - enum def_tuple { - never, -diff -up ./plugins/sudoers/def_data.in.nowait ./plugins/sudoers/def_data.in ---- ./plugins/sudoers/def_data.in.nowait 2019-10-30 13:43:48.376168944 +0100 -+++ ./plugins/sudoers/def_data.in 2019-10-30 13:43:48.379168987 +0100 -@@ -369,3 +369,6 @@ log_denied - legacy_group_processing - T_FLAG - "Don't pre-resolve all group names" -+cmnd_no_wait -+ T_FLAG -+ "Don't fork and wait for the command to finish, just exec it" -diff -up ./plugins/sudoers/sudoers.c.nowait ./plugins/sudoers/sudoers.c ---- ./plugins/sudoers/sudoers.c.nowait 2019-10-30 13:43:48.376168944 +0100 -+++ ./plugins/sudoers/sudoers.c 2019-10-30 13:43:48.379168987 +0100 -@@ -225,6 +225,20 @@ sudoers_policy_init(void *info, char * c - def_match_group_by_gid = false; - def_legacy_group_processing = false; - } -+ -+ /* -+ * Emulate cmnd_no_wait option by disabling PAM session, PTY allocation -+ * and I/O logging. This will cause sudo to execute the given command -+ * directly instead of forking a separate process for it. -+ */ -+ if (def_cmnd_no_wait) { -+ def_pam_setcred = false; -+ def_pam_session = false; -+ def_use_pty = false; -+ def_log_input = false; -+ def_log_output = false; -+ } -+ - cleanup: - if (!restore_perms()) - ret = -1; diff --git a/sudo-1.8.23-sudoldapconfman.patch b/sudo-1.8.23-sudoldapconfman.patch deleted file mode 100644 index d290162..0000000 --- a/sudo-1.8.23-sudoldapconfman.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff -up sudo-1.8.23/doc/Makefile.in.sudoldapconfman sudo-1.8.23/doc/Makefile.in ---- sudo-1.8.23/doc/Makefile.in.sudoldapconfman 2018-04-29 21:59:31.000000000 +0200 -+++ sudo-1.8.23/doc/Makefile.in 2018-05-17 13:56:24.693651178 +0200 -@@ -345,10 +345,16 @@ install-doc: install-dirs - rm -f $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)$(MANCOMPRESSEXT); \ - echo ln -s sudo.$(mansectsu)$(MANCOMPRESSEXT) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)$(MANCOMPRESSEXT); \ - ln -s sudo.$(mansectsu)$(MANCOMPRESSEXT) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)$(MANCOMPRESSEXT); \ -+ rm -f $(DESTDIR)$(mandirform)/sudo-ldap.conf.$(mansectform)$(MANCOMPRESSEXT); \ -+ echo ln -s sudoers.ldap.$(mansectform)$(MANCOMPRESSEXT) $(DESTDIR)$(mandirform)/sudo-ldap.conf.$(mansectform)$(MANCOMPRESSEXT); \ -+ ln -s sudoers.ldap.$(mansectform)$(MANCOMPRESSEXT) $(DESTDIR)$(mandirform)/sudo-ldap.conf.$(mansectform)$(MANCOMPRESSEXT); \ - else \ - rm -f $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu); \ - echo ln -s sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu); \ - ln -s sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu); \ -+ rm -f $(DESTDIR)$(mandirform)/sudo-ldap.conf.$(mansectform); \ -+ echo ln -s sudoers.ldap.$(mansectform) $(DESTDIR)$(mandirform)/sudo-ldap.conf.$(mansectform); \ -+ ln -s sudoers.ldap.$(mansectform) $(DESTDIR)$(mandirform)/sudo-ldap.conf.$(mansectform); \ - fi - - install-plugin: -@@ -363,8 +369,9 @@ uninstall: - $(DESTDIR)$(mandirsu)/visudo.$(mansectsu) \ - $(DESTDIR)$(mandirform)/sudo.conf.$(mansectform) \ - $(DESTDIR)$(mandirform)/sudoers.$(mansectform) \ -- $(DESTDIR)$(mandirform)/sudoers_timestamp.$(mansectform) -- $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform) -+ $(DESTDIR)$(mandirform)/sudoers_timestamp.$(mansectform) \ -+ $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform) \ -+ $(DESTDIR)$(mandirform)/sudo-ldap.conf.$(mansectform) - - splint: - diff --git a/sudo-1.8.29-CVE-2019-18634.patch b/sudo-1.8.29-CVE-2019-18634.patch deleted file mode 100644 index cc6fa49..0000000 --- a/sudo-1.8.29-CVE-2019-18634.patch +++ /dev/null @@ -1,77 +0,0 @@ -diff -up ./src/tgetpass.c.CVE-2019-18634 ./src/tgetpass.c ---- ./src/tgetpass.c.CVE-2019-18634 2019-10-28 13:27:39.000000000 +0100 -+++ ./src/tgetpass.c 2020-02-05 14:08:27.516101197 +0100 -@@ -61,7 +61,7 @@ enum tgetpass_errval { - static volatile sig_atomic_t signo[NSIG]; - - static void tgetpass_handler(int); --static char *getln(int, char *, size_t, int, enum tgetpass_errval *); -+static char *getln(int, char *, size_t, bool, enum tgetpass_errval *); - static char *sudo_askpass(const char *, const char *); - - static int -@@ -125,6 +125,7 @@ tgetpass(const char *prompt, int timeout - static char buf[SUDO_CONV_REPL_MAX + 1]; - int i, input, output, save_errno, ttyfd; - bool need_restart, neednl = false; -+ bool feedback = ISSET(flags, TGP_MASK); - enum tgetpass_errval errval; - debug_decl(tgetpass, SUDO_DEBUG_CONV) - -@@ -180,7 +181,7 @@ restart: - */ - if (!ISSET(flags, TGP_ECHO)) { - for (;;) { -- if (ISSET(flags, TGP_MASK)) -+ if (feedback) - neednl = sudo_term_cbreak(input); - else - neednl = sudo_term_noecho(input); -@@ -194,6 +195,9 @@ restart: - } - } - } -+ /* Only use feedback mode when we can disable echo. */ -+ if (!neednl) -+ feedback = false; - - /* - * Catch signals that would otherwise cause the user to end -@@ -224,7 +228,7 @@ restart: - - if (timeout > 0) - alarm(timeout); -- pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval); -+ pass = getln(input, buf, sizeof(buf), feedback, &errval); - alarm(0); - save_errno = errno; - -@@ -360,7 +364,7 @@ sudo_askpass(const char *askpass, const - extern int sudo_term_eof, sudo_term_erase, sudo_term_kill; - - static char * --getln(int fd, char *buf, size_t bufsiz, int feedback, -+getln(int fd, char *buf, size_t bufsiz, bool feedback, - enum tgetpass_errval *errval) - { - size_t left = bufsiz; -@@ -389,15 +393,15 @@ getln(int fd, char *buf, size_t bufsiz, - while (cp > buf) { - if (write(fd, "\b \b", 3) == -1) - break; -- --cp; -+ cp--; - } -+ cp = buf; - left = bufsiz; - continue; - } else if (c == sudo_term_erase) { - if (cp > buf) { -- if (write(fd, "\b \b", 3) == -1) -- break; -- --cp; -+ ignore_result(write(fd, "\b \b", 3)); -+ cp--; - left++; - } - continue; diff --git a/sudo-1.8.29-CVE-2019-19232.patch b/sudo-1.8.29-CVE-2019-19232.patch deleted file mode 100644 index f7a006f..0000000 --- a/sudo-1.8.29-CVE-2019-19232.patch +++ /dev/null @@ -1,169 +0,0 @@ -diff -up ./doc/sudoers.man.in.CVE-2019-19232 ./doc/sudoers.man.in ---- ./doc/sudoers.man.in.CVE-2019-19232 2019-10-28 13:28:52.000000000 +0100 -+++ ./doc/sudoers.man.in 2020-01-14 15:34:46.908027286 +0100 -@@ -2942,6 +2942,23 @@ This flag is - \fIoff\fR - by default. - .TP 18n -+runas_allow_unknown_id -+If enabled, allow matching of runas user and group IDs that are -+not present in the password or group databases. -+In addition to explicitly matching unknown user or group IDs in a -+\fRRunas_List\fR, -+this option also allows the -+\fBALL\fR -+alias to match unknown IDs. -+This flag is -+\fIoff\fR -+by default. -+.sp -+This setting is only supported by version 1.8.29 or higher. -+Older versions of -+\fBsudo\fR -+always allowed matching of unknown user and group IDs. -+.TP 18n - runaspw - If set, - \fBsudo\fR -diff -up ./doc/sudoers.mdoc.in.CVE-2019-19232 ./doc/sudoers.mdoc.in ---- ./doc/sudoers.mdoc.in.CVE-2019-19232 2019-10-28 13:28:52.000000000 +0100 -+++ ./doc/sudoers.mdoc.in 2020-01-14 15:34:46.908027286 +0100 -@@ -2768,6 +2768,22 @@ when running a command or editing a file - This flag is - .Em off - by default. -+.It runas_allow_unknown_id -+If enabled, allow matching of runas user and group IDs that are -+not present in the password or group databases. -+In addition to explicitly matching unknown user or group IDs in a -+.Li Runas_List , -+this option also allows the -+.Sy ALL -+alias to match unknown IDs. -+This flag is -+.Em off -+by default. -+.Pp -+This setting is only supported by version 1.8.29 or higher. -+Older versions of -+.Nm sudo -+always allowed matching of unknown user and group IDs. - .It runaspw - If set, - .Nm sudo -diff -up ./plugins/sudoers/defaults.c.CVE-2019-19232 ./plugins/sudoers/defaults.c ---- ./plugins/sudoers/defaults.c.CVE-2019-19232 2020-01-14 15:34:46.902027246 +0100 -+++ ./plugins/sudoers/defaults.c 2020-01-14 15:34:46.909027293 +0100 -@@ -581,6 +581,7 @@ init_defaults(void) - def_fdexec = digest_only; - def_log_allowed = true; - def_log_denied = true; -+ def_runas_allow_unknown_id = false; - - /* Syslog options need special care since they both strings and ints */ - #if (LOGGING & SLOG_SYSLOG) -diff -up ./plugins/sudoers/def_data.c.CVE-2019-19232 ./plugins/sudoers/def_data.c ---- ./plugins/sudoers/def_data.c.CVE-2019-19232 2020-01-14 15:34:46.908027286 +0100 -+++ ./plugins/sudoers/def_data.c 2020-01-14 15:40:19.441555509 +0100 -@@ -514,6 +514,10 @@ struct sudo_defs_types sudo_defs_table[] - N_("Don't fork and wait for the command to finish, just exec it"), - NULL, - }, { -+ "runas_allow_unknown_id", T_FLAG, -+ N_("Allow the use of unknown runas user and/or group ID"), -+ NULL, -+ }, { - NULL, 0, NULL - } - }; -diff -up ./plugins/sudoers/def_data.h.CVE-2019-19232 ./plugins/sudoers/def_data.h ---- ./plugins/sudoers/def_data.h.CVE-2019-19232 2020-01-14 15:34:46.909027293 +0100 -+++ ./plugins/sudoers/def_data.h 2020-01-14 15:41:33.658012401 +0100 -@@ -236,6 +236,8 @@ - #define def_legacy_group_processing (sudo_defs_table[I_LEGACY_GROUP_PROCESSING].sd_un.flag) - #define I_CMND_NO_WAIT 118 - #define def_cmnd_no_wait (sudo_defs_table[I_CMND_NO_WAIT].sd_un.flag) -+#define I_RUNAS_ALLOW_UNKNOWN_ID 119 -+#define def_runas_allow_unknown_id (sudo_defs_table[I_RUNAS_ALLOW_UNKNOWN_ID].sd_un.flag) - - enum def_tuple { - never, -diff -up ./plugins/sudoers/def_data.in.CVE-2019-19232 ./plugins/sudoers/def_data.in ---- ./plugins/sudoers/def_data.in.CVE-2019-19232 2020-01-14 15:34:46.909027293 +0100 -+++ ./plugins/sudoers/def_data.in 2020-01-14 15:42:42.176481484 +0100 -@@ -372,3 +372,6 @@ legacy_group_processing - cmnd_no_wait - T_FLAG - "Don't fork and wait for the command to finish, just exec it" -+runas_allow_unknown_id -+ T_FLAG -+ "Allow the use of unknown runas user and/or group ID" -diff -up ./plugins/sudoers/sudoers.c.CVE-2019-19232 ./plugins/sudoers/sudoers.c ---- ./plugins/sudoers/sudoers.c.CVE-2019-19232 2020-01-14 15:34:46.905027266 +0100 -+++ ./plugins/sudoers/sudoers.c 2020-01-14 15:34:46.910027299 +0100 -@@ -105,6 +105,8 @@ static char *prev_user; - static char *runas_user; - static char *runas_group; - static struct sudo_nss_list *snl; -+static bool unknown_runas_uid; -+static bool unknown_runas_gid; - - #ifdef __linux__ - static struct rlimit nproclimit; -@@ -354,6 +356,22 @@ sudoers_policy_main(int argc, char * con - } - } - -+ /* Defer uid/gid checks until after defaults have been updated. */ -+ if (unknown_runas_uid && !def_runas_allow_unknown_id) { -+ audit_failure(NewArgc, NewArgv, N_("unknown user: %s"), -+ runas_pw->pw_name); -+ sudo_warnx(U_("unknown user: %s"), runas_pw->pw_name); -+ goto done; -+ } -+ if (runas_gr != NULL) { -+ if (unknown_runas_gid && !def_runas_allow_unknown_id) { -+ audit_failure(NewArgc, NewArgv, N_("unknown group: %s"), -+ runas_gr->gr_name); -+ sudo_warnx(U_("unknown group: %s"), runas_gr->gr_name); -+ goto done; -+ } -+ } -+ - /* - * Look up the timestamp dir owner if one is specified. - */ -@@ -1167,12 +1185,15 @@ set_runaspw(const char *user, bool quiet - struct passwd *pw = NULL; - debug_decl(set_runaspw, SUDOERS_DEBUG_PLUGIN) - -+ unknown_runas_uid = false; - if (*user == '#') { - const char *errstr; - uid_t uid = sudo_strtoid(user + 1, &errstr); - if (errstr == NULL) { -- if ((pw = sudo_getpwuid(uid)) == NULL) -+ if ((pw = sudo_getpwuid(uid)) == NULL) { -+ unknown_runas_uid = true; - pw = sudo_fakepwnam(user, user_gid); -+ } - } - } - if (pw == NULL) { -@@ -1198,12 +1219,15 @@ set_runasgr(const char *group, bool quie - struct group *gr = NULL; - debug_decl(set_runasgr, SUDOERS_DEBUG_PLUGIN) - -+ unknown_runas_gid = false; - if (*group == '#') { - const char *errstr; - gid_t gid = sudo_strtoid(group + 1, &errstr); - if (errstr == NULL) { -- if ((gr = sudo_getgrgid(gid)) == NULL) -+ if ((gr = sudo_getgrgid(gid)) == NULL) { -+ unknown_runas_gid = true; - gr = sudo_fakegrnam(group); -+ } - } - } - if (gr == NULL) { diff --git a/sudo-1.8.29-CVE-2019-19234.patch b/sudo-1.8.29-CVE-2019-19234.patch deleted file mode 100644 index 264db7f..0000000 --- a/sudo-1.8.29-CVE-2019-19234.patch +++ /dev/null @@ -1,439 +0,0 @@ -diff -up ./config.h.in.CVE-2019-19234 ./config.h.in ---- ./config.h.in.CVE-2019-19234 2019-10-28 13:28:52.000000000 +0100 -+++ ./config.h.in 2020-01-14 15:53:40.506988064 +0100 -@@ -334,6 +334,9 @@ - /* Define to 1 if you have the `getuserattr' function. */ - #undef HAVE_GETUSERATTR - -+/* Define to 1 if you have the `getusershell' function. */ -+#undef HAVE_GETUSERSHELL -+ - /* Define to 1 if you have the `getutid' function. */ - #undef HAVE_GETUTID - -diff -up ./configure.ac.CVE-2019-19234 ./configure.ac ---- ./configure.ac.CVE-2019-19234 2020-01-14 15:53:40.496987995 +0100 -+++ ./configure.ac 2020-01-14 15:53:40.509988084 +0100 -@@ -2562,6 +2562,10 @@ AC_CHECK_FUNCS([getdelim], [], [ - SUDO_APPEND_COMPAT_EXP(sudo_getdelim) - COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }getdelim_test" - ]) -+AC_CHECK_FUNCS([getusershell], [], [ -+ AC_LIBOBJ(getusershell) -+ SUDO_APPEND_COMPAT_EXP(sudo_getusershell) -+]) - AC_CHECK_FUNCS([reallocarray], [], [ - AC_LIBOBJ(reallocarray) - SUDO_APPEND_COMPAT_EXP(sudo_reallocarray) -diff -up ./configure.CVE-2019-19234 ./configure ---- ./configure.CVE-2019-19234 2019-10-28 13:29:14.000000000 +0100 -+++ ./configure 2020-01-14 15:53:40.509988084 +0100 -@@ -19395,6 +19395,32 @@ esac - fi - done - -+for ac_func in getusershell -+do : -+ ac_fn_c_check_func "$LINENO" "getusershell" "ac_cv_func_getusershell" -+if test "x$ac_cv_func_getusershell" = xyes; then : -+ cat >>confdefs.h <<_ACEOF -+#define HAVE_GETUSERSHELL 1 -+_ACEOF -+ -+else -+ -+ case " $LIBOBJS " in -+ *" getusershell.$ac_objext "* ) ;; -+ *) LIBOBJS="$LIBOBJS getusershell.$ac_objext" -+ ;; -+esac -+ -+ -+ for _sym in sudo_getusershell; do -+ COMPAT_EXP="${COMPAT_EXP}${_sym} -+" -+ done -+ -+ -+fi -+done -+ - for ac_func in reallocarray - do : - ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" -diff -up ./doc/sudoers.man.in.CVE-2019-19234 ./doc/sudoers.man.in ---- ./doc/sudoers.man.in.CVE-2019-19234 2020-01-14 15:53:40.503988043 +0100 -+++ ./doc/sudoers.man.in 2020-01-14 15:53:40.510988091 +0100 -@@ -2959,6 +2959,28 @@ Older versions of - \fBsudo\fR - always allowed matching of unknown user and group IDs. - .TP 18n -+runas_check_shell -+.br -+If enabled, -+\fBsudo\fR -+will only run commands as a user whose shell appears in the -+\fI/etc/shells\fR -+file, even if the invoking user's -+\fRRunas_List\fR -+would otherwise permit it. -+If no -+\fI/etc/shells\fR -+file is present, a system-dependent list of built-in default shells is used. -+On many operating systems, system users such as -+\(lqbin\(rq, -+do not have a valid shell and this flag can be used to prevent -+commands from being run as those users. -+This flag is -+\fIoff\fR -+by default. -+.sp -+This setting is only supported by version 1.8.29 or higher. -+.TP 18n - runaspw - If set, - \fBsudo\fR -diff -up ./doc/sudoers.mdoc.in.CVE-2019-19234 ./doc/sudoers.mdoc.in ---- ./doc/sudoers.mdoc.in.CVE-2019-19234 2020-01-14 15:53:40.504988050 +0100 -+++ ./doc/sudoers.mdoc.in 2020-01-14 15:53:40.510988091 +0100 -@@ -2784,6 +2784,26 @@ This setting is only supported by versio - Older versions of - .Nm sudo - always allowed matching of unknown user and group IDs. -+.It runas_check_shell -+If enabled, -+.Nm sudo -+will only run commands as a user whose shell appears in the -+.Pa /etc/shells -+file, even if the invoking user's -+.Li Runas_List -+would otherwise permit it. -+If no -+.Pa /etc/shells -+file is present, a system-dependent list of built-in default shells is used. -+On many operating systems, system users such as -+.Dq bin , -+do not have a valid shell and this flag can be used to prevent -+commands from being run as those users. -+This flag is -+.Em off -+by default. -+.Pp -+This setting is only supported by version 1.8.29 or higher. - .It runaspw - If set, - .Nm sudo -diff -up ./include/sudo_compat.h.CVE-2019-19234 ./include/sudo_compat.h ---- ./include/sudo_compat.h.CVE-2019-19234 2019-10-28 13:28:52.000000000 +0100 -+++ ./include/sudo_compat.h 2020-01-14 15:53:40.511988098 +0100 -@@ -407,6 +407,17 @@ __dso_public ssize_t sudo_getdelim(char - # undef getdelim - # define getdelim(_a, _b, _c, _d) sudo_getdelim((_a), (_b), (_c), (_d)) - #endif /* HAVE_GETDELIM */ -+#ifndef HAVE_GETUSERSHELL -+__dso_public char *sudo_getusershell(void); -+# undef getusershell -+# define getusershell() sudo_getusershell() -+__dso_public void sudo_setusershell(void); -+# undef setusershell -+# define setusershell() sudo_setusershell() -+__dso_public void sudo_endusershell(void); -+# undef endusershell -+# define endusershell() sudo_endusershell() -+#endif /* HAVE_GETUSERSHELL */ - #ifndef HAVE_UTIMENSAT - __dso_public int sudo_utimensat(int fd, const char *file, const struct timespec *times, int flag); - # undef utimensat -diff -up ./lib/util/getusershell.c.CVE-2019-19234 ./lib/util/getusershell.c ---- ./lib/util/getusershell.c.CVE-2019-19234 2020-01-14 15:53:40.511988098 +0100 -+++ ./lib/util/getusershell.c 2020-01-14 15:53:40.511988098 +0100 -@@ -0,0 +1,138 @@ -+/* -+ * SPDX-License-Identifier: ISC -+ * -+ * Copyright (c) 2019 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. -+ */ -+ -+/* -+ * 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 -+ -+#define DEFAULT_TEXT_DOMAIN "sudo" -+#include "sudo_gettext.h" /* must be included before sudo_compat.h */ -+ -+#include "sudo_compat.h" -+#include "sudo_debug.h" -+#include "sudo_util.h" -+ -+static char **allowed_shells, **current_shell; -+static char *default_shells[] = { -+ "/bin/sh", -+ "/bin/ksh", -+ "/bin/ksh93", -+ "/bin/bash", -+ "/bin/dash", -+ "/bin/zsh", -+ "/bin/csh", -+ "/bin/tcsh", -+ NULL -+}; -+ -+static char ** -+read_shells(void) -+{ -+ size_t maxshells = 16, nshells = 0; -+ size_t linesize = 0; -+ char *line = NULL; -+ FILE *fp; -+ debug_decl(read_shells, SUDO_DEBUG_UTIL) -+ -+ if ((fp = fopen("/etc/shells", "r")) == NULL) -+ goto bad; -+ -+ free(allowed_shells); -+ allowed_shells = reallocarray(NULL, maxshells, sizeof(char *)); -+ if (allowed_shells == NULL) -+ goto bad; -+ -+ while (sudo_parseln(&line, &linesize, NULL, fp, PARSELN_CONT_IGN) != -1) { -+ if (nshells + 1 >= maxshells) { -+ char **new_shells; -+ -+ new_shells = reallocarray(NULL, maxshells + 16, sizeof(char *)); -+ if (new_shells == NULL) -+ goto bad; -+ allowed_shells = new_shells; -+ maxshells += 16; -+ } -+ if ((allowed_shells[nshells] = strdup(line)) == NULL) -+ goto bad; -+ nshells++; -+ } -+ allowed_shells[nshells] = NULL; -+ -+ free(line); -+ fclose(fp); -+ debug_return_ptr(allowed_shells); -+bad: -+ free(line); -+ if (fp != NULL) -+ fclose(fp); -+ while (nshells != 0) -+ free(allowed_shells[--nshells]); -+ free(allowed_shells); -+ allowed_shells = NULL; -+ debug_return_ptr(default_shells); -+} -+ -+void -+sudo_setusershell(void) -+{ -+ debug_decl(setusershell, SUDO_DEBUG_UTIL) -+ -+ current_shell = read_shells(); -+ -+ debug_return; -+} -+ -+void -+sudo_endusershell(void) -+{ -+ debug_decl(endusershell, SUDO_DEBUG_UTIL) -+ -+ if (allowed_shells != NULL) { -+ char **shell; -+ -+ for (shell = allowed_shells; *shell != NULL; shell++) -+ free(*shell); -+ free(allowed_shells); -+ allowed_shells = NULL; -+ } -+ current_shell = NULL; -+ -+ debug_return; -+} -+ -+char * -+sudo_getusershell(void) -+{ -+ debug_decl(getusershell, SUDO_DEBUG_UTIL) -+ -+ if (current_shell == NULL) -+ current_shell = read_shells(); -+ -+ debug_return_str(*current_shell++); -+} -diff -up ./lib/util/Makefile.in.CVE-2019-19234 ./lib/util/Makefile.in ---- ./lib/util/Makefile.in.CVE-2019-19234 2019-10-28 13:28:53.000000000 +0100 -+++ ./lib/util/Makefile.in 2020-01-14 15:53:40.511988098 +0100 -@@ -678,6 +678,18 @@ gettime.i: $(srcdir)/gettime.c $(incdir) - $(CC) -E -o $@ $(CPPFLAGS) $< - gettime.plog: gettime.i - rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/gettime.c --i-file $< --output-file $@ -+getusershell.lo: $(srcdir)/getusershell.c $(incdir)/compat/stdbool.h \ -+ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ -+ $(incdir)/sudo_gettext.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)/getusershell.c -+getusershell.i: $(srcdir)/getusershell.c $(incdir)/compat/stdbool.h \ -+ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ -+ $(incdir)/sudo_gettext.h $(incdir)/sudo_queue.h \ -+ $(incdir)/sudo_util.h $(top_builddir)/config.h -+ $(CC) -E -o $@ $(CPPFLAGS) $< -+getusershell.plog: getusershell.i -+ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/getusershell.c --i-file $< --output-file $@ - gidlist.lo: $(srcdir)/gidlist.c $(incdir)/compat/stdbool.h \ - $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ - $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ -diff -up ./MANIFEST.CVE-2019-19234 ./MANIFEST ---- ./MANIFEST.CVE-2019-19234 2019-10-28 13:28:52.000000000 +0100 -+++ ./MANIFEST 2020-01-14 15:53:40.506988064 +0100 -@@ -103,6 +103,7 @@ lib/util/getgrouplist.c - lib/util/gethostname.c - lib/util/getopt_long.c - lib/util/gettime.c -+lib/util/getusershell.c - lib/util/gidlist.c - lib/util/glob.c - lib/util/inet_ntop.c -diff -up ./mkdep.pl.CVE-2019-19234 ./mkdep.pl ---- ./mkdep.pl.CVE-2019-19234 2019-10-28 13:28:52.000000000 +0100 -+++ ./mkdep.pl 2020-01-14 15:53:40.511988098 +0100 -@@ -116,7 +116,7 @@ sub mkdep { - # XXX - fill in AUTH_OBJS from contents of the auth dir instead - $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:; - $makefile =~ s:\@DIGEST\@:digest.lo digest_openssl.lo digest_gcrypt.lo:; -- $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.lo getopt_long.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo utimens.lo vsyslog.lo pipe2.lo:; -+ $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.lo getopt_long.lo getusershell.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo utimens.lo vsyslog.lo pipe2.lo:; - - # Parse OBJS lines - my %objs; -diff -up ./plugins/sudoers/check.c.CVE-2019-19234 ./plugins/sudoers/check.c ---- ./plugins/sudoers/check.c.CVE-2019-19234 2019-10-28 13:27:45.000000000 +0100 -+++ ./plugins/sudoers/check.c 2020-01-14 15:53:40.511988098 +0100 -@@ -333,3 +333,28 @@ get_authpw(int mode) - - debug_return_ptr(pw); - } -+ -+/* -+ * Returns true if the specified shell is allowed by /etc/shells, else false. -+ */ -+bool -+check_user_shell(const struct passwd *pw) -+{ -+ const char *shell; -+ debug_decl(check_user_shell, SUDOERS_DEBUG_AUTH) -+ -+ if (!def_runas_check_shell) -+ debug_return_bool(true); -+ -+ sudo_debug_printf(SUDO_DEBUG_INFO, -+ "%s: checking /etc/shells for %s", __func__, pw->pw_shell); -+ -+ setusershell(); -+ while ((shell = getusershell()) != NULL) { -+ if (strcmp(shell, pw->pw_shell) == 0) -+ debug_return_bool(true); -+ } -+ endusershell(); -+ -+ debug_return_bool(false); -+} -diff -up ./plugins/sudoers/def_data.c.CVE-2019-19234 ./plugins/sudoers/def_data.c ---- ./plugins/sudoers/def_data.c.CVE-2019-19234 2020-01-14 15:53:40.504988050 +0100 -+++ ./plugins/sudoers/def_data.c 2020-01-14 15:53:40.511988098 +0100 -@@ -518,6 +518,10 @@ struct sudo_defs_types sudo_defs_table[] - N_("Allow the use of unknown runas user and/or group ID"), - NULL, - }, { -+ "runas_check_shell", T_FLAG, -+ N_("Only permit running commands as a user with a valid shell"), -+ NULL, -+ }, { - NULL, 0, NULL - } - }; -diff -up ./plugins/sudoers/def_data.h.CVE-2019-19234 ./plugins/sudoers/def_data.h ---- ./plugins/sudoers/def_data.h.CVE-2019-19234 2020-01-14 15:53:40.512988105 +0100 -+++ ./plugins/sudoers/def_data.h 2020-01-14 15:58:06.927808982 +0100 -@@ -238,6 +238,8 @@ - #define def_cmnd_no_wait (sudo_defs_table[I_CMND_NO_WAIT].sd_un.flag) - #define I_RUNAS_ALLOW_UNKNOWN_ID 119 - #define def_runas_allow_unknown_id (sudo_defs_table[I_RUNAS_ALLOW_UNKNOWN_ID].sd_un.flag) -+#define I_RUNAS_CHECK_SHELL 120 -+#define def_runas_check_shell (sudo_defs_table[I_RUNAS_CHECK_SHELL].sd_un.flag) - - enum def_tuple { - never, -diff -up ./plugins/sudoers/def_data.in.CVE-2019-19234 ./plugins/sudoers/def_data.in ---- ./plugins/sudoers/def_data.in.CVE-2019-19234 2020-01-14 15:53:40.505988057 +0100 -+++ ./plugins/sudoers/def_data.in 2020-01-14 15:53:40.512988105 +0100 -@@ -375,3 +375,7 @@ cmnd_no_wait - runas_allow_unknown_id - T_FLAG - "Allow the use of unknown runas user and/or group ID" -+runas_check_shell -+ T_FLAG -+ "Only permit running commands as a user with a valid shell" -+ -diff -up ./plugins/sudoers/sudoers.c.CVE-2019-19234 ./plugins/sudoers/sudoers.c ---- ./plugins/sudoers/sudoers.c.CVE-2019-19234 2020-01-14 15:53:40.505988057 +0100 -+++ ./plugins/sudoers/sudoers.c 2020-01-14 15:53:40.512988105 +0100 -@@ -273,7 +273,7 @@ sudoers_policy_main(int argc, char * con - /* Not an audit event. */ - sudo_warnx(U_("sudoers specifies that root is not allowed to sudo")); - goto bad; -- } -+ } - - if (!set_perms(PERM_INITIAL)) - goto bad; -@@ -412,6 +412,13 @@ sudoers_policy_main(int argc, char * con - goto bad; - } - -+ /* Check runas user's shell. */ -+ if (!check_user_shell(runas_pw)) { -+ log_warningx(SLOG_RAW_MSG, N_("invalid shell for user %s: %s"), -+ runas_pw->pw_name, runas_pw->pw_shell); -+ goto bad; -+ } -+ - /* - * We don't reset the environment for sudoedit or if the user - * specified the -E command line flag and they have setenv privs. -diff -up ./plugins/sudoers/sudoers.h.CVE-2019-19234 ./plugins/sudoers/sudoers.h ---- ./plugins/sudoers/sudoers.h.CVE-2019-19234 2020-01-14 15:53:40.502988036 +0100 -+++ ./plugins/sudoers/sudoers.h 2020-01-14 15:53:40.512988105 +0100 -@@ -264,6 +264,7 @@ int find_path(const char *infile, char * - - /* check.c */ - int check_user(int validate, int mode); -+bool check_user_shell(const struct passwd *pw); - bool user_is_exempt(void); - - /* prompt.c */ diff --git a/sudo-1.8.29-expired-password-part1.patch b/sudo-1.8.29-expired-password-part1.patch deleted file mode 100644 index 8c8a0bb..0000000 --- a/sudo-1.8.29-expired-password-part1.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 4b6de608c25a6ffbdb507be958e12f814b43077c Mon Sep 17 00:00:00 2001 -From: "Todd C. Miller" -Date: Wed, 4 Dec 2019 12:38:22 -0700 -Subject: [PATCH] Only update the time stamp entry after the approval function - has succeeded. Bug #910 - ---- - plugins/sudoers/check.c | 59 +++++++++++++++++++---------------------- - 1 file changed, 27 insertions(+), 32 deletions(-) - -diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c -index db8e05161..ea1d89085 100644 ---- a/plugins/sudoers/check.c -+++ b/plugins/sudoers/check.c -@@ -51,6 +51,7 @@ static bool display_lecture(int); - static struct passwd *get_authpw(int); - - struct getpass_closure { -+ int tstat; - void *cookie; - struct passwd *auth_pw; - }; -@@ -89,27 +90,20 @@ getpass_resume(int signo, void *vclosure) - * or -1 on fatal error. - */ - static int --check_user_interactive(int validated, int mode, struct passwd *auth_pw) -+check_user_interactive(int validated, int mode, struct getpass_closure *closure) - { - struct sudo_conv_callback cb, *callback = NULL; -- struct getpass_closure closure; -- int status = TS_ERROR; - int ret = -1; - char *prompt; - bool lectured; - debug_decl(check_user_interactive, SUDOERS_DEBUG_AUTH) - -- /* Setup closure for getpass_{suspend,resume} */ -- closure.auth_pw = auth_pw; -- closure.cookie = NULL; -- sudo_pw_addref(closure.auth_pw); -- - /* Open, lock and read time stamp file if we are using it. */ - if (!ISSET(mode, MODE_IGNORE_TICKET)) { - /* Open time stamp file and check its status. */ -- closure.cookie = timestamp_open(user_name, user_sid); -- if (timestamp_lock(closure.cookie, closure.auth_pw)) -- status = timestamp_status(closure.cookie, closure.auth_pw); -+ closure->cookie = timestamp_open(user_name, user_sid); -+ if (timestamp_lock(closure->cookie, closure->auth_pw)) -+ closure->tstat = timestamp_status(closure->cookie, closure->auth_pw); - - /* Construct callback for getpass function. */ - memset(&cb, 0, sizeof(cb)); -@@ -120,7 +114,7 @@ check_user_interactive(int validated, int mode, struct passwd *auth_pw) - callback = &cb; - } - -- switch (status) { -+ switch (closure->tstat) { - case TS_FATAL: - /* Fatal error (usually setuid failure), unsafe to proceed. */ - goto done; -@@ -144,32 +138,22 @@ check_user_interactive(int validated, int mode, struct passwd *auth_pw) - } - - /* XXX - should not lecture if askpass helper is being used. */ -- lectured = display_lecture(status); -+ lectured = display_lecture(closure->tstat); - - /* Expand any escapes in the prompt. */ - prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt, -- closure.auth_pw->pw_name); -+ closure->auth_pw->pw_name); - if (prompt == NULL) - goto done; - -- ret = verify_user(closure.auth_pw, prompt, validated, callback); -+ ret = verify_user(closure->auth_pw, prompt, validated, callback); - if (ret == true && lectured) - (void)set_lectured(); /* lecture error not fatal */ - free(prompt); - break; - } - -- /* -- * Only update time stamp if user was validated. -- * Failure to update the time stamp is not a fatal error. -- */ -- if (ret == true && ISSET(validated, VALIDATE_SUCCESS) && status != TS_ERROR) -- (void)timestamp_update(closure.cookie, closure.auth_pw); - done: -- if (closure.cookie != NULL) -- timestamp_close(closure.cookie); -- sudo_pw_delref(closure.auth_pw); -- - debug_return_int(ret); - } - -@@ -180,7 +164,7 @@ done: - int - check_user(int validated, int mode) - { -- struct passwd *auth_pw; -+ struct getpass_closure closure = { TS_ERROR }; - int ret = -1; - bool exempt = false; - debug_decl(check_user, SUDOERS_DEBUG_AUTH) -@@ -189,9 +173,9 @@ check_user(int validated, int mode) - * Init authentication system regardless of whether we need a password. - * Required for proper PAM session support. - */ -- if ((auth_pw = get_authpw(mode)) == NULL) -+ if ((closure.auth_pw = get_authpw(mode)) == NULL) - goto done; -- if (sudo_auth_init(auth_pw) == -1) -+ if (sudo_auth_init(closure.auth_pw) == -1) - goto done; - - /* -@@ -222,15 +206,26 @@ check_user(int validated, int mode) - } - } - -- ret = check_user_interactive(validated, mode, auth_pw); -+ ret = check_user_interactive(validated, mode, &closure); - - done: - if (ret == true) { - /* The approval function may disallow a user post-authentication. */ -- ret = sudo_auth_approval(auth_pw, validated, exempt); -+ ret = sudo_auth_approval(closure.auth_pw, validated, exempt); -+ -+ /* -+ * Only update time stamp if user validated and was approved. -+ * Failure to update the time stamp is not a fatal error. -+ */ -+ if (ret == true && closure.tstat != TS_ERROR) { -+ if (ISSET(validated, VALIDATE_SUCCESS)) -+ (void)timestamp_update(closure.cookie, closure.auth_pw); -+ } - } -- sudo_auth_cleanup(auth_pw); -- sudo_pw_delref(auth_pw); -+ timestamp_close(closure.cookie); -+ sudo_auth_cleanup(closure.auth_pw); -+ if (closure.auth_pw != NULL) -+ sudo_pw_delref(closure.auth_pw); - - debug_return_int(ret); - } --- -2.25.1 - diff --git a/sudo-1.8.29-expired-password-part2.patch b/sudo-1.8.29-expired-password-part2.patch deleted file mode 100644 index 47f94d4..0000000 --- a/sudo-1.8.29-expired-password-part2.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 5472b1751645f750e42a0ba6daac667983b1a56c Mon Sep 17 00:00:00 2001 -From: "Todd C. Miller" -Date: Fri, 24 Jan 2020 11:13:55 -0700 -Subject: [PATCH] Fix crash in sudo 1.8.30 when suspending sudo at the password - prompt. The closure pointer in sudo_conv_callback was being filled in with a - struct getpass_closure ** instead of a struct getpass_closure *. The bug was - introduced in the fix for Bug #910; previously the closure variable was a - struct getpass_closure, not a pointer. Fix from Michael Norton; Bug #914. - ---- - plugins/sudoers/check.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c -index 72e87eef6..9b03c7a05 100644 ---- a/plugins/sudoers/check.c -+++ b/plugins/sudoers/check.c -@@ -108,7 +108,7 @@ check_user_interactive(int validated, int mode, struct getpass_closure *closure) - /* Construct callback for getpass function. */ - memset(&cb, 0, sizeof(cb)); - cb.version = SUDO_CONV_CALLBACK_VERSION; -- cb.closure = &closure; -+ cb.closure = closure; - cb.on_suspend = getpass_suspend; - cb.on_resume = getpass_resume; - callback = &cb; --- -2.25.1 - diff --git a/sudo-1.8.31-CVE-2021-3156.patch b/sudo-1.8.31-CVE-2021-3156.patch deleted file mode 100644 index 4175c1d..0000000 --- a/sudo-1.8.31-CVE-2021-3156.patch +++ /dev/null @@ -1,206 +0,0 @@ -diff -up ./plugins/sudoers/policy.c.heap-buffer ./plugins/sudoers/policy.c ---- ./plugins/sudoers/policy.c.heap-buffer 2019-10-28 13:28:52.000000000 +0100 -+++ ./plugins/sudoers/policy.c 2021-01-20 11:38:06.481807015 +0100 -@@ -100,10 +100,11 @@ parse_bool(const char *line, int varlen, - int - sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group) - { -+ const int edit_mask = MODE_EDIT|MODE_IGNORE_TICKET|MODE_NONINTERACTIVE; - struct sudoers_policy_open_info *info = v; -- char * const *cur; - const char *p, *errstr, *groups = NULL; - const char *remhost = NULL; -+ char * const *cur; - int flags = 0; - debug_decl(sudoers_policy_deserialize_info, SUDOERS_DEBUG_PLUGIN) - -@@ -332,6 +333,12 @@ sudoers_policy_deserialize_info(void *v, - #endif - } - -+ /* Sudo front-end should restrict mode flags for sudoedit. */ -+ if (ISSET(flags, MODE_EDIT) && (flags & edit_mask) != flags) { -+ sudo_warnx(U_("invalid mode flags from sudo front end: 0x%x"), flags); -+ goto bad; -+ } -+ - user_gid = (gid_t)-1; - user_sid = (pid_t)-1; - user_uid = (gid_t)-1; -diff -up ./plugins/sudoers/sudoers.c.heap-buffer ./plugins/sudoers/sudoers.c ---- ./plugins/sudoers/sudoers.c.heap-buffer 2021-01-20 11:34:57.523317977 +0100 -+++ ./plugins/sudoers/sudoers.c 2021-01-20 12:08:01.331553520 +0100 -@@ -451,7 +451,7 @@ sudoers_policy_main(int argc, char * con - - /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ - /* XXX - causes confusion when root is not listed in sudoers */ -- if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) { -+ if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT) && prev_user != NULL) { - if (user_uid == 0 && strcmp(prev_user, "root") != 0) { - struct passwd *pw; - -@@ -834,8 +834,8 @@ set_cmnd(void) - if (user_cmnd == NULL) - user_cmnd = NewArgv[0]; - -- if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { -- if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) { -+ if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT|MODE_CHECK)) { -+ if (!ISSET(sudo_mode, MODE_EDIT)) { - if (def_secure_path && !user_is_exempt()) - path = def_secure_path; - if (!set_perms(PERM_RUNAS)) -@@ -873,7 +873,8 @@ set_cmnd(void) - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - debug_return_int(-1); - } -- if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { -+ if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) && -+ ISSET(sudo_mode, MODE_RUN)) { - /* - * When running a command via a shell, the sudo front-end - * escapes potential meta chars. We unescape non-spaces -@@ -881,10 +882,22 @@ set_cmnd(void) - */ - for (to = user_args, av = NewArgv + 1; (from = *av); av++) { - while (*from) { -- if (from[0] == '\\' && !isspace((unsigned char)from[1])) -+ if (from[0] == '\\' && from[1] != '\0' && -+ !isspace((unsigned char)from[1])) { - from++; -+ } -+ if (size - (to - user_args) < 1) { -+ sudo_warnx(U_("internal error, %s overflow"), -+ __func__); -+ debug_return_int(NOT_FOUND_ERROR); -+ } - *to++ = *from++; - } -+ if (size - (to - user_args) < 1) { -+ sudo_warnx(U_("internal error, %s overflow"), -+ __func__); -+ debug_return_int(NOT_FOUND_ERROR); -+ } - *to++ = ' '; - } - *--to = '\0'; -diff -up ./plugins/sudoers/timestamp.c.heap-buffer ./plugins/sudoers/timestamp.c ---- ./plugins/sudoers/timestamp.c.heap-buffer 2021-01-20 12:11:28.218774128 +0100 -+++ ./plugins/sudoers/timestamp.c 2021-01-20 12:20:41.772324808 +0100 -@@ -652,8 +652,8 @@ timestamp_lock(void *vcookie, struct pas - } else if (entry.type != TS_LOCKEXCL) { - /* Old sudo record, convert it to TS_LOCKEXCL. */ - entry.type = TS_LOCKEXCL; -- memset((char *)&entry + offsetof(struct timestamp_entry, type), 0, -- nread - offsetof(struct timestamp_entry, type)); -+ memset((char *)&entry + offsetof(struct timestamp_entry, flags), 0, -+ nread - offsetof(struct timestamp_entry, flags)); - if (ts_write(cookie->fd, cookie->fname, &entry, 0) == -1) - debug_return_bool(false); - } -diff -up ./src/parse_args.c.heap-buffer ./src/parse_args.c ---- ./src/parse_args.c.heap-buffer 2021-01-20 11:35:18.231043445 +0100 -+++ ./src/parse_args.c 2021-01-20 12:26:31.290591673 +0100 -@@ -124,7 +124,10 @@ struct environment { - /* - * Default flags allowed when running a command. - */ --#define DEFAULT_VALID_FLAGS (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL) -+#define DEFAULT_VALID_FLAGS (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_PRESERVE_GROUPS|MODE_SHELL) -+#define EDIT_VALID_FLAGS MODE_NONINTERACTIVE -+#define LIST_VALID_FLAGS (MODE_NONINTERACTIVE|MODE_LONG_LIST) -+#define VALIDATE_VALID_FLAGS MODE_NONINTERACTIVE - - /* Option number for the --host long option due to ambiguity of the -h flag. */ - #define OPT_HOSTNAME 256 -@@ -269,6 +272,7 @@ parse_args(int argc, char **argv, int *n - progname = "sudoedit"; - mode = MODE_EDIT; - sudo_settings[ARG_SUDOEDIT].value = "true"; -+ valid_flags = EDIT_VALID_FLAGS; - } - - /* Load local IP addresses and masks. */ -@@ -360,7 +364,7 @@ parse_args(int argc, char **argv, int *n - usage_excl(1); - mode = MODE_EDIT; - sudo_settings[ARG_SUDOEDIT].value = "true"; -- valid_flags = MODE_NONINTERACTIVE; -+ valid_flags = EDIT_VALID_FLAGS; - break; - case 'g': - assert(optarg != NULL); -@@ -371,6 +375,7 @@ parse_args(int argc, char **argv, int *n - break; - case 'H': - sudo_settings[ARG_SET_HOME].value = "true"; -+ SET(flags, MODE_RESET_HOME); - break; - case 'h': - if (optarg == NULL) { -@@ -421,7 +426,7 @@ parse_args(int argc, char **argv, int *n - usage_excl(1); - } - mode = MODE_LIST; -- valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST; -+ valid_flags = LIST_VALID_FLAGS; - break; - case 'n': - SET(flags, MODE_NONINTERACTIVE); -@@ -429,6 +434,7 @@ parse_args(int argc, char **argv, int *n - break; - case 'P': - sudo_settings[ARG_PRESERVE_GROUPS].value = "true"; -+ SET(flags, MODE_PRESERVE_GROUPS); - break; - case 'p': - /* An empty prompt is allowed. */ -@@ -478,7 +484,7 @@ parse_args(int argc, char **argv, int *n - if (mode && mode != MODE_VALIDATE) - usage_excl(1); - mode = MODE_VALIDATE; -- valid_flags = MODE_NONINTERACTIVE; -+ valid_flags = VALIDATE_VALID_FLAGS; - break; - case 'V': - if (mode && mode != MODE_VERSION) -@@ -505,7 +511,7 @@ parse_args(int argc, char **argv, int *n - if (!mode) { - /* Defer -k mode setting until we know whether it is a flag or not */ - if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) { -- if (argc == 0 && !(flags & (MODE_SHELL|MODE_LOGIN_SHELL))) { -+ if (argc == 0 && !ISSET(flags, MODE_SHELL|MODE_LOGIN_SHELL)) { - mode = MODE_INVALIDATE; /* -k by itself */ - sudo_settings[ARG_IGNORE_TICKET].value = NULL; - valid_flags = 0; -@@ -568,23 +574,24 @@ parse_args(int argc, char **argv, int *n - /* - * For shell mode we need to rewrite argv - */ -- if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) { -+ if (ISSET(flags, MODE_SHELL|MODE_LOGIN_SHELL) && ISSET(mode, MODE_RUN)) { - char **av, *cmnd = NULL; - int ac = 1; - - if (argc != 0) { - /* shell -c "command" */ - char *src, *dst; -- size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) + -- strlen(argv[argc - 1]) + 1; -+ size_t size = 0; - -- cmnd = dst = reallocarray(NULL, cmnd_size, 2); -- if (cmnd == NULL) -+ for (av = argv; *av != NULL; av++) -+ size += strlen(*av) + 1; -+ -+ if (size == 0 || (cmnd = reallocarray(NULL, size, 2)) == NULL) - sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - if (!gc_add(GC_PTR, cmnd)) - exit(1); - -- for (av = argv; *av != NULL; av++) { -+ for (dst = cmnd, av = argv; *av != NULL; av++) { - for (src = *av; *src != '\0'; src++) { - /* quote potential meta characters */ - if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$') diff --git a/sudo-1.8.6p7-logsudouser.patch b/sudo-1.8.6p7-logsudouser.patch deleted file mode 100644 index c3742a0..0000000 --- a/sudo-1.8.6p7-logsudouser.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 06b46ae226fecd4188af372ac0ccd7aa582e21c8 Mon Sep 17 00:00:00 2001 -From: Tomas Sykora -Date: Wed, 17 Aug 2016 10:12:11 +0200 -Subject: [PATCH] Sudo logs username root instead of realuser - -RHEL7 sudo logs username root instead of realuser in /var/log/secure - -Rebased from: -Patch50: sudo-1.8.6p7-logsudouser.patch - -Resolves: -rhbz#1312486 ---- - plugins/sudoers/logging.c | 14 +++++++------- - plugins/sudoers/sudoers.h | 1 + - 2 files changed, 8 insertions(+), 7 deletions(-) - -diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c -index 45cae67..74b2220 100644 ---- a/plugins/sudoers/logging.c -+++ b/plugins/sudoers/logging.c -@@ -104,7 +104,7 @@ do_syslog(int pri, char *msg) - * Log the full line, breaking into multiple syslog(3) calls if necessary - */ - fmt = _("%8s : %s"); -- maxlen = def_syslog_maxlen - (strlen(fmt) - 5 + strlen(user_name)); -+ maxlen = def_syslog_maxlen - (strlen(fmt) - 5 + strlen(sudo_user_name)); - for (p = msg; *p != '\0'; ) { - len = strlen(p); - if (len > maxlen) { -@@ -120,7 +120,7 @@ do_syslog(int pri, char *msg) - save = *tmp; - *tmp = '\0'; - -- mysyslog(pri, fmt, user_name, p); -+ mysyslog(pri, fmt, sudo_user_name, p); - - *tmp = save; /* restore saved character */ - -@@ -128,11 +128,11 @@ do_syslog(int pri, char *msg) - for (p = tmp; *p == ' '; p++) - continue; - } else { -- mysyslog(pri, fmt, user_name, p); -+ mysyslog(pri, fmt, sudo_user_name, p); - p += len; - } - fmt = _("%8s : (command continued) %s"); -- maxlen = def_syslog_maxlen - (strlen(fmt) - 5 + strlen(user_name)); -+ maxlen = def_syslog_maxlen - (strlen(fmt) - 5 + strlen(sudo_user_name)); - } - - sudoers_setlocale(oldlocale, NULL); -@@ -179,10 +179,10 @@ do_logfile(const char *msg) - timestr = "invalid date"; - if (def_log_host) { - len = asprintf(&full_line, "%s : %s : HOST=%s : %s", -- timestr, user_name, user_srunhost, msg); -+ timestr, sudo_user_name, user_srunhost, msg); - } else { - len = asprintf(&full_line, "%s : %s : %s", -- timestr, user_name, msg); -+ timestr, sudo_user_name, msg); - } - if (len == -1) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -@@ -746,7 +746,7 @@ send_mail(const char *fmt, ...) - - if ((timestr = get_timestr(time(NULL), def_log_year)) == NULL) - timestr = "invalid date"; -- (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host, timestr, user_name); -+ (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host, timestr, sudo_user_name); - va_start(ap, fmt); - (void) vfprintf(mail, fmt, ap); - va_end(ap); -diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h -index cfd5abb..c69a043 100644 ---- a/plugins/sudoers/sudoers.h -+++ b/plugins/sudoers/sudoers.h -@@ -180,6 +180,7 @@ struct sudo_user { - /* - * Shortcuts for sudo_user contents. - */ -+#define sudo_user_name (sudo_user.pw->pw_name) - #define user_name (sudo_user.name) - #define user_uid (sudo_user.uid) - #define user_gid (sudo_user.gid) --- -2.7.4 - diff --git a/sudo-1.9.12-CVE-2023-22809-backports.patch b/sudo-1.9.12-CVE-2023-22809-backports.patch deleted file mode 100644 index 10745ac..0000000 --- a/sudo-1.9.12-CVE-2023-22809-backports.patch +++ /dev/null @@ -1,171 +0,0 @@ -diff -up ./plugins/sudoers/editor.c.other ./plugins/sudoers/editor.c ---- ./plugins/sudoers/editor.c.other 2023-01-16 17:37:04.659967300 +0100 -+++ ./plugins/sudoers/editor.c 2023-01-16 17:40:35.944400376 +0100 -@@ -39,6 +39,82 @@ - #include "sudoers.h" - - /* -+ * Non-destructive word-split that handles single and double quotes and -+ * escaped white space. Quotes are only recognized at the start of a word. -+ * They are treated as normal characters inside a word. -+ */ -+static const char * -+wordsplit(const char *str, const char *endstr, const char **last) -+{ -+ const char *cp; -+ debug_decl(wordsplit, SUDO_DEBUG_UTIL); -+ -+ /* If no str specified, use last ptr (if any). */ -+ if (str == NULL) { -+ str = *last; -+ /* Consume end quote if present. */ -+ if (*str == '"' || *str == '\'') -+ str++; -+ } -+ -+ /* Skip leading white space characters. */ -+ while (str < endstr && (*str == ' ' || *str == '\t')) -+ str++; -+ -+ /* Empty string? */ -+ if (str >= endstr) { -+ *last = endstr; -+ debug_return_ptr(NULL); -+ } -+ -+ /* If word is quoted, skip to end quote and return. */ -+ if (*str == '"' || *str == '\'') { -+ const char *endquote = memchr(str + 1, *str, endstr - str); -+ if (endquote != NULL) { -+ *last = endquote; -+ debug_return_const_ptr(str + 1); -+ } -+ } -+ -+ /* Scan str until we encounter white space. */ -+ for (cp = str; cp < endstr; cp++) { -+ if (*cp == '\\') { -+ /* quoted char, do not interpret */ -+ cp++; -+ continue; -+ } -+ if (*cp == ' ' || *cp == '\t') { -+ /* end of word */ -+ break; -+ } -+ } -+ *last = cp; -+ debug_return_const_ptr(str); -+} -+ -+/* Copy len chars from string, collapsing chars escaped with a backslash. */ -+static char * -+copy_arg(const char *src, size_t len) -+{ -+ const char *src_end = src + len; -+ char *copy, *dst; -+ debug_decl(copy_arg, SUDOERS_DEBUG_UTIL); -+ -+ if ((copy = malloc(len + 1)) != NULL) { -+ for (dst = copy; src < src_end; ) { -+ if (*src == '\\') { -+ src++; -+ continue; -+ } -+ *dst++ = *src++; -+ } -+ *dst = '\0'; -+ } -+ -+ debug_return_ptr(copy); -+} -+ -+/* - * Search for the specified editor in the user's PATH, checking - * the result against allowlist if non-NULL. An argument vector - * suitable for execve() is allocated and stored in argv_out. -@@ -52,7 +128,7 @@ static char * - resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, - int *argc_out, char ***argv_out, char * const *allowlist) - { -- char **nargv, *editor, *editor_path = NULL; -+ char **nargv = NULL, *editor = NULL, *editor_path = NULL; - const char *cp, *ep, *tmp; - const char *edend = ed + edlen; - struct stat user_editor_sb; -@@ -64,14 +140,12 @@ resolve_editor(const char *ed, size_t ed - * The EDITOR and VISUAL environment variables may contain command - * line args so look for those and alloc space for them too. - */ -- cp = sudo_strsplit(ed, edend, " \t", &ep); -+ cp = wordsplit(ed, edend, &ep); - if (cp == NULL) - debug_return_str(NULL); -- editor = strndup(cp, (size_t)(ep - cp)); -- if (editor == NULL) { -- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -- debug_return_str(NULL); -- } -+ editor = copy_arg(cp, ep - cp); -+ if (editor == NULL) -+ goto oom; - - /* If we can't find the editor in the user's PATH, give up. */ - if (find_path(editor, &editor_path, &user_editor_sb, getenv("PATH"), 0, allowlist) != FOUND) { -@@ -81,30 +155,22 @@ resolve_editor(const char *ed, size_t ed - } - - /* Count rest of arguments and allocate editor argv. */ -- for (nargc = 1, tmp = ep; sudo_strsplit(NULL, edend, " \t", &tmp) != NULL; ) -+ for (nargc = 1, tmp = ep; wordsplit(NULL, edend, &tmp) != NULL; ) - nargc++; - if (nfiles != 0) - nargc += nfiles + 1; - nargv = reallocarray(NULL, nargc + 1, sizeof(char *)); -- if (nargv == NULL) { -- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -- free(editor); -- free(editor_path); -- debug_return_str(NULL); -- } -+ if (nargv == NULL) -+ goto oom; - - /* Fill in editor argv (assumes files[] is NULL-terminated). */ - nargv[0] = editor; -- for (nargc = 1; (cp = sudo_strsplit(NULL, edend, " \t", &ep)) != NULL; nargc++) { -- nargv[nargc] = strndup(cp, (size_t)(ep - cp)); -- if (nargv[nargc] == NULL) { -- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -- free(editor_path); -- while (nargc--) -- free(nargv[nargc]); -- free(nargv); -- debug_return_str(NULL); -- } -+ editor = NULL; -+ for (nargc = 1; (cp = wordsplit(NULL, edend, &ep)) != NULL; nargc++) { -+ /* Copy string, collapsing chars escaped with a backslash. */ -+ nargv[nargc] = copy_arg(cp, ep - cp); -+ if (nargv[nargc] == NULL) -+ goto oom; - } - if (nfiles != 0) { - nargv[nargc++] = "--"; -@@ -116,6 +182,16 @@ resolve_editor(const char *ed, size_t ed - *argc_out = nargc; - *argv_out = nargv; - debug_return_str(editor_path); -+oom: -+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -+ free(editor); -+ free(editor_path); -+ if (nargv != NULL) { -+ while (nargc--) -+ free(nargv[nargc]); -+ free(nargv); -+ } -+ debug_return_str(NULL); - } - - /* diff --git a/sudo-1.9.12-CVE-2023-22809-whitelist.patch b/sudo-1.9.12-CVE-2023-22809-whitelist.patch deleted file mode 100644 index fb78325..0000000 --- a/sudo-1.9.12-CVE-2023-22809-whitelist.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff -up ./plugins/sudoers/editor.c.whitelist ./plugins/sudoers/editor.c ---- ./plugins/sudoers/editor.c.whitelist 2023-01-16 17:31:58.108335076 +0100 -+++ ./plugins/sudoers/editor.c 2023-01-16 17:33:37.375547672 +0100 -@@ -40,7 +40,7 @@ - - /* - * Search for the specified editor in the user's PATH, checking -- * the result against whitelist if non-NULL. An argument vector -+ * the result against allowlist if non-NULL. An argument vector - * suitable for execve() is allocated and stored in argv_out. - * If nfiles is non-zero, files[] is added to the end of argv_out. - * -@@ -50,7 +50,7 @@ - */ - static char * - resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, -- int *argc_out, char ***argv_out, char * const *whitelist) -+ int *argc_out, char ***argv_out, char * const *allowlist) - { - char **nargv, *editor, *editor_path = NULL; - const char *cp, *ep, *tmp; -@@ -74,7 +74,7 @@ resolve_editor(const char *ed, size_t ed - } - - /* If we can't find the editor in the user's PATH, give up. */ -- if (find_path(editor, &editor_path, &user_editor_sb, getenv("PATH"), 0, whitelist) != FOUND) { -+ if (find_path(editor, &editor_path, &user_editor_sb, getenv("PATH"), 0, allowlist) != FOUND) { - free(editor); - errno = ENOENT; - debug_return_str(NULL); -@@ -130,7 +130,7 @@ resolve_editor(const char *ed, size_t ed - */ - char * - find_editor(int nfiles, char **files, int *argc_out, char ***argv_out, -- char * const *whitelist, const char **env_editor, bool env_error) -+ char * const *allowlist, const char **env_editor, bool env_error) - { - char *ev[3], *editor_path = NULL; - unsigned int i; -@@ -149,7 +149,7 @@ find_editor(int nfiles, char **files, in - if (editor != NULL && *editor != '\0') { - *env_editor = editor; - editor_path = resolve_editor(editor, strlen(editor), -- nfiles, files, argc_out, argv_out, whitelist); -+ nfiles, files, argc_out, argv_out, allowlist); - if (editor_path != NULL) - break; - if (errno != ENOENT) -@@ -169,7 +169,7 @@ find_editor(int nfiles, char **files, in - for (cp = sudo_strsplit(def_editor, def_editor_end, ":", &ep); - cp != NULL; cp = sudo_strsplit(NULL, def_editor_end, ":", &ep)) { - editor_path = resolve_editor(cp, (size_t)(ep - cp), nfiles, -- files, argc_out, argv_out, whitelist); -+ files, argc_out, argv_out, allowlist); - if (editor_path != NULL) - break; - if (errno != ENOENT) diff --git a/sudo-1.9.12-CVE-2023-22809.patch b/sudo-1.9.12-CVE-2023-22809.patch index 15d5a06..66f866f 100644 --- a/sudo-1.9.12-CVE-2023-22809.patch +++ b/sudo-1.9.12-CVE-2023-22809.patch @@ -1,19 +1,19 @@ diff -up ./plugins/sudoers/editor.c.cve ./plugins/sudoers/editor.c ---- ./plugins/sudoers/editor.c.cve 2023-01-16 17:52:37.074066664 +0100 -+++ ./plugins/sudoers/editor.c 2023-01-16 17:58:06.603774304 +0100 -@@ -132,7 +132,7 @@ resolve_editor(const char *ed, size_t ed - const char *cp, *ep, *tmp; +--- ./plugins/sudoers/editor.c.cve 2021-01-09 21:12:16.000000000 +0100 ++++ ./plugins/sudoers/editor.c 2023-01-17 13:57:05.598949058 +0100 +@@ -126,7 +126,7 @@ resolve_editor(const char *ed, size_t ed + const char *tmp, *cp, *ep = NULL; const char *edend = ed + edlen; struct stat user_editor_sb; - int nargc; + int nargc = 0; - debug_decl(resolve_editor, SUDOERS_DEBUG_UTIL) + debug_decl(resolve_editor, SUDOERS_DEBUG_UTIL); /* -@@ -149,9 +149,7 @@ resolve_editor(const char *ed, size_t ed - +@@ -144,9 +144,7 @@ resolve_editor(const char *ed, size_t ed /* If we can't find the editor in the user's PATH, give up. */ - if (find_path(editor, &editor_path, &user_editor_sb, getenv("PATH"), 0, allowlist) != FOUND) { + if (find_path(editor, &editor_path, &user_editor_sb, getenv("PATH"), NULL, + 0, allowlist) != FOUND) { - free(editor); - errno = ENOENT; - debug_return_str(NULL); @@ -21,7 +21,7 @@ diff -up ./plugins/sudoers/editor.c.cve ./plugins/sudoers/editor.c } /* Count rest of arguments and allocate editor argv. */ -@@ -171,7 +169,19 @@ resolve_editor(const char *ed, size_t ed +@@ -166,6 +164,18 @@ resolve_editor(const char *ed, size_t ed nargv[nargc] = copy_arg(cp, ep - cp); if (nargv[nargc] == NULL) goto oom; @@ -36,12 +36,11 @@ diff -up ./plugins/sudoers/editor.c.cve ./plugins/sudoers/editor.c + errno = EINVAL; + goto bad; + } - } + + } if (nfiles != 0) { nargv[nargc++] = "--"; - while (nfiles--) -@@ -184,6 +194,7 @@ resolve_editor(const char *ed, size_t ed +@@ -179,6 +189,7 @@ resolve_editor(const char *ed, size_t ed debug_return_str(editor_path); oom: sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); @@ -50,16 +49,17 @@ diff -up ./plugins/sudoers/editor.c.cve ./plugins/sudoers/editor.c free(editor_path); if (nargv != NULL) { diff -up ./plugins/sudoers/sudoers.c.cve ./plugins/sudoers/sudoers.c ---- ./plugins/sudoers/sudoers.c.cve 2023-01-16 17:52:37.074066664 +0100 -+++ ./plugins/sudoers/sudoers.c 2023-01-16 18:02:43.928307505 +0100 -@@ -634,21 +634,32 @@ sudoers_policy_main(int argc, char * con +--- ./plugins/sudoers/sudoers.c.cve 2023-01-17 13:50:33.718255775 +0100 ++++ ./plugins/sudoers/sudoers.c 2023-01-17 14:00:53.049710094 +0100 +@@ -724,21 +724,34 @@ sudoers_policy_main(int argc, char * con /* Note: must call audit before uid change. */ if (ISSET(sudo_mode, MODE_EDIT)) { -- int edit_argc; ++ const char *env_editor = NULL; + char **edit_argv; + int edit_argc; - const char *env_editor; -+ const char *env_editor = NULL; -+ int edit_argc; ++ free(safe_cmnd); safe_cmnd = find_editor(NewArgc - 1, NewArgv + 1, &edit_argc, @@ -67,47 +67,46 @@ diff -up ./plugins/sudoers/sudoers.c.cve ./plugins/sudoers/sudoers.c if (safe_cmnd == NULL) { - if (errno != ENOENT) - goto done; -- audit_failure(NewArgc, NewArgv, N_("%s: command not found"), +- audit_failure(NewArgv, N_("%s: command not found"), - env_editor ? env_editor : def_editor); - sudo_warnx(U_("%s: command not found"), - env_editor ? env_editor : def_editor); - goto bad; -- } -+ switch (errno) { -+ case ENOENT: -+ audit_failure(NewArgc, NewArgv, N_("%s: command not found"), -+ env_editor ? env_editor : def_editor); -+ sudo_warnx(U_("%s: command not found"), -+ env_editor ? env_editor : def_editor); -+ goto bad; -+ case EINVAL: -+ if (def_env_editor && env_editor != NULL) { -+ /* User tried to do something funny with the editor. */ -+ log_warningx(SLOG_NO_STDERR|SLOG_SEND_MAIL, -+ "invalid user-specified editor: %s", env_editor); -+ goto bad; -+ } -+ default: -+ goto done; -+ } -+ } + - if (audit_success(edit_argc, edit_argv) != 0 && !def_ignore_audit_errors) - goto done; - ++ switch (errno) { ++ case ENOENT: ++ audit_failure(NewArgv, N_("%s: command not found"), ++ env_editor ? env_editor : def_editor); ++ sudo_warnx(U_("%s: command not found"), ++ env_editor ? env_editor : def_editor); ++ goto bad; ++ case EINVAL: ++ if (def_env_editor && env_editor != NULL) { ++ /* User tried to do something funny with the editor. */ ++ log_warningx(SLOG_NO_STDERR|SLOG_AUDIT|SLOG_SEND_MAIL, ++ "invalid user-specified editor: %s", env_editor); ++ goto bad; ++ } ++ FALLTHROUGH; ++ default: ++ goto done; ++ } + } + sudoers_gc_add(GC_VECTOR, edit_argv); + NewArgv = edit_argv; diff -up ./plugins/sudoers/visudo.c.cve ./plugins/sudoers/visudo.c ---- ./plugins/sudoers/visudo.c.cve 2019-10-28 13:28:54.000000000 +0100 -+++ ./plugins/sudoers/visudo.c 2023-01-16 18:03:48.713975354 +0100 -@@ -308,7 +308,7 @@ static char * +--- ./plugins/sudoers/visudo.c.cve 2021-01-09 21:12:16.000000000 +0100 ++++ ./plugins/sudoers/visudo.c 2023-01-17 14:02:01.393135129 +0100 +@@ -303,7 +303,7 @@ static char * get_editor(int *editor_argc, char ***editor_argv) { - char *editor_path = NULL, **whitelist = NULL; + char *editor_path = NULL, **allowlist = NULL; - const char *env_editor; + const char *env_editor = NULL; static char *files[] = { "+1", "sudoers" }; - unsigned int whitelist_len = 0; - debug_decl(get_editor, SUDOERS_DEBUG_UTIL) -@@ -342,7 +342,11 @@ get_editor(int *editor_argc, char ***edi + unsigned int allowlist_len = 0; + debug_decl(get_editor, SUDOERS_DEBUG_UTIL); +@@ -337,7 +337,11 @@ get_editor(int *editor_argc, char ***edi if (editor_path == NULL) { if (def_env_editor && env_editor != NULL) { /* We are honoring $EDITOR so this is a fatal error. */ 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-1.9.5-CVE-2021-23239.patch b/sudo-1.9.5-CVE-2021-23239.patch deleted file mode 100644 index 2ff50fd..0000000 --- a/sudo-1.9.5-CVE-2021-23239.patch +++ /dev/null @@ -1,61 +0,0 @@ -From db1f27c0350e9e437c93780ffe88648ae1984467 Mon Sep 17 00:00:00 2001 -From: "Todd C. Miller" -Date: Wed, 6 Jan 2021 10:16:00 -0700 -Subject: [PATCH] Fix potential directory existing info leak in sudoedit. When - creating a new file, sudoedit checks to make sure the parent directory exists - so it can provide the user with a sensible error message. However, this - could be used to test for the existence of directories not normally - accessible to the user by pointing to them with a symbolic link when the - parent directory is controlled by the user. Problem reported by Matthias - Gerstner of SUSE. - ---- - src/sudo_edit.c | 29 ++++++++++++++++++++++++----- - 1 file changed, 24 insertions(+), 5 deletions(-) - -diff --git a/src/sudo_edit.c b/src/sudo_edit.c -index 82e04a71b..5502b7bd9 100644 ---- a/src/sudo_edit.c -+++ b/src/sudo_edit.c -@@ -541,14 +541,33 @@ sudo_edit_create_tfiles(struct command_details *command_details, - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details); - if (ofd != -1 || errno == ENOENT) { - if (ofd == -1) { -- /* New file, verify parent dir exists unless in cwd. */ -+ /* -+ * New file, verify parent dir exists unless in cwd. -+ * This fails early so the user knows ahead of time if the -+ * edit won't succeed. Additional checks are performed -+ * when copying the temporary file back to the origin. -+ */ - char *slash = strrchr(files[i], '/'); - if (slash != NULL && slash != files[i]) { -- int serrno = errno; -+ const int sflags = command_details->flags; -+ const int serrno = errno; -+ int dfd; -+ -+ /* -+ * The parent directory is allowed to be a symbolic -+ * link as long as *its* parent is not writable. -+ */ - *slash = '\0'; -- if (stat(files[i], &sb) == 0 && S_ISDIR(sb.st_mode)) { -- memset(&sb, 0, sizeof(sb)); -- rc = 0; -+ SET(command_details->flags, CD_SUDOEDIT_FOLLOW); -+ dfd = sudo_edit_open(files[i], DIR_OPEN_FLAGS, -+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details); -+ command_details->flags = sflags; -+ if (dfd != -1) { -+ if (fstat(dfd, &sb) == 0 && S_ISDIR(sb.st_mode)) { -+ memset(&sb, 0, sizeof(sb)); -+ rc = 0; -+ } -+ close(dfd); - } - *slash = '/'; - errno = serrno; --- -2.26.2 - diff --git a/sudo-1.9.5-CVE-2021-23240-1.patch b/sudo-1.9.5-CVE-2021-23240-1.patch deleted file mode 100644 index 02efa86..0000000 --- a/sudo-1.9.5-CVE-2021-23240-1.patch +++ /dev/null @@ -1,158 +0,0 @@ -From adb4360c40df99238c17c3ecedcb1d32d76e2b2e Mon Sep 17 00:00:00 2001 -From: "Todd C. Miller" -Date: Fri, 17 Apr 2020 19:08:56 -0600 -Subject: [PATCH] Extend the original file before to the new size before - updating it. Instead of opening the original file for writing w/ tuncation, - we first extend the file with zeroes (by writing, not seeking), then - overwrite it. This should allow sudo to fail early if the disk is out of - space before it overwrites the original file. - ---- - src/sudo_edit.c | 93 ++++++++++++++++++++++++++++++++++++++++--------- - 1 file changed, 77 insertions(+), 16 deletions(-) - -diff --git a/src/sudo_edit.c b/src/sudo_edit.c -index 28f6c6100..d99a5658a 100644 ---- a/src/sudo_edit.c -+++ b/src/sudo_edit.c -@@ -1,7 +1,7 @@ - /* - * SPDX-License-Identifier: ISC - * -- * Copyright (c) 2004-2008, 2010-2018 Todd C. Miller -+ * Copyright (c) 2004-2008, 2010-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 -@@ -650,6 +650,51 @@ sudo_edit_create_tfiles(struct command_details *command_details, - debug_return_int(j); - } - -+/* -+ * Extend the given fd to the specified size in bytes. -+ * We do this to allocate disk space up-front before overwriting -+ * the original file with the temporary. Otherwise, we could -+ * we run out of disk space after truncating the original file. -+ */ -+static int -+sudo_edit_extend_file(int fd, off_t new_size) -+{ -+ off_t old_size, size; -+ ssize_t nwritten; -+ char zeroes[1024] = { '\0' }; -+ debug_decl(sudo_edit_extend_file, SUDO_DEBUG_EDIT); -+ -+ if ((old_size = lseek(fd, 0, SEEK_END)) == -1) { -+ sudo_warn("lseek"); -+ debug_return_int(-1); -+ } -+ sudo_debug_printf(SUDO_DEBUG_INFO, "%s: extending file from %lld to %lld", -+ __func__, (long long)old_size, (long long)new_size); -+ -+ for (size = old_size; size < new_size; size += nwritten) { -+ size_t len = new_size - size; -+ if (len > sizeof(zeroes)) -+ len = sizeof(zeroes); -+ nwritten = write(fd, zeroes, len); -+ if (nwritten == -1) { -+ int serrno = errno; -+ if (ftruncate(fd, old_size) == -1) { -+ sudo_debug_printf( -+ SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, -+ "unable to truncate to %lld", (long long)old_size); -+ } -+ errno = serrno; -+ debug_return_int(-1); -+ } -+ } -+ if (lseek(fd, 0, SEEK_SET) == -1) { -+ sudo_warn("lseek"); -+ debug_return_int(-1); -+ } -+ -+ debug_return_int(0); -+} -+ - /* - * Copy the temporary files specified in tf to the originals. - * Returns the number of copy errors or 0 if completely successful. -@@ -708,38 +753,53 @@ sudo_edit_copy_tfiles(struct command_details *command_details, - switch_user(command_details->euid, command_details->egid, - command_details->ngroups, command_details->groups); - oldmask = umask(command_details->umask); -- ofd = sudo_edit_open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, -+ ofd = sudo_edit_open(tf[i].ofile, O_WRONLY|O_CREAT, - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details); - umask(oldmask); - switch_user(ROOT_UID, user_details.egid, - user_details.ngroups, user_details.groups); -- if (ofd == -1) { -- sudo_warn(U_("unable to write to %s"), tf[i].ofile); -- sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile); -- close(tfd); -- errors++; -- continue; -+ if (ofd == -1) -+ goto write_error; -+ /* Extend the file to the new size if larger before copying. */ -+ if (tf[i].osize > 0 && sb.st_size > tf[i].osize) { -+ if (sudo_edit_extend_file(ofd, sb.st_size) == -1) -+ goto write_error; - } -+ /* Overwrite the old file with the new contents. */ - while ((nread = read(tfd, buf, sizeof(buf))) > 0) { -- if ((nwritten = write(ofd, buf, nread)) != nread) { -+ ssize_t off = 0; -+ do { -+ nwritten = write(ofd, buf + off, nread - off); - if (nwritten == -1) -- sudo_warn("%s", tf[i].ofile); -- else -- sudo_warnx(U_("%s: short write"), tf[i].ofile); -- break; -- } -+ goto write_error; -+ off += nwritten; -+ } while (nread > off); - } - if (nread == 0) { -- /* success, got EOF */ -+ /* success, read to EOF */ -+ if (tf[i].osize > 0 && sb.st_size < tf[i].osize) { -+ /* We don't open with O_TRUNC so must truncate manually. */ -+ if (ftruncate(ofd, sb.st_size) == -1) { -+ sudo_debug_printf( -+ SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, -+ "unable to truncate %s to %lld", tf[i].ofile, -+ (long long)sb.st_size); -+ goto write_error; -+ } -+ } - unlink(tf[i].tfile); - } else if (nread < 0) { - sudo_warn(U_("unable to read temporary file")); - sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile); -+ errors++; - } else { -+write_error: - sudo_warn(U_("unable to write to %s"), tf[i].ofile); - sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile); -+ errors++; - } -- close(ofd); -+ if (ofd != -1) -+ close(ofd); - close(tfd); - } - debug_return_int(errors); -@@ -1065,6 +1125,7 @@ cleanup: - for (i = 0; i < nfiles; i++) { - if (tf[i].tfile != NULL) - unlink(tf[i].tfile); -+ free(tf[i].tfile); - } - } - free(tf); --- -2.26.2 - diff --git a/sudo-1.9.5-CVE-2021-23240-2.patch b/sudo-1.9.5-CVE-2021-23240-2.patch deleted file mode 100644 index 1b40774..0000000 --- a/sudo-1.9.5-CVE-2021-23240-2.patch +++ /dev/null @@ -1,431 +0,0 @@ -diff -up ./src/copy_file.c.symbolic-link-attack-2 ./src/copy_file.c ---- ./src/copy_file.c.symbolic-link-attack-2 2021-02-02 15:31:20.555340446 +0100 -+++ ./src/copy_file.c 2021-02-02 15:31:20.555340446 +0100 -@@ -0,0 +1,128 @@ -+/* -+ * 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. -+ */ -+ -+/* -+ * 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 "sudo.h" -+ -+/* -+ * Extend the given fd to the specified size in bytes. -+ * We do this to allocate disk space up-front before overwriting -+ * the original file with the temporary. Otherwise, we could -+ * we run out of disk space after truncating the original file. -+ */ -+static int -+sudo_extend_file(int fd, const char *name, off_t new_size) -+{ -+ off_t old_size, size; -+ ssize_t nwritten; -+ char zeroes[BUFSIZ] = { '\0' }; -+ debug_decl(sudo_extend_file, SUDO_DEBUG_UTIL); -+ -+ if ((old_size = lseek(fd, 0, SEEK_END)) == -1) { -+ sudo_warn("lseek"); -+ debug_return_int(-1); -+ } -+ sudo_debug_printf(SUDO_DEBUG_INFO, "%s: extending %s from %lld to %lld", -+ __func__, name, (long long)old_size, (long long)new_size); -+ -+ for (size = old_size; size < new_size; size += nwritten) { -+ size_t len = new_size - size; -+ if (len > sizeof(zeroes)) -+ len = sizeof(zeroes); -+ nwritten = write(fd, zeroes, len); -+ if (nwritten == -1) { -+ int serrno = errno; -+ if (ftruncate(fd, old_size) == -1) { -+ sudo_debug_printf( -+ SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, -+ "unable to truncate %s to %lld", name, (long long)old_size); -+ } -+ errno = serrno; -+ debug_return_int(-1); -+ } -+ } -+ if (lseek(fd, 0, SEEK_SET) == -1) { -+ sudo_warn("lseek"); -+ debug_return_int(-1); -+ } -+ -+ debug_return_int(0); -+} -+ -+/* -+ * Copy the contents of src_fd into dst_fd. -+ * Returns 0 on success or -1 on error. -+ */ -+int -+sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst, -+ int dst_fd, off_t dst_len) -+{ -+ char buf[BUFSIZ]; -+ ssize_t nwritten, nread; -+ debug_decl(sudo_copy_file, SUDO_DEBUG_UTIL); -+ -+ /* Extend the file to the new size if larger before copying. */ -+ if (dst_len > 0 && src_len > dst_len) { -+ if (sudo_extend_file(dst_fd, dst, src_len) == -1) -+ goto write_error; -+ } -+ -+ /* Overwrite the old file with the new contents. */ -+ while ((nread = read(src_fd, buf, sizeof(buf))) > 0) { -+ ssize_t off = 0; -+ do { -+ nwritten = write(dst_fd, buf + off, nread - off); -+ if (nwritten == -1) -+ goto write_error; -+ off += nwritten; -+ } while (nread > off); -+ } -+ if (nread == 0) { -+ /* success, read to EOF */ -+ if (src_len < dst_len) { -+ /* We don't open with O_TRUNC so must truncate manually. */ -+ if (ftruncate(dst_fd, src_len) == -1) { -+ sudo_debug_printf( -+ SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, -+ "unable to truncate %s to %lld", dst, (long long)src_len); -+ goto write_error; -+ } -+ } -+ debug_return_int(0); -+ } else if (nread < 0) { -+ sudo_warn(U_("unable to read from %s"), src); -+ debug_return_int(-1); -+ } else { -+write_error: -+ sudo_warn(U_("unable to write to %s"), dst); -+ debug_return_int(-1); -+ } -+} -diff -up ./src/Makefile.in.symbolic-link-attack-2 ./src/Makefile.in ---- ./src/Makefile.in.symbolic-link-attack-2 2019-10-28 13:28:54.000000000 +0100 -+++ ./src/Makefile.in 2021-02-02 15:31:20.555340446 +0100 -@@ -120,16 +120,17 @@ SHELL = @SHELL@ - - PROGS = @PROGS@ - --OBJS = conversation.o env_hooks.o exec.o exec_common.o exec_monitor.o \ -- exec_nopty.o exec_pty.o get_pty.o hooks.o limits.o load_plugins.o \ -- net_ifs.o parse_args.o preserve_fds.o signal.o sudo.o sudo_edit.o \ -- tcsetpgrp_nobg.o tgetpass.o ttyname.o utmp.o @SUDO_OBJS@ -+OBJS = conversation.o copy_file.o env_hooks.o exec.o exec_common.o \ -+ exec_monitor.o exec_nopty.o exec_pty.o get_pty.o hooks.o \ -+ limits.o load_plugins.o net_ifs.o parse_args.o preserve_fds.o \ -+ signal.o sudo.o sudo_edit.o tcsetpgrp_nobg.o tgetpass.o \ -+ ttyname.o utmp.o @SUDO_OBJS@ - - IOBJS = $(OBJS:.o=.i) sesh.i - - POBJS = $(IOBJS:.i=.plog) - --SESH_OBJS = sesh.o exec_common.o -+SESH_OBJS = copy_file.o exec_common.o sesh.o - - CHECK_NOEXEC_OBJS = check_noexec.o exec_common.o - -@@ -335,6 +336,22 @@ conversation.i: $(srcdir)/conversation.c - $(CC) -E -o $@ $(CPPFLAGS) $< - conversation.plog: conversation.i - rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/conversation.c --i-file $< --output-file $@ -+copy_file.o: $(srcdir)/copy_file.c $(incdir)/compat/stdbool.h \ -+ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ -+ $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \ -+ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ -+ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/sudo.h \ -+ $(top_builddir)/config.h $(top_builddir)/pathnames.h -+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/copy_file.c -+copy_file.i: $(srcdir)/copy_file.c $(incdir)/compat/stdbool.h \ -+ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ -+ $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \ -+ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ -+ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/sudo.h \ -+ $(top_builddir)/config.h $(top_builddir)/pathnames.h -+ $(CC) -E -o $@ $(CPPFLAGS) $< -+copy_file.plog: copy_file.i -+ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/copy_file.c --i-file $< --output-file $@ - env_hooks.o: $(srcdir)/env_hooks.c $(incdir)/compat/stdbool.h \ - $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ - $(incdir)/sudo_debug.h $(incdir)/sudo_dso.h \ -diff -up ./src/sesh.c.symbolic-link-attack-2 ./src/sesh.c ---- ./src/sesh.c.symbolic-link-attack-2 2019-10-28 13:28:52.000000000 +0100 -+++ ./src/sesh.c 2021-02-02 15:31:20.555340446 +0100 -@@ -1,7 +1,7 @@ - /* - * SPDX-License-Identifier: ISC - * -- * Copyright (c) 2008, 2010-2018 Todd C. Miller -+ * Copyright (c) 2008, 2010-2018, 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 -@@ -182,7 +182,7 @@ sesh_sudoedit(int argc, char *argv[]) - * so that it's ensured that the temporary files are - * created by us and that we are not opening any symlinks. - */ -- oflags_dst = O_WRONLY|O_TRUNC|O_CREAT|(post ? follow : O_EXCL); -+ oflags_dst = O_WRONLY|O_CREAT|(post ? follow : O_EXCL); - for (i = 0; i < argc - 1; i += 2) { - const char *path_src = argv[i]; - const char *path_dst = argv[i + 1]; -@@ -214,14 +214,29 @@ sesh_sudoedit(int argc, char *argv[]) - } - - if (fd_src != -1) { -- while ((nread = read(fd_src, buf, sizeof(buf))) > 0) { -- if ((nwritten = write(fd_dst, buf, nread)) != nread) { -- sudo_warn("%s", path_src); -- if (post) { -- ret = SESH_ERR_SOME_FILES; -- goto nocleanup; -- } else -- goto cleanup_0; -+ off_t len_src = -1; -+ off_t len_dst = -1; -+ -+ if (post) { -+ if (fstat(fd_src, &sb) != 0) { -+ ret = SESH_ERR_SOME_FILES; -+ goto nocleanup; -+ } -+ len_src = sb.st_size; -+ if (fstat(fd_dst, &sb) != 0) { -+ ret = SESH_ERR_SOME_FILES; -+ goto nocleanup; -+ } -+ len_dst = sb.st_size; -+ } -+ -+ if (sudo_copy_file(path_src, fd_src, len_src, path_dst, fd_dst, -+ len_dst) == -1) { -+ if (post) { -+ ret = SESH_ERR_SOME_FILES; -+ goto nocleanup; -+ } else { -+ goto cleanup_0; - } - } - } -diff -up ./src/sudo_edit.c.symbolic-link-attack-2 ./src/sudo_edit.c ---- ./src/sudo_edit.c.symbolic-link-attack-2 2021-02-02 15:31:20.554340459 +0100 -+++ ./src/sudo_edit.c 2021-02-02 15:31:54.355884326 +0100 -@@ -42,7 +42,6 @@ - #include - #include - #include --#include - #include - - #include "sudo.h" -@@ -551,8 +550,6 @@ sudo_edit_create_tfiles(struct command_d - struct tempfile *tf, char *files[], int nfiles) - { - int i, j, tfd, ofd, rc; -- char buf[BUFSIZ]; -- ssize_t nwritten, nread; - struct timespec times[2]; - struct stat sb; - debug_decl(sudo_edit_create_tfiles, SUDO_DEBUG_EDIT) -@@ -648,18 +645,7 @@ sudo_edit_create_tfiles(struct command_d - debug_return_int(-1); - } - if (ofd != -1) { -- while ((nread = read(ofd, buf, sizeof(buf))) > 0) { -- if ((nwritten = write(tfd, buf, nread)) != nread) { -- if (nwritten == -1) -- sudo_warn("%s", tf[j].tfile); -- else -- sudo_warnx(U_("%s: short write"), tf[j].tfile); -- break; -- } -- } -- if (nread != 0) { -- if (nread < 0) -- sudo_warn("%s", files[i]); -+ if (sudo_copy_file(tf[j].ofile, ofd, tf[j].osize, tf[j].tfile, tfd, -1) == -1) { - close(ofd); - close(tfd); - debug_return_int(-1); -@@ -689,51 +675,6 @@ sudo_edit_create_tfiles(struct command_d - } - - /* -- * Extend the given fd to the specified size in bytes. -- * We do this to allocate disk space up-front before overwriting -- * the original file with the temporary. Otherwise, we could -- * we run out of disk space after truncating the original file. -- */ --static int --sudo_edit_extend_file(int fd, off_t new_size) --{ -- off_t old_size, size; -- ssize_t nwritten; -- char zeroes[1024] = { '\0' }; -- debug_decl(sudo_edit_extend_file, SUDO_DEBUG_EDIT); -- -- if ((old_size = lseek(fd, 0, SEEK_END)) == -1) { -- sudo_warn("lseek"); -- debug_return_int(-1); -- } -- sudo_debug_printf(SUDO_DEBUG_INFO, "%s: extending file from %lld to %lld", -- __func__, (long long)old_size, (long long)new_size); -- -- for (size = old_size; size < new_size; size += nwritten) { -- size_t len = new_size - size; -- if (len > sizeof(zeroes)) -- len = sizeof(zeroes); -- nwritten = write(fd, zeroes, len); -- if (nwritten == -1) { -- int serrno = errno; -- if (ftruncate(fd, old_size) == -1) { -- sudo_debug_printf( -- SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, -- "unable to truncate to %lld", (long long)old_size); -- } -- errno = serrno; -- debug_return_int(-1); -- } -- } -- if (lseek(fd, 0, SEEK_SET) == -1) { -- sudo_warn("lseek"); -- debug_return_int(-1); -- } -- -- debug_return_int(0); --} -- --/* - * Copy the temporary files specified in tf to the originals. - * Returns the number of copy errors or 0 if completely successful. - */ -@@ -741,9 +682,7 @@ static int - sudo_edit_copy_tfiles(struct command_details *command_details, - struct tempfile *tf, int nfiles, struct timespec *times) - { -- int i, tfd, ofd, rc, errors = 0; -- char buf[BUFSIZ]; -- ssize_t nwritten, nread; -+ int i, tfd, ofd, errors = 0; - struct timespec ts; - struct stat sb; - mode_t oldmask; -@@ -751,7 +690,7 @@ sudo_edit_copy_tfiles(struct command_det - - /* Copy contents of temp files to real ones. */ - for (i = 0; i < nfiles; i++) { -- rc = -1; -+ int rc = -1; - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "seteuid(%u)", (unsigned int)user_details.uid); - if (seteuid(user_details.uid) != 0) -@@ -764,8 +703,8 @@ sudo_edit_copy_tfiles(struct command_det - "seteuid(%u)", ROOT_UID); - if (seteuid(ROOT_UID) != 0) - sudo_fatal("seteuid(ROOT_UID)"); -- if (rc || !S_ISREG(sb.st_mode)) { -- if (rc) -+ if (rc == -1 || !S_ISREG(sb.st_mode)) { -+ if (rc == -1) - sudo_warn("%s", tf[i].tfile); - else - sudo_warnx(U_("%s: not a regular file"), tf[i].tfile); -@@ -796,46 +735,19 @@ sudo_edit_copy_tfiles(struct command_det - umask(oldmask); - switch_user(ROOT_UID, user_details.egid, - user_details.ngroups, user_details.groups); -- if (ofd == -1) -- goto write_error; -- /* Extend the file to the new size if larger before copying. */ -- if (tf[i].osize > 0 && sb.st_size > tf[i].osize) { -- if (sudo_edit_extend_file(ofd, sb.st_size) == -1) -- goto write_error; -+ if (ofd == -1) { -+ sudo_warn(U_("unable to write to %s"), tf[i].ofile); -+ goto bad; - } -+ - /* Overwrite the old file with the new contents. */ -- while ((nread = read(tfd, buf, sizeof(buf))) > 0) { -- ssize_t off = 0; -- do { -- nwritten = write(ofd, buf + off, nread - off); -- if (nwritten == -1) -- goto write_error; -- off += nwritten; -- } while (nread > off); -- } -- if (nread == 0) { -- /* success, read to EOF */ -- if (tf[i].osize > 0 && sb.st_size < tf[i].osize) { -- /* We don't open with O_TRUNC so must truncate manually. */ -- if (ftruncate(ofd, sb.st_size) == -1) { -- sudo_debug_printf( -- SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, -- "unable to truncate %s to %lld", tf[i].ofile, -- (long long)sb.st_size); -- goto write_error; -- } -- } -- unlink(tf[i].tfile); -- } else if (nread < 0) { -- sudo_warn(U_("unable to read temporary file")); -- sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile); -- errors++; -- } else { --write_error: -- sudo_warn(U_("unable to write to %s"), tf[i].ofile); -+ if (sudo_copy_file(tf[i].tfile, tfd, sb.st_size, tf[i].ofile, ofd, -+ tf[i].osize) == -1) { -+bad: - sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile); - errors++; - } -+ - if (ofd != -1) - close(ofd); - close(tfd); -diff -up ./src/sudo_exec.h.symbolic-link-attack-2 ./src/sudo_exec.h ---- ./src/sudo_exec.h.symbolic-link-attack-2 2019-10-28 13:27:39.000000000 +0100 -+++ ./src/sudo_exec.h 2021-02-02 15:31:20.556340432 +0100 -@@ -84,6 +84,9 @@ - struct command_details; - struct command_status; - -+/* copy_file.c */ -+int sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst, int dst_fd, off_t dst_len); -+ - /* exec.c */ - void exec_cmnd(struct command_details *details, int errfd); - void terminate_command(pid_t pid, bool use_pgrp); diff --git a/sudo-1.9.5-CVE-2021-23240-3.patch b/sudo-1.9.5-CVE-2021-23240-3.patch deleted file mode 100644 index 8e4ae34..0000000 --- a/sudo-1.9.5-CVE-2021-23240-3.patch +++ /dev/null @@ -1,345 +0,0 @@ -diff -up ./src/exec_monitor.c.symbolic-link-attack-3 ./src/exec_monitor.c ---- ./src/exec_monitor.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100 -+++ ./src/exec_monitor.c 2021-02-02 17:11:32.382020407 +0100 -@@ -613,7 +613,7 @@ exec_monitor(struct command_details *det - #ifdef HAVE_SELINUX - if (ISSET(details->flags, CD_RBAC_ENABLED)) { - if (selinux_setup(details->selinux_role, details->selinux_type, -- details->tty, io_fds[SFD_SLAVE]) == -1) -+ details->tty, io_fds[SFD_SLAVE], true) == -1) - goto bad; - } - #endif -diff -up ./src/exec_nopty.c.symbolic-link-attack-3 ./src/exec_nopty.c ---- ./src/exec_nopty.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100 -+++ ./src/exec_nopty.c 2021-02-02 17:11:32.382020407 +0100 -@@ -381,7 +381,7 @@ exec_nopty(struct command_details *detai - #ifdef HAVE_SELINUX - if (ISSET(details->flags, CD_RBAC_ENABLED)) { - if (selinux_setup(details->selinux_role, details->selinux_type, -- details->tty, -1) == -1) { -+ details->tty, -1, true) == -1) { - cstat->type = CMD_ERRNO; - cstat->val = errno; - debug_return; -diff -up ./src/selinux.c.symbolic-link-attack-3 ./src/selinux.c ---- ./src/selinux.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100 -+++ ./src/selinux.c 2021-02-02 17:11:32.382020407 +0100 -@@ -363,7 +363,7 @@ bad: - */ - int - selinux_setup(const char *role, const char *type, const char *ttyn, -- int ptyfd) -+ int ptyfd, bool label_tty) - { - int ret = -1; - debug_decl(selinux_setup, SUDO_DEBUG_SELINUX) -@@ -392,7 +392,7 @@ selinux_setup(const char *role, const ch - sudo_debug_printf(SUDO_DEBUG_INFO, "%s: new context %s", __func__, - se_state.new_context); - -- if (relabel_tty(ttyn, ptyfd) == -1) { -+ if (label_tty && relabel_tty(ttyn, ptyfd) == -1) { - sudo_warn(U_("unable to set tty context to %s"), se_state.new_context); - goto done; - } -@@ -408,6 +408,28 @@ done: - debug_return_int(ret); - } - -+int -+selinux_setcon(void) -+{ -+ debug_decl(selinux_setcon, SUDO_DEBUG_SELINUX); -+ -+ if (setexeccon(se_state.new_context)) { -+ sudo_warn(U_("unable to set exec context to %s"), se_state.new_context); -+ if (se_state.enforcing) -+ debug_return_int(-1); -+ } -+ -+#ifdef HAVE_SETKEYCREATECON -+ if (setkeycreatecon(se_state.new_context)) { -+ sudo_warn(U_("unable to set key creation context to %s"), se_state.new_context); -+ if (se_state.enforcing) -+ debug_return_int(-1); -+ } -+#endif /* HAVE_SETKEYCREATECON */ -+ -+ debug_return_int(0); -+} -+ - void - selinux_execve(int fd, const char *path, char *const argv[], char *envp[], - bool noexec) -@@ -424,19 +446,9 @@ selinux_execve(int fd, const char *path, - debug_return; - } - -- if (setexeccon(se_state.new_context)) { -- sudo_warn(U_("unable to set exec context to %s"), se_state.new_context); -- if (se_state.enforcing) -- debug_return; -- } -- --#ifdef HAVE_SETKEYCREATECON -- if (setkeycreatecon(se_state.new_context)) { -- sudo_warn(U_("unable to set key creation context to %s"), se_state.new_context); -- if (se_state.enforcing) -- debug_return; -- } --#endif /* HAVE_SETKEYCREATECON */ -+ /* Set SELinux exec and keycreate contexts. */ -+ if (selinux_setcon() == -1) -+ debug_return; - - /* - * Build new argv with sesh as argv[0]. -diff -up ./src/sudo.c.symbolic-link-attack-3 ./src/sudo.c ---- ./src/sudo.c.symbolic-link-attack-3 2021-02-02 17:12:32.773182386 +0100 -+++ ./src/sudo.c 2021-02-02 17:12:48.510964009 +0100 -@@ -971,10 +971,6 @@ run_command(struct command_details *deta - case CMD_WSTATUS: - /* Command ran, exited or was killed. */ - status = cstat.val; --#ifdef HAVE_SELINUX -- if (ISSET(details->flags, CD_SUDOEDIT_COPY)) -- break; --#endif - sudo_debug_printf(SUDO_DEBUG_DEBUG, - "calling policy close with wait status %d", status); - policy_close(&policy_plugin, status, 0); -diff -up ./src/sudo_edit.c.symbolic-link-attack-3 ./src/sudo_edit.c ---- ./src/sudo_edit.c.symbolic-link-attack-3 2021-02-02 17:11:32.380020435 +0100 -+++ ./src/sudo_edit.c 2021-02-02 17:11:32.382020407 +0100 -@@ -757,28 +757,54 @@ bad: - - #ifdef HAVE_SELINUX - static int -+selinux_run_helper(char *argv[], char *envp[]) -+{ -+ int status, ret = SESH_ERR_FAILURE; -+ const char *sesh; -+ pid_t child, pid; -+ debug_decl(selinux_run_helper, SUDO_DEBUG_EDIT); -+ -+ sesh = sudo_conf_sesh_path(); -+ if (sesh == NULL) { -+ sudo_warnx("internal error: sesh path not set"); -+ debug_return_int(-1); -+ } -+ -+ child = sudo_debug_fork(); -+ switch (child) { -+ case -1: -+ sudo_warn(U_("unable to fork")); -+ break; -+ case 0: -+ /* child runs sesh in new context */ -+ if (selinux_setcon() == 0) -+ execve(sesh, argv, envp); -+ _exit(SESH_ERR_FAILURE); -+ default: -+ /* parent waits */ -+ do { -+ pid = waitpid(child, &status, 0); -+ } while (pid == -1 && errno == EINTR); -+ -+ ret = WIFSIGNALED(status) ? SESH_ERR_KILLED : WEXITSTATUS(status); -+ } -+ -+ debug_return_int(ret); -+} -+ -+static int - selinux_edit_create_tfiles(struct command_details *command_details, - struct tempfile *tf, char *files[], int nfiles) - { - char **sesh_args, **sesh_ap; - int i, rc, sesh_nargs; - struct stat sb; -- struct command_details saved_command_details; - debug_decl(selinux_edit_create_tfiles, SUDO_DEBUG_EDIT) -- -- /* Prepare selinux stuff (setexeccon) */ -- if (selinux_setup(command_details->selinux_role, -- command_details->selinux_type, NULL, -1) != 0) -- debug_return_int(-1); - - if (nfiles < 1) - debug_return_int(0); - - /* Construct common args for sesh */ -- memcpy(&saved_command_details, command_details, sizeof(struct command_details)); -- command_details->command = _PATH_SUDO_SESH; -- command_details->flags |= CD_SUDOEDIT_COPY; -- - sesh_nargs = 4 + (nfiles * 2) + 1; - sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *)); - if (sesh_args == NULL) { -@@ -791,6 +817,7 @@ selinux_edit_create_tfiles(struct comman - *sesh_ap++ = "-h"; - *sesh_ap++ = "0"; - -+ /* XXX - temp files should be created with user's context */ - for (i = 0; i < nfiles; i++) { - char *tfile, *ofile = files[i]; - int tfd; -@@ -820,8 +847,7 @@ selinux_edit_create_tfiles(struct comman - *sesh_ap = NULL; - - /* Run sesh -e [-h] 0 ... */ -- command_details->argv = sesh_args; -- rc = run_command(command_details); -+ rc = selinux_run_helper(sesh_args, command_details->envp); - switch (rc) { - case SESH_SUCCESS: - break; -@@ -829,15 +855,12 @@ selinux_edit_create_tfiles(struct comman - sudo_fatalx(U_("sesh: internal error: odd number of paths")); - case SESH_ERR_NO_FILES: - sudo_fatalx(U_("sesh: unable to create temporary files")); -+ case SESH_ERR_KILLED: -+ sudo_fatalx(U_("sesh: killed by a signal")); - default: - sudo_fatalx(U_("sesh: unknown error %d"), rc); - } - -- /* Restore saved command_details. */ -- command_details->command = saved_command_details.command; -- command_details->flags = saved_command_details.flags; -- command_details->argv = saved_command_details.argv; -- - /* Chown to user's UID so they can edit the temporary files. */ - for (i = 0; i < nfiles; i++) { - if (chown(tf[i].tfile, user_details.uid, user_details.gid) != 0) { -@@ -858,24 +881,14 @@ selinux_edit_copy_tfiles(struct command_ - { - char **sesh_args, **sesh_ap; - int i, rc, sesh_nargs, ret = 1; -- struct command_details saved_command_details; - struct timespec ts; - struct stat sb; - debug_decl(selinux_edit_copy_tfiles, SUDO_DEBUG_EDIT) -- -- /* Prepare selinux stuff (setexeccon) */ -- if (selinux_setup(command_details->selinux_role, -- command_details->selinux_type, NULL, -1) != 0) -- debug_return_int(1); - - if (nfiles < 1) - debug_return_int(0); - - /* Construct common args for sesh */ -- memcpy(&saved_command_details, command_details, sizeof(struct command_details)); -- command_details->command = _PATH_SUDO_SESH; -- command_details->flags |= CD_SUDOEDIT_COPY; -- - sesh_nargs = 3 + (nfiles * 2) + 1; - sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *)); - if (sesh_args == NULL) { -@@ -913,32 +926,29 @@ selinux_edit_copy_tfiles(struct command_ - - if (sesh_ap - sesh_args > 3) { - /* Run sesh -e 1 ... */ -- command_details->argv = sesh_args; -- rc = run_command(command_details); -+ rc = selinux_run_helper(sesh_args, command_details->envp); - switch (rc) { - case SESH_SUCCESS: - ret = 0; - break; - case SESH_ERR_NO_FILES: - sudo_warnx(U_("unable to copy temporary files back to their original location")); -- sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir); - break; - case SESH_ERR_SOME_FILES: - sudo_warnx(U_("unable to copy some of the temporary files back to their original location")); -- sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir); -+ break; -+ case SESH_ERR_KILLED: -+ sudo_warnx(U_("sesh: killed by a signal")); - break; - default: - sudo_warnx(U_("sesh: unknown error %d"), rc); - break; - } -+ if (ret != 0) -+ sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir); - } - free(sesh_args); - -- /* Restore saved command_details. */ -- command_details->command = saved_command_details.command; -- command_details->flags = saved_command_details.flags; -- command_details->argv = saved_command_details.argv; -- - debug_return_int(ret); - } - #endif /* HAVE_SELINUX */ -@@ -990,6 +1000,15 @@ sudo_edit(struct command_details *comman - goto cleanup; - } - -+#ifdef HAVE_SELINUX -+ /* Compute new SELinux security context. */ -+ if (ISSET(command_details->flags, CD_RBAC_ENABLED)) { -+ if (selinux_setup(command_details->selinux_role, -+ command_details->selinux_type, NULL, -1, false) != 0) -+ goto cleanup; -+ } -+#endif -+ - /* Copy editor files to temporaries. */ - tf = calloc(nfiles, sizeof(*tf)); - if (tf == NULL) { -@@ -1025,6 +1044,7 @@ sudo_edit(struct command_details *comman - /* - * Run the editor with the invoking user's creds, - * keeping track of the time spent in the editor. -+ * XXX - should run editor with user's context - */ - if (sudo_gettime_real(×[0]) == -1) { - sudo_warn(U_("unable to read the clock")); -diff -up ./src/sudo_exec.h.symbolic-link-attack-3 ./src/sudo_exec.h ---- ./src/sudo_exec.h.symbolic-link-attack-3 2021-02-02 17:11:32.380020435 +0100 -+++ ./src/sudo_exec.h 2021-02-02 17:11:32.382020407 +0100 -@@ -73,6 +73,7 @@ - */ - #define SESH_SUCCESS 0 /* successful operation */ - #define SESH_ERR_FAILURE 1 /* unspecified error */ -+#define SESH_ERR_KILLED 2 /* killed by a signal */ - #define SESH_ERR_INVALID 30 /* invalid -e arg value */ - #define SESH_ERR_BAD_PATHS 31 /* odd number of paths */ - #define SESH_ERR_NO_FILES 32 /* copy error, no files copied */ -diff -up ./src/sudo.h.symbolic-link-attack-3 ./src/sudo.h ---- ./src/sudo.h.symbolic-link-attack-3 2019-10-28 13:28:52.000000000 +0100 -+++ ./src/sudo.h 2021-02-02 17:11:32.382020407 +0100 -@@ -135,12 +135,11 @@ struct user_details { - #define CD_USE_PTY 0x001000 - #define CD_SET_UTMP 0x002000 - #define CD_EXEC_BG 0x004000 --#define CD_SUDOEDIT_COPY 0x008000 --#define CD_SUDOEDIT_FOLLOW 0x010000 --#define CD_SUDOEDIT_CHECKDIR 0x020000 --#define CD_SET_GROUPS 0x040000 --#define CD_LOGIN_SHELL 0x080000 --#define CD_OVERRIDE_UMASK 0x100000 -+#define CD_SUDOEDIT_FOLLOW 0x008000 -+#define CD_SUDOEDIT_CHECKDIR 0x010000 -+#define CD_SET_GROUPS 0x020000 -+#define CD_LOGIN_SHELL 0x040000 -+#define CD_OVERRIDE_UMASK 0x080000 - - struct preserved_fd { - TAILQ_ENTRY(preserved_fd) entries; -@@ -240,7 +239,8 @@ int os_init_openbsd(int argc, char *argv - /* selinux.c */ - int selinux_restore_tty(void); - int selinux_setup(const char *role, const char *type, const char *ttyn, -- int ttyfd); -+ int ttyfd, bool label_tty); -+int selinux_setcon(void); - void selinux_execve(int fd, const char *path, char *const argv[], - char *envp[], bool noexec); - diff --git a/sudo-1.9.5-CVE-2021-23240-4.patch b/sudo-1.9.5-CVE-2021-23240-4.patch deleted file mode 100644 index b6d2813..0000000 --- a/sudo-1.9.5-CVE-2021-23240-4.patch +++ /dev/null @@ -1,380 +0,0 @@ -diff -up ./src/copy_file.c.symbolic-link-attack-4 ./src/copy_file.c ---- ./src/copy_file.c.symbolic-link-attack-4 2021-02-02 16:35:18.453036846 +0100 -+++ ./src/copy_file.c 2021-02-02 16:38:09.430731749 +0100 -@@ -23,6 +23,7 @@ - - #include - -+#include - #include - - #include -@@ -126,3 +127,35 @@ write_error: - debug_return_int(-1); - } - } -+ -+#ifdef HAVE_SELINUX -+bool -+sudo_check_temp_file(int tfd, const char *tfile, uid_t uid, struct stat *sb) -+{ -+ struct stat sbuf; -+ debug_decl(sudo_check_temp_file, SUDO_DEBUG_UTIL); -+ -+ if (sb == NULL) -+ sb = &sbuf; -+ -+ if (fstat(tfd, sb) == -1) { -+ sudo_warn(U_("unable to stat %s"), tfile); -+ debug_return_bool(false); -+ } -+ if (!S_ISREG(sb->st_mode)) { -+ sudo_warnx(U_("%s: not a regular file"), tfile); -+ debug_return_bool(false); -+ } -+ if ((sb->st_mode & ALLPERMS) != (S_IRUSR|S_IWUSR)) { -+ sudo_warnx(U_("%s: bad file mode: 0%o"), tfile, -+ (unsigned int)(sb->st_mode & ALLPERMS)); -+ debug_return_bool(false); -+ } -+ if (sb->st_uid != uid) { -+ sudo_warnx(U_("%s is owned by uid %u, should be %u"), -+ tfile, (unsigned int)sb->st_uid, (unsigned int)uid); -+ debug_return_bool(false); -+ } -+ debug_return_bool(true); -+} -+#endif /* SELINUX */ -diff -up ./src/sesh.c.symbolic-link-attack-4 ./src/sesh.c ---- ./src/sesh.c.symbolic-link-attack-4 2021-02-02 16:35:18.450036887 +0100 -+++ ./src/sesh.c 2021-02-02 16:38:52.907146897 +0100 -@@ -134,7 +134,7 @@ main(int argc, char *argv[], char *envp[ - static int - sesh_sudoedit(int argc, char *argv[]) - { -- int i, oflags_dst, post, ret = SESH_ERR_FAILURE; -+ int i, oflags_src, oflags_dst, post, ret = SESH_ERR_FAILURE; - int fd_src = -1, fd_dst = -1, follow = 0; - ssize_t nread, nwritten; - struct stat sb; -@@ -178,10 +178,12 @@ sesh_sudoedit(int argc, char *argv[]) - debug_return_int(SESH_ERR_BAD_PATHS); - - /* -- * Use O_EXCL if we are not in the post editing stage -- * so that it's ensured that the temporary files are -- * created by us and that we are not opening any symlinks. -+ * In the pre-editing stage, use O_EXCL to ensure that the temporary -+ * files are created by us and that we are not opening any symlinks. -+ * In the post-editing stage, use O_NOFOLLOW so we don't follow symlinks -+ * when opening the temporary files. - */ -+ oflags_src = O_RDONLY|(post ? O_NONBLOCK|O_NOFOLLOW : follow); - oflags_dst = O_WRONLY|O_CREAT|(post ? follow : O_EXCL); - for (i = 0; i < argc - 1; i += 2) { - const char *path_src = argv[i]; -@@ -191,7 +193,7 @@ sesh_sudoedit(int argc, char *argv[]) - * doesn't exist, that's OK, we'll create an empty - * destination file. - */ -- if ((fd_src = open(path_src, O_RDONLY|follow, S_IRUSR|S_IWUSR)) < 0) { -+ if ((fd_src = open(path_src, oflags_src, S_IRUSR|S_IWUSR)) < 0) { - if (errno != ENOENT) { - sudo_warn("%s", path_src); - if (post) { -@@ -201,6 +203,14 @@ sesh_sudoedit(int argc, char *argv[]) - goto cleanup_0; - } - } -+ if (post) { -+ /* Make sure the temporary file is safe and has the proper owner. */ -+ if (!sudo_check_temp_file(fd_src, path_src, geteuid(), &sb)) { -+ ret = SESH_ERR_SOME_FILES; -+ goto nocleanup; -+ } -+ fcntl(fd_src, F_SETFL, fcntl(fd_src, F_GETFL, 0) & ~O_NONBLOCK); -+ } - - if ((fd_dst = open(path_dst, oflags_dst, post ? - (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR))) < 0) { -@@ -218,10 +228,7 @@ sesh_sudoedit(int argc, char *argv[]) - off_t len_dst = -1; - - if (post) { -- if (fstat(fd_src, &sb) != 0) { -- ret = SESH_ERR_SOME_FILES; -- goto nocleanup; -- } -+ /* sudo_check_temp_file() filled in sb for us. */ - len_src = sb.st_size; - if (fstat(fd_dst, &sb) != 0) { - ret = SESH_ERR_SOME_FILES; -diff -up ./src/sudo_edit.c.symbolic-link-attack-4 ./src/sudo_edit.c ---- ./src/sudo_edit.c.symbolic-link-attack-4 2021-02-02 16:35:18.452036860 +0100 -+++ ./src/sudo_edit.c 2021-02-02 16:54:25.943429580 +0100 -@@ -253,8 +253,10 @@ sudo_edit_mktemp(const char *ofile, char - } else { - len = asprintf(tfile, "%s/%s.XXXXXXXX", edit_tmpdir, cp); - } -- if (len == -1) -- sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -+ if (len == -1) { -+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -+ debug_return_int(-1); -+ } - tfd = mkstemps(*tfile, suff ? strlen(suff) : 0); - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "%s -> %s, fd %d", ofile, *tfile, tfd); -@@ -757,7 +759,8 @@ bad: - - #ifdef HAVE_SELINUX - static int --selinux_run_helper(char *argv[], char *envp[]) -+selinux_run_helper(uid_t uid, gid_t gid, int ngroups, GETGROUPS_T *groups, -+ char *const argv[], char *const envp[]) - { - int status, ret = SESH_ERR_FAILURE; - const char *sesh; -@@ -777,8 +780,10 @@ selinux_run_helper(char *argv[], char *e - break; - case 0: - /* child runs sesh in new context */ -- if (selinux_setcon() == 0) -+ if (selinux_setcon() == 0) { -+ switch_user(uid, gid, ngroups, groups); - execve(sesh, argv, envp); -+ } - _exit(SESH_ERR_FAILURE); - default: - /* parent waits */ -@@ -797,7 +802,7 @@ selinux_edit_create_tfiles(struct comman - struct tempfile *tf, char *files[], int nfiles) - { - char **sesh_args, **sesh_ap; -- int i, rc, sesh_nargs; -+ int i, rc, error, sesh_nargs, ret = -1; - struct stat sb; - debug_decl(selinux_edit_create_tfiles, SUDO_DEBUG_EDIT) - -@@ -809,7 +814,7 @@ selinux_edit_create_tfiles(struct comman - sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *)); - if (sesh_args == NULL) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -- debug_return_int(-1); -+ goto done; - } - *sesh_ap++ = "sesh"; - *sesh_ap++ = "-e"; -@@ -817,7 +822,6 @@ selinux_edit_create_tfiles(struct comman - *sesh_ap++ = "-h"; - *sesh_ap++ = "0"; - -- /* XXX - temp files should be created with user's context */ - for (i = 0; i < nfiles; i++) { - char *tfile, *ofile = files[i]; - int tfd; -@@ -835,8 +839,7 @@ selinux_edit_create_tfiles(struct comman - if (tfd == -1) { - sudo_warn("mkstemps"); - free(tfile); -- free(sesh_args); -- debug_return_int(-1); -+ goto done; - } - /* Helper will re-create temp file with proper security context. */ - close(tfd); -@@ -847,8 +850,10 @@ selinux_edit_create_tfiles(struct comman - *sesh_ap = NULL; - - /* Run sesh -e [-h] 0 ... */ -- rc = selinux_run_helper(sesh_args, command_details->envp); -- switch (rc) { -+ error = selinux_run_helper(command_details->uid, command_details->gid, -+ command_details->ngroups, command_details->groups, sesh_args, -+ command_details->envp); -+ switch (error) { - case SESH_SUCCESS: - break; - case SESH_ERR_BAD_PATHS: -@@ -858,21 +863,34 @@ selinux_edit_create_tfiles(struct comman - case SESH_ERR_KILLED: - sudo_fatalx(U_("sesh: killed by a signal")); - default: -- sudo_fatalx(U_("sesh: unknown error %d"), rc); -+ sudo_fatalx(U_("sesh: unknown error %d"), error); -+ goto done; - } - -- /* Chown to user's UID so they can edit the temporary files. */ - for (i = 0; i < nfiles; i++) { -- if (chown(tf[i].tfile, user_details.uid, user_details.gid) != 0) { -- sudo_warn("unable to chown(%s) to %d:%d for editing", -- tf[i].tfile, user_details.uid, user_details.gid); -- } -+ int tfd = open(tf[i].tfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW); -+ if (tfd == -1) { -+ sudo_warn(U_("unable to open %s"), tf[i].tfile); -+ goto done; -+ } -+ if (!sudo_check_temp_file(tfd, tf[i].tfile, command_details->uid, NULL)) { -+ close(tfd); -+ goto done; -+ } -+ if (fchown(tfd, user_details.uid, user_details.gid) != 0) { -+ sudo_warn("unable to chown(%s) to %d:%d for editing", -+ tf[i].tfile, user_details.uid, user_details.gid); -+ close(tfd); -+ goto done; -+ } -+ close(tfd); - } - -+done: - /* Contents of tf will be freed by caller. */ - free(sesh_args); - -- return (nfiles); -+ debug_return_int(ret); - } - - static int -@@ -880,7 +898,8 @@ selinux_edit_copy_tfiles(struct command_ - struct tempfile *tf, int nfiles, struct timespec *times) - { - char **sesh_args, **sesh_ap; -- int i, rc, sesh_nargs, ret = 1; -+ int i, rc, error, sesh_nargs, ret = 1; -+ int tfd = -1; - struct timespec ts; - struct stat sb; - debug_decl(selinux_edit_copy_tfiles, SUDO_DEBUG_EDIT) -@@ -901,33 +920,43 @@ selinux_edit_copy_tfiles(struct command_ - - /* Construct args for sesh -e 1 */ - for (i = 0; i < nfiles; i++) { -- if (stat(tf[i].tfile, &sb) == 0) { -- mtim_get(&sb, ts); -- if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) { -- /* -- * If mtime and size match but the user spent no measurable -- * time in the editor we can't tell if the file was changed. -- */ -- if (sudo_timespeccmp(×[0], ×[1], !=)) { -- sudo_warnx(U_("%s unchanged"), tf[i].ofile); -- unlink(tf[i].tfile); -- continue; -- } -+ if (tfd != -1) -+ close(tfd); -+ if ((tfd = open(tf[i].tfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW)) == -1) { -+ sudo_warn(U_("unable to open %s"), tf[i].tfile); -+ continue; -+ } -+ if (!sudo_check_temp_file(tfd, tf[i].tfile, user_details.uid, &sb)) -+ continue; -+ mtim_get(&sb, ts); -+ if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) { -+ /* -+ * If mtime and size match but the user spent no measurable -+ * time in the editor we can't tell if the file was changed. -+ */ -+ if (sudo_timespeccmp(×[0], ×[1], !=)) { -+ sudo_warnx(U_("%s unchanged"), tf[i].ofile); -+ unlink(tf[i].tfile); -+ continue; - } - } - *sesh_ap++ = tf[i].tfile; - *sesh_ap++ = tf[i].ofile; -- if (chown(tf[i].tfile, command_details->uid, command_details->gid) != 0) { -+ if (fchown(tfd, command_details->uid, command_details->gid) != 0) { - sudo_warn("unable to chown(%s) back to %d:%d", tf[i].tfile, - command_details->uid, command_details->gid); - } - } - *sesh_ap = NULL; -+ if (tfd != -1) -+ close(tfd); - - if (sesh_ap - sesh_args > 3) { - /* Run sesh -e 1 ... */ -- rc = selinux_run_helper(sesh_args, command_details->envp); -- switch (rc) { -+ error = selinux_run_helper(command_details->uid, command_details->gid, -+ command_details->ngroups, command_details->groups, sesh_args, -+ command_details->envp); -+ switch (error) { - case SESH_SUCCESS: - ret = 0; - break; -@@ -941,7 +970,7 @@ selinux_edit_copy_tfiles(struct command_ - sudo_warnx(U_("sesh: killed by a signal")); - break; - default: -- sudo_warnx(U_("sesh: unknown error %d"), rc); -+ sudo_warnx(U_("sesh: unknown error %d"), error); - break; - } - if (ret != 0) -@@ -963,7 +992,7 @@ sudo_edit(struct command_details *comman - { - struct command_details saved_command_details; - char **nargv = NULL, **ap, **files = NULL; -- int errors, i, ac, nargc, rc; -+ int errors, i, ac, nargc, ret; - int editor_argc = 0, nfiles = 0; - struct timespec times[2]; - struct tempfile *tf = NULL; -@@ -1058,7 +1087,7 @@ sudo_edit(struct command_details *comman - command_details->ngroups = user_details.ngroups; - command_details->groups = user_details.groups; - command_details->argv = nargv; -- rc = run_command(command_details); -+ ret = run_command(command_details); - if (sudo_gettime_real(×[1]) == -1) { - sudo_warn(U_("unable to read the clock")); - goto cleanup; -@@ -1080,14 +1109,16 @@ sudo_edit(struct command_details *comman - else - #endif - errors = sudo_edit_copy_tfiles(command_details, tf, nfiles, times); -- if (errors) -- goto cleanup; -+ if (errors) { -+ /* Preserve the edited temporary files. */ -+ ret = W_EXITCODE(1, 0); -+ } - - for (i = 0; i < nfiles; i++) - free(tf[i].tfile); - free(tf); - free(nargv); -- debug_return_int(rc); -+ debug_return_int(ret); - - cleanup: - /* Clean up temp files and return. */ -diff -up ./src/sudo_exec.h.symbolic-link-attack-4 ./src/sudo_exec.h ---- ./src/sudo_exec.h.symbolic-link-attack-4 2021-02-02 16:35:18.452036860 +0100 -+++ ./src/sudo_exec.h 2021-02-02 16:35:18.454036833 +0100 -@@ -1,7 +1,7 @@ - /* - * SPDX-License-Identifier: ISC - * -- * Copyright (c) 2010-2016 Todd C. Miller -+ * Copyright (c) 2010-2017, 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 -@@ -84,9 +84,11 @@ - */ - struct command_details; - struct command_status; -+struct stat; - - /* copy_file.c */ - int sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst, int dst_fd, off_t dst_len); -+bool sudo_check_temp_file(int tfd, const char *tname, uid_t uid, struct stat *sb); - - /* exec.c */ - void exec_cmnd(struct command_details *details, int errfd); diff --git a/sudo-1.9.5-CVE-2021-23240-5.patch b/sudo-1.9.5-CVE-2021-23240-5.patch deleted file mode 100644 index fd1bbd1..0000000 --- a/sudo-1.9.5-CVE-2021-23240-5.patch +++ /dev/null @@ -1,47 +0,0 @@ -diff -up ./src/copy_file.c.symbolic-link-attack-5 ./src/copy_file.c ---- ./src/copy_file.c.symbolic-link-attack-5 2021-02-02 17:18:05.355567274 +0100 -+++ ./src/copy_file.c 2021-02-02 17:19:09.904671563 +0100 -@@ -128,7 +128,6 @@ write_error: - } - } - --#ifdef HAVE_SELINUX - bool - sudo_check_temp_file(int tfd, const char *tfile, uid_t uid, struct stat *sb) - { -@@ -158,4 +157,3 @@ sudo_check_temp_file(int tfd, const char - } - debug_return_bool(true); - } --#endif /* SELINUX */ -diff -up ./src/sudo_edit.c.symbolic-link-attack-5 ./src/sudo_edit.c ---- ./src/sudo_edit.c.symbolic-link-attack-5 2021-02-02 17:18:05.355567274 +0100 -+++ ./src/sudo_edit.c 2021-02-02 17:18:05.356567260 +0100 -@@ -692,24 +692,17 @@ sudo_edit_copy_tfiles(struct command_det - - /* Copy contents of temp files to real ones. */ - for (i = 0; i < nfiles; i++) { -- int rc = -1; - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "seteuid(%u)", (unsigned int)user_details.uid); - if (seteuid(user_details.uid) != 0) - sudo_fatal("seteuid(%u)", (unsigned int)user_details.uid); - tfd = sudo_edit_open(tf[i].tfile, O_RDONLY, - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, NULL); -- if (tfd != -1) -- rc = fstat(tfd, &sb); -- sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, -- "seteuid(%u)", ROOT_UID); - if (seteuid(ROOT_UID) != 0) - sudo_fatal("seteuid(ROOT_UID)"); -- if (rc == -1 || !S_ISREG(sb.st_mode)) { -- if (rc == -1) -- sudo_warn("%s", tf[i].tfile); -- else -- sudo_warnx(U_("%s: not a regular file"), tf[i].tfile); -+ sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, -+ "seteuid(%u)", ROOT_UID); -+ if (tfd == -1 || !sudo_check_temp_file(tfd, tf[i].tfile, user_details.uid, &sb)) { - sudo_warnx(U_("%s left unmodified"), tf[i].ofile); - if (tfd != -1) - close(tfd); diff --git a/sudo-1.9.5-selinux-t.patch b/sudo-1.9.5-selinux-t.patch new file mode 100644 index 0000000..aec3024 --- /dev/null +++ b/sudo-1.9.5-selinux-t.patch @@ -0,0 +1,74 @@ +From 73006fb25f0ebc35bc46b8f20036d40fcbb6de53 Mon Sep 17 00:00:00 2001 +From: Radovan Sroka +Date: Thu, 1 Apr 2021 21:42:03 +0200 +Subject: [PATCH] Removed depricated security_context_t + +Signed-off-by: Radovan Sroka +--- + src/selinux.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/src/selinux.c b/src/selinux.c +index a2f73f8d0..c2f50aafb 100644 +--- a/src/selinux.c ++++ b/src/selinux.c +@@ -58,10 +58,10 @@ + #include "sudo_exec.h" + + static struct selinux_state { +- security_context_t old_context; +- security_context_t new_context; +- security_context_t tty_con_raw; +- security_context_t new_tty_con_raw; ++ char * old_context; ++ char * new_context; ++ char * tty_con_raw; ++ char * new_tty_con_raw; + const char *ttyn; + int ttyfd; + int enforcing; +@@ -69,8 +69,8 @@ static struct selinux_state { + + #ifdef HAVE_LINUX_AUDIT + static int +-audit_role_change(const security_context_t old_context, +- const security_context_t new_context, const char *ttyn, int result) ++audit_role_change(const char * old_context, ++ const char * new_context, const char *ttyn, int result) + { + int au_fd, rc = -1; + char *message; +@@ -111,7 +111,7 @@ int + selinux_restore_tty(void) + { + int ret = -1; +- security_context_t chk_tty_con_raw = NULL; ++ char * chk_tty_con_raw = NULL; + debug_decl(selinux_restore_tty, SUDO_DEBUG_SELINUX); + + if (se_state.ttyfd == -1 || se_state.new_tty_con_raw == NULL) { +@@ -166,8 +166,8 @@ selinux_restore_tty(void) + static int + relabel_tty(const char *ttyn, int ptyfd) + { +- security_context_t tty_con = NULL; +- security_context_t new_tty_con = NULL; ++ char * tty_con = NULL; ++ char * new_tty_con = NULL; + struct stat sb; + int fd; + debug_decl(relabel_tty, SUDO_DEBUG_SELINUX); +@@ -308,10 +308,10 @@ relabel_tty(const char *ttyn, int ptyfd) + * Returns a new security context based on the old context and the + * specified role and type. + */ +-security_context_t +-get_exec_context(security_context_t old_context, const char *role, const char *type) ++char * ++get_exec_context(char * old_context, const char *role, const char *type) + { +- security_context_t new_context = NULL; ++ char * new_context = NULL; + context_t context = NULL; + char *typebuf = NULL; + debug_decl(get_exec_context, SUDO_DEBUG_SELINUX); diff --git a/sudo-1.9.5-sesh-bad-condition.patch b/sudo-1.9.5-sesh-bad-condition.patch new file mode 100644 index 0000000..25335ec --- /dev/null +++ b/sudo-1.9.5-sesh-bad-condition.patch @@ -0,0 +1,51 @@ +From 613a8053dbc3ab43cf0cdaf09f207ffdb0b40e08 Mon Sep 17 00:00:00 2001 +From: Radovan Sroka +Date: Wed, 7 Apr 2021 14:43:40 +0200 +Subject: [PATCH] Fixed bad condition for sesh args + +In selinux_edit_copy_tfiles() when there is only one file and the open() +fails then number of arguments is lower than expected. +Sudo should return error with or without "Defaults !sudoedit_checkdir" set. + +This was found with regression testing of CVE-2021-23240. + +Signed-off-by: Radovan Sroka +--- + src/sudo_edit.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/sudo_edit.c b/src/sudo_edit.c +index 41fc61c3a..15c75d8c4 100644 +--- a/src/sudo_edit.c ++++ b/src/sudo_edit.c +@@ -529,6 +529,8 @@ selinux_edit_copy_tfiles(struct command_details *command_details, + if (nfiles < 1) + debug_return_int(0); + ++ const int check_dir = ISSET(command_details->flags, CD_SUDOEDIT_CHECKDIR); ++ + /* Construct common args for sesh */ + sesh_nargs = 5 + (nfiles * 2) + 1; + sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *)); +@@ -538,7 +540,7 @@ selinux_edit_copy_tfiles(struct command_details *command_details, + } + *sesh_ap++ = "sesh"; + *sesh_ap++ = "-e"; +- if (ISSET(command_details->flags, CD_SUDOEDIT_CHECKDIR)) { ++ if (check_dir) { + if ((user_str = selinux_fmt_sudo_user()) == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + goto done; +@@ -581,7 +583,11 @@ selinux_edit_copy_tfiles(struct command_details *command_details, + if (tfd != -1) + close(tfd); + +- if (sesh_ap - sesh_args > 3) { ++ /* ++ * check dir adds two more args to the array ++ */ ++ if ((!check_dir && sesh_ap - sesh_args > 3) ++ || (check_dir && sesh_ap - sesh_args > 5)) { + /* Run sesh -e 1 ... */ + error = selinux_run_helper(command_details->cred.uid, command_details->cred.gid, + command_details->cred.ngroups, command_details->cred.groups, sesh_args, diff --git a/sudo-1.9.5-sudoedit-selinux.patch b/sudo-1.9.5-sudoedit-selinux.patch deleted file mode 100644 index ece57bd..0000000 --- a/sudo-1.9.5-sudoedit-selinux.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -up ./src/sudo_edit.c.rest ./src/sudo_edit.c ---- ./src/sudo_edit.c.rest 2021-11-21 18:41:09.420657680 +0100 -+++ ./src/sudo_edit.c 2021-11-21 18:42:23.214272777 +0100 -@@ -878,6 +878,7 @@ selinux_edit_create_tfiles(struct comman - } - close(tfd); - } -+ ret = nfiles; - - done: - /* Contents of tf will be freed by caller. */ diff --git a/sudo-1.9.5-undefined-symbol.patch b/sudo-1.9.5-undefined-symbol.patch new file mode 100644 index 0000000..ce4002c --- /dev/null +++ b/sudo-1.9.5-undefined-symbol.patch @@ -0,0 +1,19 @@ +diff -up ./plugins/sudoers/audit.c.undefined ./plugins/sudoers/audit.c +--- ./plugins/sudoers/audit.c.undefined 2021-07-12 14:59:53.472306208 +0200 ++++ ./plugins/sudoers/audit.c 2021-07-12 15:00:45.620620369 +0200 +@@ -197,7 +197,6 @@ sudoers_audit_open(unsigned int version, + debug_return_int(ret); + } + +-#ifdef SUDOERS_LOG_CLIENT + static void + audit_to_eventlog(struct eventlog *evlog, char * const command_info[], + char * const run_argv[], char * const run_envp[]) +@@ -244,6 +243,7 @@ audit_to_eventlog(struct eventlog *evlog + debug_return; + } + ++#ifdef SUDOERS_LOG_CLIENT + static bool + log_server_accept(char * const command_info[], char * const run_argv[], + char * const run_envp[]) diff --git a/sudo-1.9.7-utmp-leak.patch b/sudo-1.9.5-utmp-leak.patch similarity index 100% rename from sudo-1.9.7-utmp-leak.patch rename to sudo-1.9.5-utmp-leak.patch diff --git a/sudo-1.9.7-krb5ccname.patch b/sudo-1.9.7-krb5ccname.patch deleted file mode 100644 index 4339423..0000000 --- a/sudo-1.9.7-krb5ccname.patch +++ /dev/null @@ -1,54 +0,0 @@ -diff -up ./plugins/sudoers/auth/pam.c.krb5ccname ./plugins/sudoers/auth/pam.c ---- ./plugins/sudoers/auth/pam.c.krb5ccname 2019-10-28 13:27:38.000000000 +0100 -+++ ./plugins/sudoers/auth/pam.c 2021-12-06 11:14:15.580226222 +0100 -@@ -119,10 +119,10 @@ conv_filter_init(void) - - /* - * Messages from PAM account management when trusted mode is enabled: -- * 1 Last successful login for %s: %s -- * 2 Last successful login for %s: %s on %s -- * 3 Last unsuccessful login for %s: %s -- * 4 Last unsuccessful login for %s: %s on %s -+ * 1 Last successful login for %s: %s -+ * 2 Last successful login for %s: %s on %s -+ * 3 Last unsuccessful login for %s: %s -+ * 4 Last unsuccessful login for %s: %s on %s - */ - if ((catd = catopen("pam_comsec", NL_CAT_LOCALE)) != -1) { - maxfilters += 4; -@@ -290,6 +290,7 @@ sudo_pam_init_quiet(struct passwd *pw, s - int - sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback) - { -+ const char *envccname; - const char *s; - int *pam_status = (int *) auth->data; - debug_decl(sudo_pam_verify, SUDOERS_DEBUG_AUTH) -@@ -298,8 +299,27 @@ sudo_pam_verify(struct passwd *pw, char - getpass_error = false; /* set by converse if user presses ^C */ - conv_callback = callback; /* passed to conversation function */ - -+ /* Set KRB5CCNAME from the user environment if not set to propagate this -+ * information to PAM modules that may use it to authentication. */ -+ envccname = sudo_getenv("KRB5CCNAME"); -+ if (envccname == NULL && user_ccname != NULL) { -+ if (sudo_setenv("KRB5CCNAME", user_ccname, true) != 0) { -+ sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, -+ "unable to set KRB5CCNAME"); -+ debug_return_int(AUTH_FAILURE); -+ } -+ } -+ - /* PAM_SILENT prevents the authentication service from generating output. */ - *pam_status = pam_authenticate(pamh, PAM_SILENT); -+ -+ /* Restore KRB5CCNAME to its original value. */ -+ if (envccname == NULL && sudo_unsetenv("KRB5CCNAME") != 0) { -+ sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, -+ "unable to restore KRB5CCNAME"); -+ debug_return_int(AUTH_FAILURE); -+ } -+ - if (getpass_error) { - /* error or ^C from tgetpass() */ - debug_return_int(AUTH_INTR); diff --git a/sudo-1.9.7-sigchild.patch b/sudo-1.9.7-sigchild.patch deleted file mode 100644 index 94fcc94..0000000 --- a/sudo-1.9.7-sigchild.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 727056e0c9519d8eecde801e950b35f2f69c72e2 Mon Sep 17 00:00:00 2001 -From: "Todd C. Miller" -Date: Fri, 23 Apr 2021 07:41:27 -0600 -Subject: [PATCH] Make sure SIGCHLD is not ignored when sudo is executed. If - SIGCHLD is ignored there is a race condition between when the process is - executed and when the SIGCHLD handler is installed. This fixes the bug - described by GitHub PR #98 - ---- - src/signal.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/src/signal.c b/src/signal.c -index 7f90d707b..866b64790 100644 ---- a/src/signal.c -+++ b/src/signal.c -@@ -133,6 +133,18 @@ init_signals(void) - case SIGTTOU: - /* Don't install these until exec time. */ - break; -+ case SIGCHLD: -+ /* Sudo needs to be able to catch SIGCHLD. */ -+ if (ss->sa.sa_handler == SIG_IGN) { -+ sudo_debug_printf(SUDO_DEBUG_INFO, -+ "will restore signal %d on exec", SIGCHLD); -+ ss->restore = true; -+ } -+ if (sigaction(SIGCHLD, &sa, NULL) != 0) { -+ sudo_warn(U_("unable to set handler for signal %d"), -+ SIGCHLD); -+ } -+ break; - default: - if (ss->sa.sa_handler != SIG_IGN) { - if (sigaction(ss->signo, &sa, NULL) != 0) { diff --git a/sudo.spec b/sudo.spec index 678ac5f..c6ee998 100644 --- a/sudo.spec +++ b/sudo.spec @@ -1,7 +1,7 @@ Summary: Allows restricted root access for specified users Name: sudo -Version: 1.8.29 -Release: 10%{?dist} +Version: 1.9.5p2 +Release: 1%{?dist} License: ISC Group: Applications/System URL: https://www.sudo.ws/ @@ -31,57 +31,27 @@ BuildRequires: openldap-devel BuildRequires: pam-devel BuildRequires: zlib-devel -# don't strip -Patch1: sudo-1.6.7p5-strip.patch -# 881258 - rpmdiff: added missing sudo-ldap.conf manpage -Patch2: sudo-1.8.23-sudoldapconfman.patch -# env debug patch -Patch3: sudo-1.7.2p1-envdebug.patch -# 1247591 - Sudo taking a long time when user information is stored externally. -Patch4: sudo-1.8.23-legacy-group-processing.patch -# 840980 - sudo creates a new parent process -# Adds cmnd_no_wait Defaults option -Patch5: sudo-1.8.23-nowaitopt.patch -# 1312486 - RHEL7 sudo logs username "root" instead of realuser in /var/log/secure -Patch6: sudo-1.8.6p7-logsudouser.patch -# 1786987 - CVE-2019-19232 sudo: attacker with access to a Runas ALL sudoer account -# can impersonate a nonexistent user [rhel-8] -Patch7: sudo-1.8.29-CVE-2019-19232.patch -# 1796518 - [RFE] add optional check for the target user shell -Patch8: sudo-1.8.29-CVE-2019-19234.patch -# 1798093 - CVE-2019-18634 sudo: Stack based buffer overflow in when pwfeedback is enabled [rhel-8.2.0] -Patch9: sudo-1.8.29-CVE-2019-18634.patch +Patch2: sudo-1.9.5-undefined-symbol.patch +Patch3: sudo-1.9.5-selinux-t.patch +Patch4: sudo-1.9.5-sesh-bad-condition.patch +Patch5: sudo-1.9.5-utmp-leak.patch +Patch6: covscan.patch +Patch7: sha-digest-calc.patch +Patch8: sudo-1.9.12-CVE-2023-22809.patch -# 1815164 - sudo allows privilege escalation with expire password -Patch10: sudo-1.8.29-expired-password-part1.patch -Patch11: sudo-1.8.29-expired-password-part2.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 -# 1917734 - EMBARGOED CVE-2021-3156 sudo: Heap-buffer overflow in argument parsing [rhel-8.4.0] -Patch12: sudo-1.8.31-CVE-2021-3156.patch -# 1916434 - CVE-2021-23239 sudo: possible directory existence test due to race condition in sudoedit [rhel-8] -Patch13: sudo-1.9.5-CVE-2021-23239.patch -# 1917038 - CVE-2021-23240 sudo: symbolic link attack in SELinux-enabled sudoedit [rhel-8] -Patch14: sudo-1.9.5-CVE-2021-23240-1.patch -Patch15: sudo-1.9.5-CVE-2021-23240-2.patch -Patch16: sudo-1.9.5-CVE-2021-23240-3.patch -Patch17: sudo-1.9.5-CVE-2021-23240-4.patch -Patch18: sudo-1.9.5-CVE-2021-23240-5.patch +Patch18: linker.patch -# 2029551 - sudoedit does not work with selinux args -Patch19: sudo-1.9.5-sudoedit-selinux.patch -# 1999751 - Request to backport https://www.sudo.ws/repos/sudo/rev/b4c91a0f72e7 to RHEL 8 -Patch20: sudo-1.9.7-sigchild.patch -# 1917379 - [RFE] pass KRB5CCNAME to pam_authenticate environment if available -Patch21: sudo-1.9.7-krb5ccname.patch -# 1986572 - utmp resource leak in sudo -Patch22: sudo-1.9.7-utmp-leak.patch - -# 2114576 - sudo digest check fails incorrectly for certain file sizes (SHA512/SHA384) -Patch23: sha-digest-calc.patch -# 2161221 - EMBARGOED CVE-2023-22809 sudo: arbitrary file write with privileges of the RunAs user [rhel-8.8.0] -Patch24: sudo-1.9.12-CVE-2023-22809-whitelist.patch -Patch25: sudo-1.9.12-CVE-2023-22809-backports.patch -Patch26: sudo-1.9.12-CVE-2023-22809.patch +Patch19: sudo-1.9.15-CVE-2023-42465.patch %description Sudo (superuser do) allows a system administrator to give certain @@ -106,39 +76,27 @@ plugins that use %{name}. %prep %setup -q -%patch1 -p1 -b .strip -%patch2 -p1 -b .sudoldapconfman -%patch3 -p1 -b .env-debug -%patch4 -p1 -b .legacy-processing -%patch5 -p1 -b .nowait -%patch6 -p1 -b .logsudouser -%patch7 -p1 -b .CVE-2019-19232 -%patch8 -p1 -b .target-shell -%patch9 -p1 -b .CVE-2019-18634 +%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 -%patch10 -p1 -b .expired1 -%patch11 -p1 -b .expired2 +%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 -%patch12 -p1 -b .heap-buffer +%patch -P 18 -p1 -b .linker -%patch13 -p1 -b .sudoedit-race - -%patch14 -p1 -b .symbolic-link-attack-1 -%patch15 -p1 -b .symbolic-link-attack-2 -%patch16 -p1 -b .symbolic-link-attack-3 -%patch17 -p1 -b .symbolic-link-attack-4 -%patch18 -p1 -b .symbolic-link-attack-5 - -%patch19 -p1 -b .sudoedit-selinux - -%patch20 -p1 -b .sigchild -%patch21 -p1 -b .krb5ccname -%patch22 -p1 -b .utmp-leak - -%patch23 -p1 -b .sha-digest -%patch24 -p1 -b .whitelist -%patch25 -p1 -b .backports -%patch26 -p1 -b .cve +%patch -P 19 -p1 -b .rowhammer %build # Remove bundled copy of zlib @@ -158,7 +116,10 @@ export CFLAGS="$RPM_OPT_FLAGS $F_PIE" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" --sbindir=%{_sbindir} \ --libdir=%{_libdir} \ --docdir=%{_pkgdocdir} \ + --disable-openssl \ --disable-root-mailer \ + --disable-log-server \ + --disable-log-client \ --with-logging=syslog \ --with-logfac=authpriv \ --with-pam \ @@ -172,6 +133,7 @@ export CFLAGS="$RPM_OPT_FLAGS $F_PIE" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" --with-selinux \ --with-passprompt="[sudo] password for %p: " \ --with-linux-audit \ + --disable-python \ --with-sssd # --without-kerb5 \ # --without-kerb4 @@ -192,8 +154,18 @@ install -p -d -m 700 $RPM_BUILD_ROOT/var/db/sudo install -p -d -m 700 $RPM_BUILD_ROOT/var/db/sudo/lectured install -p -d -m 750 $RPM_BUILD_ROOT/etc/sudoers.d install -p -c -m 0440 %{SOURCE1} $RPM_BUILD_ROOT/etc/sudoers -install -p -c -m 0640 %{SOURCE3} $RPM_BUILD_ROOT/etc/sudo.conf install -p -c -m 0640 %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/sudo-ldap.conf +install -p -c -m 0640 %{SOURCE3} $RPM_BUILD_ROOT/%{_sysconfdir}/sudo.conf + + +# create sudo-ldap.conf man +echo ".so man5/sudoers.ldap.5" > sudo-ldap.conf.5 +gzip sudo-ldap.conf.5 +install -p -c -m 0644 sudo-ldap.conf.5.gz $RPM_BUILD_ROOT/%{_mandir}/man5/sudo-ldap.conf.5.gz +rm -f sudo-ldap.conf.5.gz + +# we are not building sendlog so we don't need this +rm -rf $RPM_BUILD_ROOT/%{_mandir}/man8/sudo_sendlog.8 # Add sudo to protected packages install -p -d -m 755 $RPM_BUILD_ROOT/etc/dnf/protected.d/ @@ -264,7 +236,9 @@ rm -rf $RPM_BUILD_ROOT %dir %{_libexecdir}/sudo %attr(0755,root,root) %{_libexecdir}/sudo/sesh %attr(0644,root,root) %{_libexecdir}/sudo/sudo_noexec.so +%attr(0644,root,root) %{_libexecdir}/sudo/audit_json.so %attr(0644,root,root) %{_libexecdir}/sudo/sudoers.so +%attr(0644,root,root) %{_libexecdir}/sudo/sample_approval.so %attr(0644,root,root) %{_libexecdir}/sudo/group_file.so %attr(0644,root,root) %{_libexecdir}/sudo/system_group.so %attr(0644,root,root) %{_libexecdir}/sudo/libsudo_util.so.?.?.? @@ -298,6 +272,16 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/sudo_plugin.8* %changelog +* Mon Jan 22 2024 Radovan Sroka - 1.9.5p2-1 +RHEL 8.9.0.Z ERRATUM +- Rebase to 1.9.5p2 +- CVE-2023-28486 sudo: Sudo does not escape control characters in log messages +Resolves: RHEL-21825 +- CVE-2023-28487 sudo: Sudo does not escape control characters in sudoreplay output +Resolves: RHEL-21831 +- CVE-2023-42465 sudo: Targeted Corruption of Register and Stack Variables +Resolves: RHEL-21820 + * Wed Jan 11 2023 Radovan Sroka - 1.8.29.9 RHEL 8.8.0 ERRATUM - CVE-2023-22809 sudo: arbitrary file write with privileges of the RunAs user