diff --git a/backport-0001-CVE-2022-37434.patch b/backport-0001-CVE-2022-37434.patch new file mode 100644 index 0000000000000000000000000000000000000000..56a97ccf88578dd9ef71491a863fbf1e406bdabd --- /dev/null +++ b/backport-0001-CVE-2022-37434.patch @@ -0,0 +1,35 @@ +From eff308af425b67093bab25f80f1ae950166bece1 Mon Sep 17 00:00:00 2001 +From: Mark Adler +Date: Sat, 30 Jul 2022 15:51:11 -0700 +Subject: [PATCH] Fix a bug when getting a gzip header extra field with + inflate(). + +If the extra field was larger than the space the user provided with +inflateGetHeader(), and if multiple calls of inflate() delivered +the extra header data, then there could be a buffer overflow of the +provided space. This commit assures that provided space is not +exceeded. +--- + inflate.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c +index 2a0ac30..95a38f5 100644 +--- a/lib/zlib/inflate.c ++++ b/lib/zlib/inflate.c +@@ -765,9 +765,10 @@ int flush; + copy = state->length; + if (copy > have) copy = have; + if (copy) { ++ len = state->head->extra_len - state->length; + if (state->head != Z_NULL && +- state->head->extra != Z_NULL) { +- len = state->head->extra_len - state->length; ++ state->head->extra != Z_NULL && ++ len < state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); +-- +2.27.0 + diff --git a/backport-0002-CVE-2022-37434.patch b/backport-0002-CVE-2022-37434.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad2318b6bcec0f2ff538a2a3fdaf576d64f79ef0 --- /dev/null +++ b/backport-0002-CVE-2022-37434.patch @@ -0,0 +1,32 @@ +From 1eb7682f845ac9e9bf9ae35bbfb3bad5dacbd91d Mon Sep 17 00:00:00 2001 +From: Mark Adler +Date: Mon, 8 Aug 2022 10:50:09 -0700 +Subject: [PATCH] Fix extra field processing bug that dereferences NULL + state->head. + +The recent commit to fix a gzip header extra field processing bug +introduced the new bug fixed here. +--- + inflate.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c +index 95a38f5..9c5934e 100644 +--- a/lib/zlib/inflate.c ++++ b/lib/zlib/inflate.c +@@ -765,10 +765,10 @@ int flush; + copy = state->length; + if (copy > have) copy = have; + if (copy) { +- len = state->head->extra_len - state->length; + if (state->head != Z_NULL && + state->head->extra != Z_NULL && +- len < state->head->extra_max) { ++ (len = state->head->extra_len - state->length) < ++ state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); +-- +2.27.0 + diff --git a/backport-CVE-2022-33070.patch b/backport-CVE-2022-33070.patch new file mode 100644 index 0000000000000000000000000000000000000000..2310f14dfc46d8f3d1fbd2677d0daaf3571a7045 --- /dev/null +++ b/backport-CVE-2022-33070.patch @@ -0,0 +1,73 @@ +diff -Naru a/lib/protobuf-c/protobuf-c.c b/lib/protobuf-c/protobuf-c.c +--- a/lib/protobuf-c/protobuf-c.c ++++ b/lib/protobuf-c/protobuf-c.c +@@ -316,9 +316,8 @@ + static inline uint32_t + zigzag32(int32_t v) + { +- // Note: the right-shift must be arithmetic +- // Note: left shift must be unsigned because of overflow +- return ((uint32_t)(v) << 1) ^ (uint32_t)(v >> 31); ++ // Note: Using unsigned types prevents undefined behavior ++ return ((uint32_t)v << 1) ^ -((uint32_t)v >> 31); + } + + /** +@@ -380,9 +379,8 @@ + static inline uint64_t + zigzag64(int64_t v) + { +- // Note: the right-shift must be arithmetic +- // Note: left shift must be unsigned because of overflow +- return ((uint64_t)(v) << 1) ^ (uint64_t)(v >> 63); ++ // Note: Using unsigned types prevents undefined behavior ++ return ((uint64_t)v << 1) ^ -((uint64_t)v >> 63); + } + + /** +@@ -802,7 +800,8 @@ + } + + /** +- * Pack a signed 32-bit integer and return the number of bytes written. ++ * Pack a signed 32-bit integer and return the number of bytes written, ++ * passed as unsigned to avoid implementation-specific behavior. + * Negative numbers are encoded as two's complement 64-bit integers. + * + * \param value +@@ -813,14 +812,14 @@ + * Number of bytes written to `out`. + */ + static inline size_t +-int32_pack(int32_t value, uint8_t *out) ++int32_pack(uint32_t value, uint8_t *out) + { +- if (value < 0) { ++ if ((int32_t)value < 0) { + out[0] = value | 0x80; + out[1] = (value >> 7) | 0x80; + out[2] = (value >> 14) | 0x80; + out[3] = (value >> 21) | 0x80; +- out[4] = (value >> 28) | 0x80; ++ out[4] = (value >> 28) | 0xf0; + out[5] = out[6] = out[7] = out[8] = 0xff; + out[9] = 0x01; + return 10; +@@ -2425,7 +2424,7 @@ + unzigzag32(uint32_t v) + { + // Note: Using unsigned types prevents undefined behavior +- return (int32_t)((v >> 1) ^ (~(v & 1) + 1)); ++ return (int32_t)((v >> 1) ^ -(v & 1)); + } + + static inline uint32_t +@@ -2467,7 +2466,7 @@ + unzigzag64(uint64_t v) + { + // Note: Using unsigned types prevents undefined behavior +- return (int64_t)((v >> 1) ^ (~(v & 1) + 1)); ++ return (int64_t)((v >> 1) ^ -(v & 1)); + } + + static inline uint64_t diff --git a/backport-CVE-2023-22809.patch b/backport-CVE-2023-22809.patch new file mode 100644 index 0000000000000000000000000000000000000000..33ea6bf00819e7b1e6f43495b46b590011ccb348 --- /dev/null +++ b/backport-CVE-2023-22809.patch @@ -0,0 +1,143 @@ +From 0274a4f3b403162a37a10f199c989f3727ed3ad4 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Thu, 12 Jan 2023 15:55:27 -0700 +Subject: [PATCH] sudoedit: do not permit editor arguments to include "--" + (CVE-2023-22809) We use "--" to separate the editor and arguments from the + files to edit. If the editor arguments include "--", sudo can be tricked into + allowing the user to edit a file not permitted by the security policy. Thanks + to Matthieu Barjole and Victor Cutillas of Synacktiv (https://synacktiv.com) + for finding this bug. + +Reference:https://github.com/sudo-project/sudo/commit/0274a4f3b403162a37a10f199c989f3727ed3ad4 +Conflict:NA + +--- + plugins/sudoers/editor.c | 19 ++++++++++++++----- + plugins/sudoers/sudoers.c | 25 ++++++++++++++++++------- + plugins/sudoers/visudo.c | 8 ++++++-- + 3 files changed, 38 insertions(+), 14 deletions(-) + +diff --git a/plugins/sudoers/editor.c b/plugins/sudoers/editor.c +index 5ca4eb0af..6d988ff68 100644 +--- a/plugins/sudoers/editor.c ++++ b/plugins/sudoers/editor.c +@@ -133,7 +133,7 @@ resolve_editor(const char *ed, size_t edlen, int nfiles, char * const *files, + 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); + + /* +@@ -151,10 +151,7 @@ resolve_editor(const char *ed, size_t edlen, int nfiles, char * const *files, + /* 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"), NULL, + 0, allowlist) != FOUND) { +- sudoers_gc_remove(GC_PTR, editor); +- free(editor); +- errno = ENOENT; +- debug_return_str(NULL); ++ goto bad; + } + + /* Count rest of arguments and allocate editor argv. */ +@@ -175,6 +172,17 @@ resolve_editor(const char *ed, size_t edlen, int nfiles, char * const *files, + nargv[nargc] = copy_arg(cp, ep - cp); + if (nargv[nargc] == NULL) + goto oom; ++ ++ /* ++ * We use "--" to separate the editor and arguments from the files ++ * to edit. The editor arguments themselves may not contain "--". ++ */ ++ if (strcmp(nargv[nargc], "--") == 0) { ++ sudo_warnx(U_("ignoring editor: %.*s"), (int)edlen, ed); ++ sudo_warnx("%s", U_("editor arguments may not contain \"--\"")); ++ errno = EINVAL; ++ goto bad; ++ } + } + if (nfiles != 0) { + nargv[nargc++] = "--"; +@@ -188,6 +196,7 @@ resolve_editor(const char *ed, size_t edlen, int nfiles, char * const *files, + debug_return_str(editor_path); + oom: + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); ++bad: + sudoers_gc_remove(GC_PTR, editor); + free(editor); + free(editor_path); +diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c +index 7b97340ac..1f22853ff 100644 +--- a/plugins/sudoers/sudoers.c ++++ b/plugins/sudoers/sudoers.c +@@ -759,21 +759,32 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], + + /* Note: must call audit before uid change. */ + if (ISSET(sudo_mode, MODE_EDIT)) { ++ const char *env_editor = NULL; + char **edit_argv; + int edit_argc; +- const char *env_editor; + + free(safe_cmnd); + safe_cmnd = find_editor(NewArgc - 1, NewArgv + 1, &edit_argc, + &edit_argv, NULL, &env_editor, false); + if (safe_cmnd == NULL) { +- if (errno != ENOENT) ++ 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; +- 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; ++ } + } + /* find_editor() already g/c'd edit_argv[] */ + sudoers_gc_remove(GC_PTR, NewArgv); +diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c +index 82f7f9e56..425071afd 100644 +--- a/plugins/sudoers/visudo.c ++++ b/plugins/sudoers/visudo.c +@@ -301,7 +301,7 @@ static char * + get_editor(int *editor_argc, char ***editor_argv) + { + char *editor_path = NULL, **allowlist = NULL; +- const char *env_editor; ++ const char *env_editor = NULL; + static char *files[] = { "+1", "sudoers" }; + unsigned int allowlist_len = 0; + debug_decl(get_editor, SUDOERS_DEBUG_UTIL); +@@ -335,7 +335,11 @@ get_editor(int *editor_argc, char ***editor_argv) + if (editor_path == NULL) { + if (def_env_editor && env_editor != NULL) { + /* We are honoring $EDITOR so this is a fatal error. */ +- sudo_fatalx(U_("specified editor (%s) doesn't exist"), env_editor); ++ if (errno == ENOENT) { ++ sudo_warnx(U_("specified editor (%s) doesn't exist"), ++ env_editor); ++ } ++ exit(EXIT_FAILURE); + } + sudo_fatalx(U_("no editor found (editor path = %s)"), def_editor); + } +-- +2.27.0 + diff --git a/backport-CVE-2023-27320.patch b/backport-CVE-2023-27320.patch new file mode 100644 index 0000000000000000000000000000000000000000..6bdd17447f0cc04a14994b6c65cc0d183baff95d --- /dev/null +++ b/backport-CVE-2023-27320.patch @@ -0,0 +1,38 @@ +diff --git a/plugins/sudoers/match_command.c b/plugins/sudoers/match_command.c +index ad9db1e..f1c09bd 100644 +--- a/plugins/sudoers/match_command.c ++++ b/plugins/sudoers/match_command.c +@@ -712,12 +712,16 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args, + /* Rule-specific runchroot, reset user_cmnd and user_stat. */ + int status; + ++ /* Save old user_cmnd first, set_cmnd_path() will free it. */ + saved_user_cmnd = user_cmnd; ++ user_cmnd = NULL; + if (user_stat != NULL) + saved_user_stat = *user_stat; + status = set_cmnd_path(runchroot); +- if (status != FOUND) ++ if (status != FOUND) { ++ user_cmnd = saved_user_cmnd; + saved_user_cmnd = NULL; ++ } + if (info != NULL) + info->status = status; + } +diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c +index 55f44d6..b8b2bc5 100644 +--- a/plugins/sudoers/visudo.c ++++ b/plugins/sudoers/visudo.c +@@ -230,7 +230,9 @@ main(int argc, char *argv[]) + } + + /* Mock up a fake sudo_user struct. */ +- user_cmnd = user_base = ""; ++ user_cmnd = user_base = strdup("true"); ++ if (user_cmnd == NULL) ++ sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + if (geteuid() == 0) { + const char *user = getenv("SUDO_USER"); + if (user != NULL && *user != '\0') + diff --git a/backport-CVE-2023-28486_CVE-2023-28487.patch b/backport-CVE-2023-28486_CVE-2023-28487.patch new file mode 100644 index 0000000000000000000000000000000000000000..41c742552ce6744af8cda445919cdf90ddeeee5d --- /dev/null +++ b/backport-CVE-2023-28486_CVE-2023-28487.patch @@ -0,0 +1,748 @@ +From 334daf92b31b79ce68ed75e2ee14fca265f029ca Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Wed, 18 Jan 2023 08:21:34 -0700 +Subject: [PATCH] Escape control characters in log messages and "sudoreplay -l" + output. The log message contains user-controlled strings that could include + things like terminal control characters. Space characters in the command + path are now also escaped. + +Command line arguments that contain spaces are surrounded with +single quotes and any literal single quote or backslash characters +are escaped with a backslash. This makes it possible to distinguish +multiple command line arguments from a single argument that contains +spaces. + +Issue found by Matthieu Barjole and Victor Cutillas of Synacktiv +(https://synacktiv.com). + +--- + include/sudo_lbuf.h | 7 ++ + lib/eventlog/eventlog.c | 210 +++++++++++------------------------ + lib/iolog/iolog_json.c | 29 ----- + lib/util/lbuf.c | 106 ++++++++++++++++++ + lib/util/util.exp.in | 1 + + plugins/sudoers/sudoreplay.c | 137 ++++++++++++++++++++--- + 6 files changed, 300 insertions(+), 190 deletions(-) + +diff --git a/include/sudo_lbuf.h b/include/sudo_lbuf.h +index c0a20c5..f52d59c 100644 +--- a/include/sudo_lbuf.h ++++ b/include/sudo_lbuf.h +@@ -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_v1(struct sudo_lbuf *lbuf); + #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 --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c +index 314140c..a56b1d0 100644 +--- a/lib/eventlog/eventlog.c ++++ b/lib/eventlog/eventlog.c +@@ -1,7 +1,7 @@ + /* + * SPDX-License-Identifier: ISC + * +- * Copyright (c) 1994-1996, 1998-2021 Todd C. Miller ++ * Copyright (c) 1994-1996, 1998-2023 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 +@@ -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, 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; + const char *tty, *tsid = NULL; + char exit_str[(((sizeof(int) * 8) + 2) / 3) + 2]; + char sessid[7], offsetstr[64] = ""; +- 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. */ +@@ -153,165 +144,88 @@ new_logline(int event_type, int flags, struct eventlog_args *args, + } + + /* +- * Compute line length +- */ +- 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) + strlen(offsetstr); +- } +- 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. ++ * Format the log line as an lbuf, escaping control characters in ++ * octal form (#0nn). Error checking (ENOMEM) is done at the end. + */ +- 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, offsetstr, 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%s ; ", tsid, ++ offsetstr); ++ } ++ 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", ++ args->signal_name); + } +- if (strlcat(line, " ; ", len) >= len || +- strlcat(line, LL_EXIT_STR, len) >= len || +- strlcat(line, exit_str, len) >= len) +- goto toobig; ++ (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 --git a/lib/iolog/iolog_json.c b/lib/iolog/iolog_json.c +index a27fe4d..408bc31 100644 +--- a/lib/iolog/iolog_json.c ++++ b/lib/iolog/iolog_json.c +@@ -489,35 +489,6 @@ iolog_parse_json_object(struct json_object *object, struct eventlog *evlog) + } + } + +- /* Merge cmd and argv as sudoreplay expects. */ +- if (evlog->command != NULL && evlog->argv != NULL && evlog->argv[0] != 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 --git a/lib/util/lbuf.c b/lib/util/lbuf.c +index f17ae0c..a9a57c9 100644 +--- a/lib/util/lbuf.c ++++ b/lib/util/lbuf.c +@@ -87,6 +87,112 @@ sudo_lbuf_expand(struct sudo_lbuf *lbuf, int extra) + debug_return_bool(true); + } + ++/* ++ * 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 --git a/lib/util/util.exp.in b/lib/util/util.exp.in +index 5b760fa..c3829ec 100644 +--- a/lib/util/util.exp.in ++++ b/lib/util/util.exp.in +@@ -98,6 +98,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 --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c +index f32d44e..7914135 100644 +--- a/plugins/sudoers/sudoreplay.c ++++ b/plugins/sudoers/sudoreplay.c +@@ -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" +@@ -373,6 +374,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)) +@@ -1312,11 +1317,57 @@ parse_expr(struct search_node_list *head, char *argv[], bool sub_expr) + 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); + +@@ -1350,13 +1401,15 @@ match_expr(struct search_node_list *head, struct eventlog *evlog, bool last_matc + 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, >=); +@@ -1377,12 +1430,13 @@ match_expr(struct search_node_list *head, struct eventlog *evlog, bool last_matc + } + + 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) +@@ -1409,18 +1463,71 @@ 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("HOST=%s ; ", evlog->submithost); +- 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); + } +@@ -1440,6 +1547,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) + 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; +@@ -1451,6 +1559,8 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) + #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); +@@ -1511,7 +1621,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) + /* 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'; +@@ -1522,6 +1632,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) + } + free(sessions); + } ++ sudo_lbuf_destroy(&lbuf); + + debug_return_int(0); + } +-- +2.27.0 + + diff --git a/backport-Fix-CVE-2022-43995-potential-heap-overflow-for-passwords.patch b/backport-Fix-CVE-2022-43995-potential-heap-overflow-for-passwords.patch new file mode 100644 index 0000000000000000000000000000000000000000..6075d90d2a2d69083833f962d1c6763d7848b93f --- /dev/null +++ b/backport-Fix-CVE-2022-43995-potential-heap-overflow-for-passwords.patch @@ -0,0 +1,55 @@ +From bd209b9f16fcd1270c13db27ae3329c677d48050 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Fri, 28 Oct 2022 07:29:55 -0600 +Subject: [PATCH] Fix CVE-2022-43995, potential heap overflow for passwords < 8 + characters. Starting with sudo 1.8.0 the plaintext password buffer is + dynamically sized so it is not safe to assume that it is at least 9 bytes in + size. Found by Hugo Lefeuvre (University of Manchester) with ConfFuzz. + +Conflict:NA +Reference:https://github.com/sudo-project/sudo/commit/bd209b9f16fcd1270c13db27ae3329c677d48050 +--- + plugins/sudoers/auth/passwd.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c +index b2046eca2..0416861e9 100644 +--- a/plugins/sudoers/auth/passwd.c ++++ b/plugins/sudoers/auth/passwd.c +@@ -63,7 +63,7 @@ sudo_passwd_init(struct passwd *pw, sudo_auth *auth) + int + sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback) + { +- char sav, *epass; ++ char des_pass[9], *epass; + char *pw_epasswd = auth->data; + size_t pw_len; + int matched = 0; +@@ -75,12 +75,12 @@ sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_c + + /* + * Truncate to 8 chars if standard DES since not all crypt()'s do this. +- * If this turns out not to be safe we will have to use OS #ifdef's (sigh). + */ +- sav = pass[8]; + pw_len = strlen(pw_epasswd); +- if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len)) +- pass[8] = '\0'; ++ if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len)) { ++ strlcpy(des_pass, pass, sizeof(des_pass)); ++ pass = des_pass; ++ } + + /* + * Normal UN*X password check. +@@ -88,7 +88,6 @@ sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_c + * only compare the first DESLEN characters in that case. + */ + epass = (char *) crypt(pass, pw_epasswd); +- pass[8] = sav; + if (epass != NULL) { + if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN) + matched = !strncmp(pw_epasswd, epass, DESLEN); +-- +2.27.0 + diff --git a/backport-Fix-a-NOPASSWD-issue-with-a-non-existent-command-whe.patch b/backport-Fix-a-NOPASSWD-issue-with-a-non-existent-command-whe.patch new file mode 100644 index 0000000000000000000000000000000000000000..23e12338790d4511ec6e17a8230d8267947bb5f3 --- /dev/null +++ b/backport-Fix-a-NOPASSWD-issue-with-a-non-existent-command-whe.patch @@ -0,0 +1,43 @@ +From 5a59ce159e0c17fb35474c9c516d97703b338027 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Thu, 7 Jul 2022 20:11:44 -0600 +Subject: [PATCH] Fix a NOPASSWD issue with a non-existent command when + fdexec=always In command_matches_all(), if the command is fully-qualified and + open_cmnd() return false, only treat it as an error if we are able to stat(2) + the command. For "sudo ALL" a non-existent command is not an error. + +Reference: https://github.com/sudo-project/sudo/commit/5a59ce159e0c17fb35474c9c516d97703b338027 +Conflict: match_command.c +--- + plugins/sudoers/match_command.c | 4 +++++-- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/plugins/sudoers/match_command.c b/plugins/sudoers/match_command.c +index 6d8b3a6..e020e81 100644 +--- a/plugins/sudoers/match_command.c ++++ b/plugins/sudoers/match_command.c +@@ -353,11 +353,15 @@ command_matches_all(const char *runchroot, + + if (user_cmnd[0] == '/') { + /* Open the file for fdexec or for digest matching. */ +- if (!open_cmnd(user_cmnd, runchroot, digests, &fd)) +- goto bad; ++ bool open_error = !open_cmnd(user_cmnd, runchroot, digests, &fd); + #ifndef SUDOERS_NAME_MATCH +- if (!do_stat(fd, user_cmnd, runchroot, intercepted, NULL)) +- goto bad; ++ /* A non-existent file is not an error for "sudo ALL". */ ++ if (do_stat(fd, user_cmnd, runchroot, intercepted, NULL)) { ++ if (open_error) { ++ /* File exists but we couldn't open it above? */ ++ goto bad; ++ } ++ } + #endif + } + +-- +2.33.0 + + + diff --git a/backport-Fix-a-clang-analyzer-14-warning-about-a-possible-NUL.patch b/backport-Fix-a-clang-analyzer-14-warning-about-a-possible-NUL.patch new file mode 100644 index 0000000000000000000000000000000000000000..967f47d064a6bcc4db763e67bb1e2d3846895f35 --- /dev/null +++ b/backport-Fix-a-clang-analyzer-14-warning-about-a-possible-NUL.patch @@ -0,0 +1,26 @@ +From bfc6249902d842626058e74074832930feaf2f80 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Wed, 29 Jun 2022 11:18:16 -0600 +Subject: [PATCH] Fix a clang analyzer 14 warning about a possible NULL deref. + +--- + lib/protobuf-c/protobuf-c.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/lib/protobuf-c/protobuf-c.c b/lib/protobuf-c/protobuf-c.c +index 3cc22c5f0..9ee355df5 100644 +--- a/lib/protobuf-c/protobuf-c.c ++++ b/lib/protobuf-c/protobuf-c.c +@@ -3246,6 +3246,9 @@ protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, + /* allocate space for repeated fields, also check that all required fields have been set */ + for (f = 0; f < desc->n_fields; f++) { + const ProtobufCFieldDescriptor *field = desc->fields + f; ++ if (field == NULL) { ++ continue; ++ } + if (field->label == PROTOBUF_C_LABEL_REPEATED) { + size_t siz = + sizeof_elt_in_repeated_array(field->type); +-- +2.33.0 + diff --git a/backport-Fix-a-potential-use-after-free-bug-with-cvtsudoers-f.patch b/backport-Fix-a-potential-use-after-free-bug-with-cvtsudoers-f.patch new file mode 100644 index 0000000000000000000000000000000000000000..2af4b2c280afa9e1626d9bf11985f003c13df9f2 --- /dev/null +++ b/backport-Fix-a-potential-use-after-free-bug-with-cvtsudoers-f.patch @@ -0,0 +1,37 @@ +From 264326de571e0eff1d8003f882bad4cdf1a9230d Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Thu, 10 Nov 2022 14:55:56 -0700 +Subject: [PATCH] Fix a potential use-after-free bug with cvtsudoers filtering. + In role_to_sudoers() when merging a privilege to the previous one where the + runas lists are the same we need to re-use the runas lists of the last + command in the previous privilege, not the first. Otherwise, the check in + free_cmndspec() will not notice the re-used runas lists. Reported/analyzed + by Sohom Datta. GitHub issue #198. + +--- + plugins/sudoers/parse_ldif.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/plugins/sudoers/parse_ldif.c b/plugins/sudoers/parse_ldif.c +index 5d2a79163..2b7109294 100644 +--- a/plugins/sudoers/parse_ldif.c ++++ b/plugins/sudoers/parse_ldif.c +@@ -432,11 +432,11 @@ role_to_sudoers(struct sudoers_parse_tree *parse_tree, struct sudo_role *role, + struct privilege *prev_priv = TAILQ_LAST(&us->privileges, privilege_list); + if (reuse_runas) { + /* Runas users and groups same if as in previous privilege. */ +- struct member_list *runasuserlist = +- TAILQ_FIRST(&prev_priv->cmndlist)->runasuserlist; +- struct member_list *runasgrouplist = +- TAILQ_FIRST(&prev_priv->cmndlist)->runasgrouplist; + struct cmndspec *cmndspec = TAILQ_FIRST(&priv->cmndlist); ++ const struct cmndspec *prev_cmndspec = ++ TAILQ_LAST(&prev_priv->cmndlist, cmndspec_list); ++ struct member_list *runasuserlist = prev_cmndspec->runasuserlist; ++ struct member_list *runasgrouplist = prev_cmndspec->runasgrouplist; + + /* Free duplicate runas lists. */ + if (cmndspec->runasuserlist != NULL) { +-- +2.27.0 + diff --git a/backport-Fix-incorrect-SHA384-512-digest-calculation.patch b/backport-Fix-incorrect-SHA384-512-digest-calculation.patch new file mode 100644 index 0000000000000000000000000000000000000000..04f72d418c88ddf56c1611fc8b0327d555229b14 --- /dev/null +++ b/backport-Fix-incorrect-SHA384-512-digest-calculation.patch @@ -0,0 +1,29 @@ +From e4f08157b6693b956fe9c7c987bc3eeac1abb2cc Mon Sep 17 00:00:00 2001 +From: Tim Shearer +Date: Tue, 2 Aug 2022 08:48:32 -0400 +Subject: [PATCH] Fix incorrect SHA384/512 digest calculation. + +Resolves an issue where certain message sizes result in an incorrect +checksum. Specifically, when: +(n*8) mod 1024 == 896 +where n is the file size in bytes. +--- + lib/util/sha2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/util/sha2.c b/lib/util/sha2.c +index b7a28cca8..f769f77f2 100644 +--- a/lib/util/sha2.c ++++ b/lib/util/sha2.c +@@ -490,7 +490,7 @@ SHA512Pad(SHA2_CTX *ctx) + SHA512Update(ctx, (uint8_t *)"\200", 1); + + /* Pad message such that the resulting length modulo 1024 is 896. */ +- while ((ctx->count[0] & 1008) != 896) ++ while ((ctx->count[0] & 1016) != 896) + SHA512Update(ctx, (uint8_t *)"\0", 1); + + /* Append length of message in bits and do final SHA512Transform(). */ +-- +2.33.0 + diff --git a/backport-Fix-issue-protobuf-c-499-unsigned-integer-overflow.patch b/backport-Fix-issue-protobuf-c-499-unsigned-integer-overflow.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef9bc2cc5ab5ceed016d4b59fb3f6ee1ae6ecf4d --- /dev/null +++ b/backport-Fix-issue-protobuf-c-499-unsigned-integer-overflow.patch @@ -0,0 +1,37 @@ +From 263fdc6b067bd892df654377c0ea051289fce33f Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Mon, 6 Jun 2022 20:15:03 -0600 +Subject: [PATCH] Fix issue protobuf-c#499: unsigned integer overflow + Signed-off-by: 10054172 + +--- + lib/protobuf-c/protobuf-c.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/lib/protobuf-c/protobuf-c.c b/lib/protobuf-c/protobuf-c.c +index 96b750650..73e120046 100644 +--- a/lib/protobuf-c/protobuf-c.c ++++ b/lib/protobuf-c/protobuf-c.c +@@ -2619,11 +2619,14 @@ parse_required_member(ScannedMember *scanned_member, + return FALSE; + + def_mess = scanned_member->field->default_value; +- subm = protobuf_c_message_unpack(scanned_member->field->descriptor, +- allocator, +- len - pref_len, +- data + pref_len); +- ++ if (len > pref_len) { ++ subm = protobuf_c_message_unpack(scanned_member->field->descriptor, ++ allocator, ++ len - pref_len, ++ data + pref_len); ++ } else { ++ subm = NULL; ++ } + if (maybe_clear && + *pmessage != NULL && + *pmessage != def_mess) +-- +2.33.0 + diff --git a/backport-Fix-memory-leak-of-pass-in-converse.patch b/backport-Fix-memory-leak-of-pass-in-converse.patch new file mode 100644 index 0000000000000000000000000000000000000000..dde3bcf0a3d51150623dc100bb43505ce8f1312a --- /dev/null +++ b/backport-Fix-memory-leak-of-pass-in-converse.patch @@ -0,0 +1,26 @@ +From f5cae905ca1a9f686f80aea45a34cea50fec0534 Mon Sep 17 00:00:00 2001 +From: modric +Date: Thu, 17 Nov 2022 16:08:59 +0800 +Subject: [PATCH] Fix memory leak of pass in converse(). + +--- + plugins/sudoers/auth/pam.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c +index 339b7a5..f5580ea 100644 +--- a/plugins/sudoers/auth/pam.c ++++ b/plugins/sudoers/auth/pam.c +@@ -722,7 +722,8 @@ converse(int num_msg, PAM_CONST struct pam_message **msg, + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "password longer than %d", PAM_MAX_RESP_SIZE); + ret = PAM_CONV_ERR; +- explicit_bzero(pass, strlen(pass)); ++ freezero(pass, strlen(pass)); ++ pass = NULL; + goto done; + } + reply[n].resp = pass; /* auth_getpass() malloc's a copy */ +-- +2.27.0 + diff --git a/backport-Fix-potential-signed-integer-overflow-on-32-bit-CPUs.patch b/backport-Fix-potential-signed-integer-overflow-on-32-bit-CPUs.patch new file mode 100644 index 0000000000000000000000000000000000000000..edbc850eae725ed0f25282c2523ccb4fa27c7926 --- /dev/null +++ b/backport-Fix-potential-signed-integer-overflow-on-32-bit-CPUs.patch @@ -0,0 +1,71 @@ +From dc8311dae99c2e6d60ecd3db6730fe84c6fe9d5b Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Fri, 27 May 2022 15:47:32 -0600 +Subject: [PATCH] Fix potential signed integer overflow on 32-bit CPUs. + Converting fractional minutes to nanoseconds could overflow a 32-bit integer, + use long long instead. + +--- + plugins/sudoers/defaults.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c +index d5bd8080d..ec6b64fe9 100644 +--- a/plugins/sudoers/defaults.c ++++ b/plugins/sudoers/defaults.c +@@ -935,38 +935,38 @@ store_timespec(const char *str, struct sudo_defs_types *def) + + sudo_timespecclear(&ts); + if (str != NULL) { +- /* Convert from minutes to timespec. */ ++ /* Convert from minutes to seconds. */ + if (*str == '+' || *str == '-') + sign = *str++; + while (*str != '\0' && *str != '.') { + if (!isdigit((unsigned char)*str)) + debug_return_bool(false); /* invalid number */ + +- /* Verify (ts.tv_sec * 10) + digit <= TIME_T_MAX. */ +- i = *str++ - '0'; ++ /* Verify (ts.tv_sec * 10) + (digit * 60) <= TIME_T_MAX. */ ++ i = (*str++ - '0') * 60L; + if (ts.tv_sec > (TIME_T_MAX - i) / 10) + debug_return_bool(false); /* overflow */ + ts.tv_sec *= 10; + ts.tv_sec += i; + } + if (*str++ == '.') { +- /* Convert optional fractional component to nanosecs. */ ++ long long nsec = 0; ++ ++ /* Convert optional fractional component to seconds and nanosecs. */ + for (i = 100000000; i > 0; i /= 10) { + if (*str == '\0') + break; + if (!isdigit((unsigned char)*str)) + debug_return_bool(false); /* invalid number */ +- ts.tv_nsec += i * (*str++ - '0'); ++ nsec += i * (*str++ - '0') * 60LL; + } +- } +- /* Convert from minutes to seconds. */ +- if (ts.tv_sec > TIME_T_MAX / 60) +- debug_return_bool(false); /* overflow */ +- ts.tv_sec *= 60; +- ts.tv_nsec *= 60; +- while (ts.tv_nsec >= 1000000000) { +- ts.tv_sec++; +- ts.tv_nsec -= 1000000000; ++ while (nsec >= 1000000000) { ++ if (ts.tv_sec == TIME_T_MAX) ++ debug_return_bool(false); /* overflow */ ++ ts.tv_sec++; ++ nsec -= 1000000000; ++ } ++ ts.tv_nsec = nsec; + } + } + if (sign == '-') { +-- +2.33.0 + diff --git a/backport-Fix-regression-with-zero-length-messages-introduced-.patch b/backport-Fix-regression-with-zero-length-messages-introduced-.patch new file mode 100644 index 0000000000000000000000000000000000000000..485884b985ae9f2ed1c9dec80a9abf4661f8973d --- /dev/null +++ b/backport-Fix-regression-with-zero-length-messages-introduced-.patch @@ -0,0 +1,26 @@ +From b6a6451482a3ff5e30f43ef888159d4b0d39143b Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Thu, 9 Jun 2022 07:34:55 -0600 +Subject: [PATCH] Fix regression with zero-length messages introduced in + protobuf-c PR 500. + +--- + lib/protobuf-c/protobuf-c.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/protobuf-c/protobuf-c.c b/lib/protobuf-c/protobuf-c.c +index 9d56e1fec..3cc22c5f0 100644 +--- a/lib/protobuf-c/protobuf-c.c ++++ b/lib/protobuf-c/protobuf-c.c +@@ -2618,7 +2618,7 @@ parse_required_member(ScannedMember *scanned_member, + return FALSE; + + def_mess = scanned_member->field->default_value; +- if (len > pref_len) { ++ if (len >= pref_len) { + subm = protobuf_c_message_unpack(scanned_member->field->descriptor, + allocator, + len - pref_len, +-- +2.33.0 + diff --git a/backport-Fix-typo-we-should-define-SSIZE_MAX-if-it-is-not-def.patch b/backport-Fix-typo-we-should-define-SSIZE_MAX-if-it-is-not-def.patch new file mode 100644 index 0000000000000000000000000000000000000000..5180a3852973884914370ce045c0095f070f901a --- /dev/null +++ b/backport-Fix-typo-we-should-define-SSIZE_MAX-if-it-is-not-def.patch @@ -0,0 +1,29 @@ +From 169e049821a68449b1c73918f13765ea1142b7f0 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Fri, 10 Jun 2022 09:34:33 -0600 +Subject: [PATCH] =?UTF-8?q?Fix=20typo,=20we=20should=20define=20SSIZE=5FMA?= + =?UTF-8?q?X=C2=A0if=20it=20is=20not=20defined.?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + include/sudo_compat.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/sudo_compat.h b/include/sudo_compat.h +index d62dea7d6..ee3c22962 100644 +--- a/include/sudo_compat.h ++++ b/include/sudo_compat.h +@@ -157,7 +157,7 @@ + #endif + + #if defined(HAVE_DECL_SSIZE_MAX) && !HAVE_DECL_SSIZE_MAX +-# define SIZE_MAX LONG_MAX ++# define SSIZE_MAX LONG_MAX + #endif + + #if defined(HAVE_DECL_PATH_MAX) && !HAVE_DECL_PATH_MAX +-- +2.33.0 + diff --git a/backport-cvtsudoers-Prevent-sudo-from-reading-into-undefined-.patch b/backport-cvtsudoers-Prevent-sudo-from-reading-into-undefined-.patch new file mode 100644 index 0000000000000000000000000000000000000000..182fbbdf75c3c8654c033937ac0c6e06e94ae3c4 --- /dev/null +++ b/backport-cvtsudoers-Prevent-sudo-from-reading-into-undefined-.patch @@ -0,0 +1,25 @@ +From 902271f441f61506392588fc26db992e64ae4ecd Mon Sep 17 00:00:00 2001 +From: Sohom +Date: Wed, 9 Nov 2022 23:20:12 +0530 +Subject: [PATCH] [cvtsudoers]: Prevent sudo from reading into undefined memory + +--- + plugins/sudoers/parse_ldif.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plugins/sudoers/parse_ldif.c b/plugins/sudoers/parse_ldif.c +index 6c2b74aa0..5d2a79163 100644 +--- a/plugins/sudoers/parse_ldif.c ++++ b/plugins/sudoers/parse_ldif.c +@@ -688,7 +688,7 @@ sudoers_parse_ldif(struct sudoers_parse_tree *parse_tree, + if (strncasecmp(attr, "cn=", 3) == 0) { + for (attr += 3; *attr != '\0'; attr++) { + /* Handle escaped ',' chars. */ +- if (*attr == '\\') ++ if (*attr == '\\' && attr[1] != '\0') + attr++; + if (*attr == ',') { + attr++; +-- +2.27.0 + diff --git a/backport-sudo_ldap_parse_options-fix-memory-leak-of-sudoRole-.patch b/backport-sudo_ldap_parse_options-fix-memory-leak-of-sudoRole-.patch new file mode 100644 index 0000000000000000000000000000000000000000..5adf9fa17615f1e8ba0ae9a604aae390f17bcdee --- /dev/null +++ b/backport-sudo_ldap_parse_options-fix-memory-leak-of-sudoRole-.patch @@ -0,0 +1,88 @@ +From 22a01410bdac0ead284e0611b7814a56973a860a Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Thu, 24 Feb 2022 07:56:38 -0700 +Subject: [PATCH] sudo_ldap_parse_options: fix memory leak of sudoRole cn + string. Coverity CID 249976 + +--- + plugins/sudoers/ldap.c | 41 ++++++++++++++++++----------------------- + 1 file changed, 18 insertions(+), 23 deletions(-) + +diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c +index e3c47b9bc..13e74160b 100644 +--- a/plugins/sudoers/ldap.c ++++ b/plugins/sudoers/ldap.c +@@ -421,38 +421,31 @@ sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry, int *rc) + static bool + sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry, struct defaults_list *defs) + { +- struct berval **bv, **p; +- char *cn, *cp, *source = NULL; ++ struct berval **p, **bv = NULL; ++ char *cp, *cn = NULL, *source = NULL; + bool ret = false; + int rc; + debug_decl(sudo_ldap_parse_options, SUDOERS_DEBUG_LDAP); + + bv = sudo_ldap_get_values_len(ld, entry, "sudoOption", &rc); + if (bv == NULL) { +- if (rc == LDAP_NO_MEMORY) { +- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); +- debug_return_bool(false); +- } ++ if (rc == LDAP_NO_MEMORY) ++ goto oom; + debug_return_bool(true); + } + + /* Use sudoRole in place of file name in defaults. */ + cn = sudo_ldap_get_first_rdn(ld, entry, &rc); + if (cn == NULL) { +- if (rc == LDAP_NO_MEMORY) { +- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); +- goto done; +- } +- } +- if (asprintf(&cp, "sudoRole %s", cn ? cn : "UNKNOWN") == -1) { +- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); +- goto done; +- } +- if ((source = sudo_rcstr_dup(cp)) == NULL) { +- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); +- free(cp); +- goto done; ++ if (rc == LDAP_NO_MEMORY) ++ goto oom; + } ++ if (asprintf(&cp, "sudoRole %s", cn ? cn : "UNKNOWN") == -1) ++ goto oom; ++ source = sudo_rcstr_dup(cp); ++ free(cp); ++ if (source == NULL) ++ goto oom; + + /* Walk through options, appending to defs. */ + for (p = bv; *p != NULL; p++) { +@@ -460,13 +453,15 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry, struct defaults_list *defs + int op; + + op = sudo_ldap_parse_option((*p)->bv_val, &var, &val); +- if (!append_default(var, val, op, source, defs)) { +- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); +- goto done; +- } ++ if (!append_default(var, val, op, source, defs)) ++ goto oom; + } + + ret = true; ++ goto done; ++ ++oom: ++ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + + done: + sudo_rcstr_delref(source); +-- +2.33.0 + diff --git a/backport-sudo_passwd_cleanup-Set-auth-data-to-NULL-after-free.patch b/backport-sudo_passwd_cleanup-Set-auth-data-to-NULL-after-free.patch new file mode 100644 index 0000000000000000000000000000000000000000..18e56e5456809a3e153dc2b468e3c20ca00bf075 --- /dev/null +++ b/backport-sudo_passwd_cleanup-Set-auth-data-to-NULL-after-free.patch @@ -0,0 +1,35 @@ +From b3834bbf248f3376ada8fc44166cba38c8ad4bcf Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Thu, 17 Nov 2022 08:10:35 -0700 +Subject: [PATCH] sudo_passwd_cleanup: Set auth->data to NULL after freeing. + GitHub issue #201 + +--- + plugins/sudoers/auth/passwd.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c +index 89da96ff6..6967e4fff 100644 +--- a/plugins/sudoers/auth/passwd.c ++++ b/plugins/sudoers/auth/passwd.c +@@ -117,11 +117,14 @@ sudo_passwd_verify(struct passwd *pw, const char *pass, sudo_auth *auth, struct + int + sudo_passwd_cleanup(struct passwd *pw, sudo_auth *auth, bool force) + { +- char *pw_epasswd = auth->data; + debug_decl(sudo_passwd_cleanup, SUDOERS_DEBUG_AUTH); + +- if (pw_epasswd != NULL) +- freezero(pw_epasswd, strlen(pw_epasswd)); ++ if (auth->data != NULL) { ++ /* Zero out encrypted password before freeing. */ ++ size_t len = strlen((char *)auth->data); ++ freezero(auth->data, len); ++ auth->data = NULL; ++ } + + debug_return_int(AUTH_SUCCESS); + } +-- +2.27.0 + diff --git a/backport-sudo_passwd_verify-zero-out-des_pass-before-returnin.patch b/backport-sudo_passwd_verify-zero-out-des_pass-before-returnin.patch new file mode 100644 index 0000000000000000000000000000000000000000..a232dc9081a070462caf02ee3e33fefc6163ac39 --- /dev/null +++ b/backport-sudo_passwd_verify-zero-out-des_pass-before-returnin.patch @@ -0,0 +1,25 @@ +From 9f948224acb911cbec1ed9041887c1fe62c59877 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Tue, 8 Nov 2022 13:17:11 -0700 +Subject: [PATCH] sudo_passwd_verify: zero out des_pass before returning. + +--- + plugins/sudoers/auth/passwd.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c +index 636c07bab..89da96ff6 100644 +--- a/plugins/sudoers/auth/passwd.c ++++ b/plugins/sudoers/auth/passwd.c +@@ -95,6 +95,8 @@ sudo_passwd_verify(struct passwd *pw, const char *pass, sudo_auth *auth, struct + matched = !strcmp(pw_epasswd, epass); + } + ++ explicit_bzero(des_pass, sizeof(des_pass)); ++ + debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE); + } + #else +-- +2.33.0 + diff --git a/backport-sudo_rcstr_dup-Fix-potential-NULL-pointer-deref.patch b/backport-sudo_rcstr_dup-Fix-potential-NULL-pointer-deref.patch new file mode 100644 index 0000000000000000000000000000000000000000..2abbb8a69610641eac47eabeca63ee94a30f1981 --- /dev/null +++ b/backport-sudo_rcstr_dup-Fix-potential-NULL-pointer-deref.patch @@ -0,0 +1,29 @@ +From dbfd84301a9316018f7c5e42ff5b3a19dd13e5c5 Mon Sep 17 00:00:00 2001 +From: modric +Date: Tue, 22 Nov 2022 10:12:29 +0800 +Subject: [PATCH] sudo_rcstr_dup: Fix potential NULL pointer deref + +--- + lib/util/rcstr.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/lib/util/rcstr.c b/lib/util/rcstr.c +index d990a99e9..08b00bcd7 100644 +--- a/lib/util/rcstr.c ++++ b/lib/util/rcstr.c +@@ -49,8 +49,10 @@ sudo_rcstr_dup(const char *src) + debug_decl(sudo_rcstr_dup, SUDO_DEBUG_UTIL); + + dst = sudo_rcstr_alloc(len); +- memcpy(dst, src, len); +- dst[len] = '\0'; ++ if (dst != NULL) { ++ memcpy(dst, src, len); ++ dst[len] = '\0'; ++ } + debug_return_ptr(dst); + } + +-- +2.27.0 + diff --git a/sudo-1.9.5p2.tar.gz b/sudo-1.9.8p2.tar.gz similarity index 35% rename from sudo-1.9.5p2.tar.gz rename to sudo-1.9.8p2.tar.gz index f7a59709219e049b2e9d1fee5c3bef9a5e79c053..402590fa1ea616a1041703d0522b1e050955ffc8 100644 Binary files a/sudo-1.9.5p2.tar.gz and b/sudo-1.9.8p2.tar.gz differ diff --git a/sudo.spec b/sudo.spec index 905e6469ea27dff853483e34c141bdf1c7a6bcc2..1659fc9f24a2c218225a3b9e46df4c24fdff91e9 100644 --- a/sudo.spec +++ b/sudo.spec @@ -1,6 +1,6 @@ Name: sudo -Version: 1.9.5p2 -Release: 1 +Version: 1.9.8p2 +Release: 12 Summary: Allows restricted root access for specified users License: ISC URL: http://www.courtesan.com/sudo/ @@ -10,6 +10,28 @@ Source1: sudoers Source2: sudo Source3: sudo-i +Patch0: backport-0001-CVE-2022-37434.patch +Patch1: backport-0002-CVE-2022-37434.patch +Patch2: backport-CVE-2022-33070.patch +Patch3: backport-Fix-CVE-2022-43995-potential-heap-overflow-for-passwords.patch +Patch4: backport-Fix-incorrect-SHA384-512-digest-calculation.patch +Patch5: backport-sudo_passwd_verify-zero-out-des_pass-before-returnin.patch +Patch6: backport-Fix-issue-protobuf-c-499-unsigned-integer-overflow.patch +Patch7: backport-Fix-regression-with-zero-length-messages-introduced-.patch +Patch8: backport-Fix-typo-we-should-define-SSIZE_MAX-if-it-is-not-def.patch +Patch9: backport-Fix-a-clang-analyzer-14-warning-about-a-possible-NUL.patch +Patch10: backport-Fix-potential-signed-integer-overflow-on-32-bit-CPUs.patch +Patch11: backport-sudo_ldap_parse_options-fix-memory-leak-of-sudoRole-.patch +Patch12: backport-cvtsudoers-Prevent-sudo-from-reading-into-undefined-.patch +Patch13: backport-Fix-a-potential-use-after-free-bug-with-cvtsudoers-f.patch +Patch14: backport-Fix-memory-leak-of-pass-in-converse.patch +Patch15: backport-sudo_passwd_cleanup-Set-auth-data-to-NULL-after-free.patch +Patch16: backport-sudo_rcstr_dup-Fix-potential-NULL-pointer-deref.patch +Patch17: backport-CVE-2023-22809.patch +Patch18: backport-Fix-a-NOPASSWD-issue-with-a-non-existent-command-whe.patch +Patch19: backport-CVE-2023-27320.patch +Patch20: backport-CVE-2023-28486_CVE-2023-28487.patch + Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: pam Recommends: vim-minimal @@ -17,7 +39,7 @@ Requires(post): coreutils BuildRequires: pam-devel groff openldap-devel flex bison automake autoconf libtool BuildRequires: audit-libs-devel libcap-devel libselinux-devel sendmail gettext zlib-devel -BuildRequires: chrpath git openssl-devel python3-devel +BuildRequires: chrpath git %description Sudo is a program designed to allow a sysadmin to give limited root privileges @@ -45,8 +67,10 @@ export CFLAGS="$RPM_OPT_FLAGS -fpie" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" --sbindir=%{_sbindir} \ --libdir=%{_libdir} \ --docdir=%{_pkgdocdir} \ - --enable-openssl \ --disable-root-mailer \ + --disable-intercept \ + --disable-log-server \ + --disable-log-client \ --with-logging=syslog \ --with-logfac=authpriv \ --with-pam \ @@ -58,7 +82,6 @@ export CFLAGS="$RPM_OPT_FLAGS -fpie" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" --with-ldap \ --with-selinux \ --with-passprompt="[sudo] password for %p: " \ - --enable-python \ --with-linux-audit \ --with-sssd @@ -92,7 +115,16 @@ rm -rf $RPM_BUILD_ROOT%{_datadir}/examples/sudo rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sudoers.dist -%chrpath_delete +chrpath -d $RPM_BUILD_ROOT%{_bindir}/sudo +chrpath -d $RPM_BUILD_ROOT%{_bindir}/sudoreplay +chrpath -d $RPM_BUILD_ROOT%{_sbindir}/visudo +chrpath -d $RPM_BUILD_ROOT%{_bindir}/cvtsudoers +chrpath -d $RPM_BUILD_ROOT%{_libexecdir}/sudo/sesh +chrpath -d $RPM_BUILD_ROOT%{_libexecdir}/sudo/sudoers.so +chrpath -d $RPM_BUILD_ROOT%{_libexecdir}/sudo/group_file.so +chrpath -d $RPM_BUILD_ROOT%{_libexecdir}/sudo/system_group.so +chrpath -d $RPM_BUILD_ROOT%{_libexecdir}/sudo/audit_json.so +chrpath -d $RPM_BUILD_ROOT%{_libexecdir}/sudo/sample_approval.so mkdir -p $RPM_BUILD_ROOT/etc/ld.so.conf.d echo "/usr/libexec/sudo" > $RPM_BUILD_ROOT/etc/ld.so.conf.d/%{name}-%{_arch}.conf @@ -128,10 +160,6 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i %attr(0644,root,root) %{_libexecdir}/sudo/audit_json.so %attr(0644,root,root) %{_libexecdir}/sudo/sample_approval.so %attr(0644,root,root) %{_libexecdir}/sudo/libsudo_util.so* -%attr(0644,root,root) %{_libexecdir}/sudo/python_plugin.so -%attr(0640,root,root) %config(noreplace) /etc/sudo_logsrvd.conf -%attr(0755,root,root) %{_sbindir}/sudo_logsrvd -%attr(0755,root,root) %{_sbindir}/sudo_sendlog %dir /var/db/sudo %dir /var/db/sudo/lectured %dir %{_libexecdir}/sudo @@ -153,6 +181,42 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i %exclude %{_pkgdocdir}/ChangeLog %changelog +* Tue Mar 28 2023 wangcheng - 1.9.8p2-11 +- Fix CVE-2023-28486 and CVE-2023-28487 + +* Tue Mar 07 2023 wangyu - 1.9.8p2-10 +- Fix CVE-2023-27320. + +* Wed Feb 01 2023 wangyu - 1.9.8p2-9 +- For "sudo ALL" a non-existent command is not an error. + +* Thu Jan 19 2023 houmingyong - 1.9.8p2-8 +- Fix CVE-2023-22809 + +* Thu Dec 08 2022 wangyu - 1.9.8p2-7 +- Backport patches from upstream community + +* Fri Nov 25 2022 wangyu - 1.9.8p2-6 +- Backport patches from upstream community + +* Wed Nov 23 2022 wangyu - 1.9.8p2-5 +- Backport patches from upstream community + +* Sat Nov 05 2022 wangyu - 1.9.8p2-4 +- Fix CVE-2022-43995 + +* Sat Sep 03 2022 wangyu - 1.9.8p2-3 +- Fix CVE-2022-37434 and CVE-2022-33070 + +* Mon Mar 7 2022 panxiaohe - 1.9.8p2-2 +- remove rpath and runpath of exec files and libraries + +* Tue Dec 14 2021 panxiaohe - 1.9.8p2-1 +- Update to 1.9.8p2 + +* Thu Sep 16 2021 yixiangzhike - 1.9.5p2-2 +- DESC: treat stack exhaustion like memory allocation failure + * Wed Jul 7 2021 panxiaohe - 1.9.5p2-1 - Update to 1.9.5p2