diff -Nru sudo-1.8.16/debian/changelog sudo-1.8.16/debian/changelog --- sudo-1.8.16/debian/changelog 2019-10-11 11:16:34.000000000 +0000 +++ sudo-1.8.16/debian/changelog 2021-01-19 14:48:09.000000000 +0000 @@ -1,3 +1,38 @@ +sudo (1.8.16-0ubuntu1.10) xenial-security; urgency=medium + + * SECURITY UPDATE: dir existence issue via sudoedit race + - debian/patches/CVE-2021-23239.patch: fix potential directory existing + info leak in sudoedit in src/sudo_edit.c. + - CVE-2021-23239 + * SECURITY UPDATE: heap-based buffer overflow + - debian/patches/CVE-2021-3156-pre1.patch: check lock record size in + plugins/sudoers/timestamp.c. + - debian/patches/CVE-2021-3156-pre2.patch: sanity check size when + converting the first record to TS_LOCKEXCL in + plugins/sudoers/timestamp.c. + - debian/patches/CVE-2021-3156-1.patch: reset valid_flags to + MODE_NONINTERACTIVE for sudoedit in src/parse_args.c. + - debian/patches/CVE-2021-3156-2.patch: add sudoedit flag checks in + plugin in plugins/sudoers/policy.c. + - debian/patches/CVE-2021-3156-3.patch: fix potential buffer overflow + when unescaping backslashes in plugins/sudoers/sudoers.c. + - debian/patches/CVE-2021-3156-4.patch: fix the memset offset when + converting a v1 timestamp to TS_LOCKEXCL in + plugins/sudoers/timestamp.c. + - debian/patches/CVE-2021-3156-5.patch: don't assume that argv is + allocated as a single flat buffer in src/parse_args.c. + - CVE-2021-3156 + + -- Marc Deslauriers Tue, 19 Jan 2021 09:48:09 -0500 + +sudo (1.8.16-0ubuntu1.9) xenial-security; urgency=medium + + * SECURITY UPDATE: buffer overflow in sudo when pwfeedback is enabled + - debian/patches/CVE-2019-18634.patch: fix overflow in src/tgetpass.c. + - CVE-2019-18634 + + -- Marc Deslauriers Fri, 31 Jan 2020 12:19:11 -0500 + sudo (1.8.16-0ubuntu1.8) xenial-security; urgency=medium * SECURITY UPDATE: privilege escalation via UID -1 diff -Nru sudo-1.8.16/debian/patches/CVE-2019-18634.patch sudo-1.8.16/debian/patches/CVE-2019-18634.patch --- sudo-1.8.16/debian/patches/CVE-2019-18634.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2019-18634.patch 2020-01-31 17:19:05.000000000 +0000 @@ -0,0 +1,92 @@ +Backport of: + +From fa8ffeb17523494f0e8bb49a25e53635f4509078 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Wed, 29 Jan 2020 20:15:21 -0700 +Subject: [PATCH] Fix a buffer overflow when pwfeedback is enabled and input is + a not a tty. In getln() if the user enters ^U (erase line) and the write(2) + fails, the remaining buffer size is reset but the current pointer is not. + While here, fix an incorrect break for erase when write(2) fails. Also + disable pwfeedback when input is not a tty as it cannot work. CVE-2019-18634 + Credit: Joe Vennix from Apple Information Security. + +--- + src/tgetpass.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +--- a/src/tgetpass.c ++++ b/src/tgetpass.c +@@ -48,7 +48,7 @@ static volatile sig_atomic_t signo[NSIG] + + static bool tty_present(void); + static void tgetpass_handler(int); +-static char *getln(int, char *, size_t, int); ++static char *getln(int, char *, size_t, bool); + static char *sudo_askpass(const char *, const char *); + + static int +@@ -90,6 +90,7 @@ tgetpass(const char *prompt, int timeout + static const char *askpass; + static char buf[SUDO_CONV_REPL_MAX + 1]; + int i, input, output, save_errno, neednl = 0, need_restart; ++ bool feedback = ISSET(flags, TGP_MASK); + debug_decl(tgetpass, SUDO_DEBUG_CONV) + + (void) fflush(stdout); +@@ -136,7 +137,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); +@@ -150,6 +151,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 +@@ -179,7 +183,7 @@ restart: + + if (timeout > 0) + alarm(timeout); +- pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK)); ++ pass = getln(input, buf, sizeof(buf), feedback); + alarm(0); + save_errno = errno; + +@@ -317,7 +321,7 @@ sudo_askpass(const char *askpass, const + extern int 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) + { + size_t left = bufsiz; + ssize_t nr = -1; +@@ -339,15 +343,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 -Nru sudo-1.8.16/debian/patches/CVE-2021-23239.patch sudo-1.8.16/debian/patches/CVE-2021-23239.patch --- sudo-1.8.16/debian/patches/CVE-2021-23239.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2021-23239.patch 2021-01-19 14:40:34.000000000 +0000 @@ -0,0 +1,55 @@ + +# HG changeset patch +# User Todd C. Miller +# Date 1609953360 25200 +# Node ID ea19d0073c02951bbbf35342dd63304da83edce8 +# Parent f1ca39a0d87089d005b78a2556e2b1a2dc17f672 +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. + +--- a/src/sudo_edit.c ++++ b/src/sudo_edit.c +@@ -501,14 +501,33 @@ sudo_edit_create_tfiles(struct command_d + ofd = sudo_edit_open(files[i], O_RDONLY, 0644, 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; diff -Nru sudo-1.8.16/debian/patches/CVE-2021-3156-1.patch sudo-1.8.16/debian/patches/CVE-2021-3156-1.patch --- sudo-1.8.16/debian/patches/CVE-2021-3156-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2021-3156-1.patch 2021-01-20 15:14:03.000000000 +0000 @@ -0,0 +1,90 @@ +# HG changeset patch +# Parent 111fde52d1166af65b622da6eae19791ce0e8871 +Reset valid_flags to MODE_NONINTERACTIVE for sudoedit. +This is consistent with how the -e option is handled. +Also reject -H and -P flags for sudoedit as was done in sudo 1.7. +Found by Qualys. + +--- a/src/parse_args.c ++++ b/src/parse_args.c +@@ -108,7 +108,10 @@ static struct sudo_settings sudo_setting + /* + * 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 +@@ -189,6 +192,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. */ +@@ -257,7 +261,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': + runas_group = optarg; +@@ -265,6 +269,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) { +@@ -312,7 +317,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); +@@ -320,6 +325,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': + sudo_settings[ARG_PROMPT].value = optarg; +@@ -350,7 +356,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) +@@ -388,7 +394,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; +@@ -451,7 +457,7 @@ 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; + diff -Nru sudo-1.8.16/debian/patches/CVE-2021-3156-2.patch sudo-1.8.16/debian/patches/CVE-2021-3156-2.patch --- sudo-1.8.16/debian/patches/CVE-2021-3156-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2021-3156-2.patch 2021-01-19 14:42:56.000000000 +0000 @@ -0,0 +1,37 @@ +Backport of: + +# HG changeset patch +# Parent 4e0af3ef53d71d1e0d1ee5894a0c078020ab391a +Add sudoedit flag checks in plugin that are consistent with front-end. +Don't assume the sudo front-end is sending reasonable mode flags. +These checks need to be kept consistent between the sudo front-end +and the sudoers plugin. + +--- a/plugins/sudoers/policy.c ++++ b/plugins/sudoers/policy.c +@@ -74,10 +74,11 @@ extern char *login_style; + 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) + +@@ -264,6 +265,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; ++ } ++ + for (cur = info->user_info; *cur != NULL; cur++) { + if (MATCHES(*cur, "user=")) { + if ((user_name = strdup(*cur + sizeof("user=") - 1)) == NULL) diff -Nru sudo-1.8.16/debian/patches/CVE-2021-3156-3.patch sudo-1.8.16/debian/patches/CVE-2021-3156-3.patch --- sudo-1.8.16/debian/patches/CVE-2021-3156-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2021-3156-3.patch 2021-01-19 14:43:03.000000000 +0000 @@ -0,0 +1,65 @@ +Backport of: + +# HG changeset patch +# Parent 9b29e05ea310e187e41d8bcb58eddef8bd8b70d3 +Fix potential buffer overflow when unescaping backslashes in user_args. +Do not try to unescaping backslashes unless in run mode *and* we are +running the command via a shell. +Found by Qualys. + +--- a/plugins/sudoers/sudoers.c ++++ b/plugins/sudoers/sudoers.c +@@ -437,7 +437,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; + +@@ -754,8 +754,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)) +@@ -793,7 +793,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 +@@ -801,10 +802,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 -Nru sudo-1.8.16/debian/patches/CVE-2021-3156-4.patch sudo-1.8.16/debian/patches/CVE-2021-3156-4.patch --- sudo-1.8.16/debian/patches/CVE-2021-3156-4.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2021-3156-4.patch 2021-01-19 15:28:09.000000000 +0000 @@ -0,0 +1,19 @@ +# HG changeset patch +# Parent 5c6c54c8f971dfa21977935328942a57591ce5a8 +Fix the memset offset when converting a v1 timestamp to TS_LOCKEXCL. +We want to zero the struct starting at flags, not type (which was just set). +Found by Qualys. + +--- a/plugins/sudoers/timestamp.c ++++ b/plugins/sudoers/timestamp.c +@@ -613,8 +613,8 @@ timestamp_lock(void *vcookie, struct pas + if (entry.size == sizeof(struct timestamp_entry)) { + /* 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); + } else { diff -Nru sudo-1.8.16/debian/patches/CVE-2021-3156-5.patch sudo-1.8.16/debian/patches/CVE-2021-3156-5.patch --- sudo-1.8.16/debian/patches/CVE-2021-3156-5.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2021-3156-5.patch 2021-01-19 14:44:32.000000000 +0000 @@ -0,0 +1,30 @@ +Backport of: + +# HG changeset patch +# Parent a84c8fe05da6097efaa00d8dee8a07b5816ae84e +Don't assume that argv is allocated as a single flat buffer. +While this is how the kernel behaves it is not a portable assumption. +The assumption may also be violated if getopt_long(3) permutes arguments. +Found by Qualys. + +--- a/src/parse_args.c ++++ b/src/parse_args.c +@@ -464,13 +464,13 @@ parse_args(int argc, char **argv, int *n + 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")); +- 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 -Nru sudo-1.8.16/debian/patches/CVE-2021-3156-pre1.patch sudo-1.8.16/debian/patches/CVE-2021-3156-pre1.patch --- sudo-1.8.16/debian/patches/CVE-2021-3156-pre1.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2021-3156-pre1.patch 2021-01-19 14:41:08.000000000 +0000 @@ -0,0 +1,28 @@ + +# HG changeset patch +# User Todd C. Miller +# Date 1513397318 25200 +# Node ID e8e4c3815db58fb6d60d52a95a620af084472086 +# Parent 7cb966d69bc6843688f333a54533cf9b49a14706 +If the lock record doesn't match the expected record size we need +to seek to the end of the record as we otherwise may have gone too +far (or not far enough). Fixes interop problems when the time stamp +record changes size. + +--- a/plugins/sudoers/timestamp.c ++++ b/plugins/sudoers/timestamp.c +@@ -601,6 +601,14 @@ timestamp_lock(void *vcookie, struct pas + if (ts_write(cookie->fd, cookie->fname, &entry, 0) == -1) + debug_return_bool(false); + } ++ if (entry.size != sizeof(entry)) { ++ /* Reset position if the lock record has an unexpected size. */ ++ if (lseek(cookie->fd, entry.size, SEEK_SET) == -1) { ++ sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, ++ "unable to seek to %lld", (long long)entry.size); ++ debug_return_bool(false); ++ } ++ } + + /* Search for a tty-based record or append a new one. */ + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, diff -Nru sudo-1.8.16/debian/patches/CVE-2021-3156-pre2.patch sudo-1.8.16/debian/patches/CVE-2021-3156-pre2.patch --- sudo-1.8.16/debian/patches/CVE-2021-3156-pre2.patch 1970-01-01 00:00:00.000000000 +0000 +++ sudo-1.8.16/debian/patches/CVE-2021-3156-pre2.patch 2021-01-19 15:29:00.000000000 +0000 @@ -0,0 +1,102 @@ +Backport of: + + +# HG changeset patch +# User Todd C. Miller +# Date 1578242229 25200 +# Node ID 5b94873c4051e9f18b7d4254b8f85fd759393844 +# Parent 4bcba58004c8df07e671bfcd2037b0b34c560815 +Sanity check size when converting the first record to TS_LOCKEXCL +Coverity CID 206591 + +--- a/plugins/sudoers/timestamp.c ++++ b/plugins/sudoers/timestamp.c +@@ -557,6 +557,25 @@ done: + } + + /* ++ * Write a TS_LOCKEXCL record at the beginning of the time stamp file. ++ */ ++bool ++timestamp_lock_write(struct ts_cookie *cookie) ++{ ++ struct timestamp_entry entry; ++ bool ret = true; ++ debug_decl(timestamp_lock_write, SUDOERS_DEBUG_AUTH); ++ ++ memset(&entry, 0, sizeof(entry)); ++ entry.version = TS_VERSION; ++ entry.size = sizeof(entry); ++ entry.type = TS_LOCKEXCL; ++ if (ts_write(cookie->fd, cookie->fname, &entry, -1) == -1) ++ ret = false; ++ debug_return_bool(ret); ++} ++ ++/* + * Lock a record in the time stamp file for exclusive access. + * If the record does not exist, it is created (as disabled). + */ +@@ -565,6 +584,7 @@ timestamp_lock(void *vcookie, struct pas + { + struct ts_cookie *cookie = vcookie; + struct timestamp_entry entry; ++ bool overwrite = false; + off_t lock_pos; + ssize_t nread; + debug_decl(timestamp_lock, SUDOERS_DEBUG_AUTH) +@@ -586,26 +606,39 @@ timestamp_lock(void *vcookie, struct pas + /* Make sure the first record is of type TS_LOCKEXCL. */ + memset(&entry, 0, sizeof(entry)); + nread = read(cookie->fd, &entry, sizeof(entry)); +- if (nread == 0) { +- /* New file, add TS_LOCKEXCL record. */ +- entry.version = TS_VERSION; +- entry.size = sizeof(entry); +- entry.type = TS_LOCKEXCL; +- if (ts_write(cookie->fd, cookie->fname, &entry, -1) == -1) +- debug_return_bool(false); ++ if (nread < sizeof(struct timestamp_entry)) { ++ /* New or invalid time stamp file. */ ++ overwrite = true; + } 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)); +- if (ts_write(cookie->fd, cookie->fname, &entry, 0) == -1) +- debug_return_bool(false); ++ if (entry.size == sizeof(struct timestamp_entry)) { ++ /* 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)); ++ if (ts_write(cookie->fd, cookie->fname, &entry, 0) == -1) ++ debug_return_bool(false); ++ } else { ++ /* Corrupted time stamp file? Just overwrite it. */ ++ sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, ++ "corrupt initial record, type: %hu, size: %hu (expected %zu)", ++ entry.type, entry.size, sizeof(struct timestamp_entry)); ++ overwrite = true; ++ } + } +- if (entry.size != sizeof(entry)) { ++ if (overwrite) { ++ /* Rewrite existing time stamp file or create new one. */ ++ if (ftruncate(cookie->fd, 0) != 0) { ++ sudo_warn(U_("unable to truncate time stamp file to %lld bytes"), ++ 0LL); ++ debug_return_bool(false); ++ } ++ if (!timestamp_lock_write(cookie)) ++ debug_return_bool(false); ++ } else if (entry.size != sizeof(entry)) { + /* Reset position if the lock record has an unexpected size. */ + if (lseek(cookie->fd, entry.size, SEEK_SET) == -1) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, +- "unable to seek to %lld", (long long)entry.size); ++ "unable to seek to %hu", entry.size); + debug_return_bool(false); + } + } diff -Nru sudo-1.8.16/debian/patches/series sudo-1.8.16/debian/patches/series --- sudo-1.8.16/debian/patches/series 2019-10-11 11:14:33.000000000 +0000 +++ sudo-1.8.16/debian/patches/series 2021-01-19 14:43:11.000000000 +0000 @@ -17,3 +17,12 @@ CVE-2016-7076-6.patch CVE-2019-14287.patch CVE-2019-14287-2.patch +CVE-2019-18634.patch +CVE-2021-23239.patch +CVE-2021-3156-pre1.patch +CVE-2021-3156-pre2.patch +CVE-2021-3156-1.patch +CVE-2021-3156-2.patch +CVE-2021-3156-3.patch +CVE-2021-3156-4.patch +CVE-2021-3156-5.patch