summaryrefslogtreecommitdiffstats
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/Add-sudoedit-flag-checks-in-plugin-that-are-consiste.patch43
-rw-r--r--debian/patches/Don-t-assume-that-argv-is-allocated-as-a-single-flat.patch39
-rw-r--r--debian/patches/Fix-a-buffer-overflow-when-pwfeedback-is-enabled-and.patch95
-rw-r--r--debian/patches/Fix-potential-buffer-overflow-when-unescaping-backsl.patch71
-rw-r--r--debian/patches/Fix-the-memset-offset-when-converting-a-v1-timestamp.patch30
-rw-r--r--debian/patches/Reset-valid_flags-to-MODE_NONINTERACTIVE-for-sudoedi.patch97
-rw-r--r--debian/patches/Sanity-check-size-when-converting-the-first-record-t.patch107
-rw-r--r--debian/patches/Whitelist-DPKG_COLORS-environment-variable.diff24
-rw-r--r--debian/patches/paths-in-samples.diff40
-rw-r--r--debian/patches/series12
-rw-r--r--debian/patches/strtoid_minus_1_test_fix.diff103
-rw-r--r--debian/patches/sudo_minus_1_uid.diff177
-rw-r--r--debian/patches/typo-in-classic-insults.diff11
13 files changed, 849 insertions, 0 deletions
diff --git a/debian/patches/Add-sudoedit-flag-checks-in-plugin-that-are-consiste.patch b/debian/patches/Add-sudoedit-flag-checks-in-plugin-that-are-consiste.patch
new file mode 100644
index 0000000..0fd3071
--- /dev/null
+++ b/debian/patches/Add-sudoedit-flag-checks-in-plugin-that-are-consiste.patch
@@ -0,0 +1,43 @@
+From 9f8d2f158166512511aac5e32928dcf6c65005c3 Mon Sep 17 00:00:00 2001
+From: "Todd C. Miller" <Todd.Miller@sudo.ws>
+Date: Wed, 20 Jan 2021 09:03:17 +0100
+Subject: [PATCH 2/5] 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.
+
+[Salvatore Bonaccorso: Backport to 1.8.27: Context changes]
+---
+ plugins/sudoers/policy.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/plugins/sudoers/policy.c
++++ b/plugins/sudoers/policy.c
+@@ -98,10 +98,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;
+ bool uid_set = false, gid_set = false;
+ int flags = 0;
+ debug_decl(sudoers_policy_deserialize_info, SUDOERS_DEBUG_PLUGIN)
+@@ -331,6 +332,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_umask = (mode_t)-1;
+ for (cur = info->user_info; *cur != NULL; cur++) {
+ if (MATCHES(*cur, "user=")) {
diff --git a/debian/patches/Don-t-assume-that-argv-is-allocated-as-a-single-flat.patch b/debian/patches/Don-t-assume-that-argv-is-allocated-as-a-single-flat.patch
new file mode 100644
index 0000000..0fa8d84
--- /dev/null
+++ b/debian/patches/Don-t-assume-that-argv-is-allocated-as-a-single-flat.patch
@@ -0,0 +1,39 @@
+From 61470612e3bc1a0aca268d80bc55c36c1802b7fd Mon Sep 17 00:00:00 2001
+From: "Todd C. Miller" <Todd.Miller@sudo.ws>
+Date: Wed, 20 Jan 2021 09:04:39 +0100
+Subject: [PATCH 5/5] 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.
+
+[Salvatore Bonaccorso: Backport to 1.8.27: Context changes]
+---
+ src/parse_args.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/src/parse_args.c
++++ b/src/parse_args.c
+@@ -563,16 +563,16 @@ 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"));
+ 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/debian/patches/Fix-a-buffer-overflow-when-pwfeedback-is-enabled-and.patch b/debian/patches/Fix-a-buffer-overflow-when-pwfeedback-is-enabled-and.patch
new file mode 100644
index 0000000..5d6f227
--- /dev/null
+++ b/debian/patches/Fix-a-buffer-overflow-when-pwfeedback-is-enabled-and.patch
@@ -0,0 +1,95 @@
+From: "Todd C. Miller" <Todd.Miller@sudo.ws>
+Date: Wed, 29 Jan 2020 20:15:21 -0700
+Subject: 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.
+Origin: https://github.com/sudo-project/sudo/commit/b5d2010b6514ff45693509273bb07df3abb0bf0a
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-18634
+Bug-Debian: https://bugs.debian.org/950371
+
+--HG--
+branch : 1.8
+[Salvatore Bonaccorso: Backport to 1.8.27 for context changes]
+---
+ src/tgetpass.c | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+--- a/src/tgetpass.c
++++ b/src/tgetpass.c
+@@ -60,7 +60,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, enum tgetpass_errval *);
++static char *getln(int, char *, size_t, bool, enum tgetpass_errval *);
+ static char *sudo_askpass(const char *, const char *);
+
+ static int
+@@ -123,6 +123,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);
+ enum tgetpass_errval errval;
+ debug_decl(tgetpass, SUDO_DEBUG_CONV)
+
+@@ -170,7 +171,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);
+@@ -184,6 +185,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
+@@ -209,7 +213,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;
+
+@@ -345,7 +349,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;
+@@ -374,15 +378,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/debian/patches/Fix-potential-buffer-overflow-when-unescaping-backsl.patch b/debian/patches/Fix-potential-buffer-overflow-when-unescaping-backsl.patch
new file mode 100644
index 0000000..414c0d9
--- /dev/null
+++ b/debian/patches/Fix-potential-buffer-overflow-when-unescaping-backsl.patch
@@ -0,0 +1,71 @@
+From 1e94630a10326635ea5cdd8dc575f43e40a80469 Mon Sep 17 00:00:00 2001
+From: "Todd C. Miller" <Todd.Miller@sudo.ws>
+Date: Wed, 20 Jan 2021 09:03:43 +0100
+Subject: [PATCH 3/5] 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.
+
+[Salvatore Bonaccorso: Backport to 1.8.27: Context changes]
+---
+ plugins/sudoers/sudoers.c | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+--- a/plugins/sudoers/sudoers.c
++++ b/plugins/sudoers/sudoers.c
+@@ -404,7 +404,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;
+
+@@ -784,8 +784,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))
+@@ -823,7 +823,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
+@@ -831,10 +832,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 --git a/debian/patches/Fix-the-memset-offset-when-converting-a-v1-timestamp.patch b/debian/patches/Fix-the-memset-offset-when-converting-a-v1-timestamp.patch
new file mode 100644
index 0000000..aa46b0f
--- /dev/null
+++ b/debian/patches/Fix-the-memset-offset-when-converting-a-v1-timestamp.patch
@@ -0,0 +1,30 @@
+From 6ab23a7a9fe7be865e5c93363b520c704867326a Mon Sep 17 00:00:00 2001
+From: "Todd C. Miller" <Todd.Miller@sudo.ws>
+Date: Wed, 20 Jan 2021 09:04:12 +0100
+Subject: [PATCH 4/5] 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.
+---
+ plugins/sudoers/timestamp.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/plugins/sudoers/timestamp.c b/plugins/sudoers/timestamp.c
+index ace568e5a4fe..dfc9bdfc5f26 100644
+--- a/plugins/sudoers/timestamp.c
++++ b/plugins/sudoers/timestamp.c
+@@ -643,8 +643,8 @@ timestamp_lock(void *vcookie, struct passwd *pw)
+ if (entry.size == sizeof(struct timestamp_entry_v1)) {
+ /* 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 {
+--
+2.30.0
+
diff --git a/debian/patches/Reset-valid_flags-to-MODE_NONINTERACTIVE-for-sudoedi.patch b/debian/patches/Reset-valid_flags-to-MODE_NONINTERACTIVE-for-sudoedi.patch
new file mode 100644
index 0000000..ac62729
--- /dev/null
+++ b/debian/patches/Reset-valid_flags-to-MODE_NONINTERACTIVE-for-sudoedi.patch
@@ -0,0 +1,97 @@
+From 6f726f8a6f5e203ae2f4675902ba4aa03a8393af Mon Sep 17 00:00:00 2001
+From: "Todd C. Miller" <Todd.Miller@sudo.ws>
+Date: Wed, 20 Jan 2021 09:02:42 +0100
+Subject: [PATCH 1/5] 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.
+
+[Salvatore Bonaccorso: Backport to 1.8.27: Context changes]
+---
+ src/parse_args.c | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+--- a/src/parse_args.c
++++ b/src/parse_args.c
+@@ -121,7 +121,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
+@@ -265,6 +268,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. */
+@@ -350,7 +354,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':
+ if (*optarg == '\0')
+@@ -360,6 +364,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) {
+@@ -409,7 +414,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);
+@@ -417,6 +422,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. */
+@@ -460,7 +466,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)
+@@ -487,7 +493,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;
+@@ -550,7 +556,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 --git a/debian/patches/Sanity-check-size-when-converting-the-first-record-t.patch b/debian/patches/Sanity-check-size-when-converting-the-first-record-t.patch
new file mode 100644
index 0000000..c0964be
--- /dev/null
+++ b/debian/patches/Sanity-check-size-when-converting-the-first-record-t.patch
@@ -0,0 +1,107 @@
+From 586b418ad85ff8c2e756eff7063ffaeca631fa02 Mon Sep 17 00:00:00 2001
+From: "Todd C. Miller" <Todd.Miller@sudo.ws>
+Date: Sun, 5 Jan 2020 09:37:09 -0700
+Subject: [PATCH] Sanity check size when converting the first record to
+ TS_LOCKEXCL Coverity CID 206591
+
+[Salvatore Bonaccorso: Backport to 1.8.27:
+ - Context changes
+ - Drop hunk about copyright years update
+ - Cast sizeof(struct timestamp_entry_v1) into ssize_t as 1.8.27 does
+ not contain the "Add ssizeof macro that returns ssize_t" change.
+]
+---
+ plugins/sudoers/timestamp.c | 65 ++++++++++++++++++++++++++++---------
+ 1 file changed, 49 insertions(+), 16 deletions(-)
+
+--- a/plugins/sudoers/timestamp.c
++++ b/plugins/sudoers/timestamp.c
+@@ -611,6 +611,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).
+ */
+@@ -619,6 +638,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)
+@@ -640,26 +660,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 < (ssize_t)sizeof(struct timestamp_entry_v1)) {
++ /* 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_v1)) {
++ /* 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_v1));
++ 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 --git a/debian/patches/Whitelist-DPKG_COLORS-environment-variable.diff b/debian/patches/Whitelist-DPKG_COLORS-environment-variable.diff
new file mode 100644
index 0000000..c2e1711
--- /dev/null
+++ b/debian/patches/Whitelist-DPKG_COLORS-environment-variable.diff
@@ -0,0 +1,24 @@
+From 18087bc16ec20ca2c8f0045a6b0408e94c53075c Mon Sep 17 00:00:00 2001
+From: Guillem Jover <guillem@hadrons.org>
+Date: Wed, 4 May 2016 01:53:13 +0200
+Subject: [PATCH] Whitelist DPKG_COLORS environment variable
+
+---
+ plugins/sudoers/env.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/plugins/sudoers/env.c b/plugins/sudoers/env.c
+index 9065250..c037bd8 100644
+--- a/plugins/sudoers/env.c
++++ b/plugins/sudoers/env.c
+@@ -188,6 +188,7 @@ static const char *initial_checkenv_table[] = {
+ static const char *initial_keepenv_table[] = {
+ "COLORS",
+ "DISPLAY",
++ "DPKG_COLORS",
+ "HOSTNAME",
+ "KRB5CCNAME",
+ "LS_COLORS",
+--
+2.8.1
+
diff --git a/debian/patches/paths-in-samples.diff b/debian/patches/paths-in-samples.diff
new file mode 100644
index 0000000..4fef5d9
--- /dev/null
+++ b/debian/patches/paths-in-samples.diff
@@ -0,0 +1,40 @@
+--- a/examples/sudoers
++++ b/examples/sudoers
+@@ -44,10 +44,10 @@
+ # Cmnd alias specification
+ ##
+ Cmnd_Alias DUMPS = /usr/sbin/dump, /usr/sbin/rdump, /usr/sbin/restore, \
+- /usr/sbin/rrestore, /usr/bin/mt, \
++ /usr/sbin/rrestore, /bin/mt, \
+ sha224:0GomF8mNN3wlDt1HD9XldjJ3SNgpFdbjO1+NsQ== \
+ /home/operator/bin/start_backups
+-Cmnd_Alias KILL = /usr/bin/kill, /usr/bin/top
++Cmnd_Alias KILL = /bin/kill, /usr/bin/top
+ Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm
+ Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown
+ Cmnd_Alias HALT = /usr/sbin/halt
+@@ -85,7 +85,7 @@
+ sudoedit /etc/printcap, /usr/oper/bin/
+
+ # joe may su only to operator
+-joe ALL = /usr/bin/su operator
++joe ALL = /bin/su operator
+
+ # pete may change passwords for anyone but root on the hp snakes
+ pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd *root*
+@@ -99,13 +99,13 @@
+
+ # users in the secretaries netgroup need to help manage the printers
+ # as well as add and remove users
+-+secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
+++secretaries ALL = PRINTING, /usr/sbin/adduser
+
+ # fred can run commands as oracle or sybase without a password
+ fred ALL = (DB) NOPASSWD: ALL
+
+ # on the alphas, john may su to anyone but root and flags are not allowed
+-john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
++john ALPHA = /bin/su [!-]*, !/bin/su *root*
+
+ # jen can run anything on all machines except the ones
+ # in the "SERVERS" Host_Alias
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..fe0bf5a
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,12 @@
+typo-in-classic-insults.diff
+paths-in-samples.diff
+Whitelist-DPKG_COLORS-environment-variable.diff
+sudo_minus_1_uid.diff
+strtoid_minus_1_test_fix.diff
+Fix-a-buffer-overflow-when-pwfeedback-is-enabled-and.patch
+Sanity-check-size-when-converting-the-first-record-t.patch
+Reset-valid_flags-to-MODE_NONINTERACTIVE-for-sudoedi.patch
+Add-sudoedit-flag-checks-in-plugin-that-are-consiste.patch
+Fix-potential-buffer-overflow-when-unescaping-backsl.patch
+Fix-the-memset-offset-when-converting-a-v1-timestamp.patch
+Don-t-assume-that-argv-is-allocated-as-a-single-flat.patch
diff --git a/debian/patches/strtoid_minus_1_test_fix.diff b/debian/patches/strtoid_minus_1_test_fix.diff
new file mode 100644
index 0000000..6a2f148
--- /dev/null
+++ b/debian/patches/strtoid_minus_1_test_fix.diff
@@ -0,0 +1,103 @@
+Description: Fix test failure in plugins/sudoers/regress/testsudoers/test5.sh
+ Fix test failure after fix for CVE-2019-14287 .
+Origin: upstream
+Author: Todd C. Miller <Todd.Miller@sudo.ws>
+Reviewed-by: Salvatore Bonaccorso <carnil@debian.org>
+Last-Update: 2019-10-10
+
+diff -r fcd7a6d8330e lib/util/regress/atofoo/atofoo_test.c
+--- a/lib/util/regress/atofoo/atofoo_test.c Fri Jan 11 13:31:15 2019 -0700
++++ b/lib/util/regress/atofoo/atofoo_test.c Thu Oct 10 14:02:30 2019 -0600
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2014 Todd C. Miller <Todd.Miller@sudo.ws>
++ * Copyright (c) 2014-2019 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+@@ -24,6 +24,7 @@
+ #else
+ # include "compat/stdbool.h"
+ #endif
++#include <errno.h>
+
+ #include "sudo_compat.h"
+ #include "sudo_util.h"
+@@ -78,15 +79,20 @@ static struct strtoid_data {
+ id_t id;
+ const char *sep;
+ const char *ep;
++ int errnum;
+ } strtoid_data[] = {
+- { "0,1", 0, ",", "," },
+- { "10", 10, NULL, NULL },
+- { "-2", -2, NULL, NULL },
++ { "0,1", 0, ",", ",", 0 },
++ { "10", 10, NULL, NULL, 0 },
++ { "-1", 0, NULL, NULL, EINVAL },
++ { "4294967295", 0, NULL, NULL, EINVAL },
++ { "4294967296", 0, NULL, NULL, ERANGE },
++ { "-2147483649", 0, NULL, NULL, ERANGE },
++ { "-2", -2, NULL, NULL, 0 },
+ #if SIZEOF_ID_T != SIZEOF_LONG_LONG
+- { "-2", (id_t)4294967294U, NULL, NULL },
++ { "-2", (id_t)4294967294U, NULL, NULL, 0 },
+ #endif
+- { "4294967294", (id_t)4294967294U, NULL, NULL },
+- { NULL, 0, NULL, NULL }
++ { "4294967294", (id_t)4294967294U, NULL, NULL, 0 },
++ { NULL, 0, NULL, NULL, 0 }
+ };
+
+ static int
+@@ -102,11 +108,23 @@ test_strtoid(int *ntests)
+ (*ntests)++;
+ errstr = "some error";
+ value = sudo_strtoid(d->idstr, d->sep, &ep, &errstr);
+- if (errstr != NULL) {
+- if (d->id != (id_t)-1) {
+- sudo_warnx_nodebug("FAIL: %s: %s", d->idstr, errstr);
++ if (d->errnum != 0) {
++ if (errstr == NULL) {
++ sudo_warnx_nodebug("FAIL: %s: missing errstr for errno %d",
++ d->idstr, d->errnum);
++ errors++;
++ } else if (value != 0) {
++ sudo_warnx_nodebug("FAIL: %s should return 0 on error",
++ d->idstr);
++ errors++;
++ } else if (errno != d->errnum) {
++ sudo_warnx_nodebug("FAIL: %s: errno mismatch, %d != %d",
++ d->idstr, errno, d->errnum);
+ errors++;
+ }
++ } else if (errstr != NULL) {
++ sudo_warnx_nodebug("FAIL: %s: %s", d->idstr, errstr);
++ errors++;
+ } else if (value != d->id) {
+ sudo_warnx_nodebug("FAIL: %s != %u", d->idstr, (unsigned int)d->id);
+ errors++;
+diff -r fcd7a6d8330e plugins/sudoers/regress/testsudoers/test5.out.ok
+--- a/plugins/sudoers/regress/testsudoers/test5.out.ok Fri Jan 11 13:31:15 2019 -0700
++++ b/plugins/sudoers/regress/testsudoers/test5.out.ok Thu Oct 10 14:02:30 2019 -0600
+@@ -4,7 +4,7 @@ Parse error in sudoers near line 1.
+ Entries for user root:
+
+ Command unmatched
+-testsudoers: test5.inc should be owned by gid 4294967295
++testsudoers: test5.inc should be owned by gid 4294967294
+ Parse error in sudoers near line 1.
+
+ Entries for user root:
+diff -r fcd7a6d8330e plugins/sudoers/regress/testsudoers/test5.sh
+--- a/plugins/sudoers/regress/testsudoers/test5.sh Fri Jan 11 13:31:15 2019 -0700
++++ b/plugins/sudoers/regress/testsudoers/test5.sh Thu Oct 10 14:02:30 2019 -0600
+@@ -24,7 +24,7 @@ EOF
+
+ # Test group writable
+ chmod 664 $TESTFILE
+-./testsudoers -U $MYUID -G -1 root id <<EOF
++./testsudoers -U $MYUID -G -2 root id <<EOF
+ #include $TESTFILE
+ EOF
+
diff --git a/debian/patches/sudo_minus_1_uid.diff b/debian/patches/sudo_minus_1_uid.diff
new file mode 100644
index 0000000..167b75d
--- /dev/null
+++ b/debian/patches/sudo_minus_1_uid.diff
@@ -0,0 +1,177 @@
+Description: Treat an ID of -1 as invalid since that means "no change".
+ Fixes CVE-2019-14287.
+ Found by Joe Vennix from Apple Information Security.
+Origin: upstream
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-14287
+Author: Todd C. Miller <Todd.Miller@sudo.ws>
+Reviewed-by: Salvatore Bonaccorso <carnil@debian.org>
+Last-Update: 2019-10-10
+
+diff -r fcd7a6d8330e lib/util/strtoid.c
+--- a/lib/util/strtoid.c Fri Jan 11 13:31:15 2019 -0700
++++ b/lib/util/strtoid.c Thu Oct 10 09:52:12 2019 -0600
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2013-2016 Todd C. Miller <Todd.Miller@sudo.ws>
++ * Copyright (c) 2013-2019 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+@@ -47,6 +47,27 @@
+ #include "sudo_util.h"
+
+ /*
++ * Make sure that the ID ends with a valid separator char.
++ */
++static bool
++valid_separator(const char *p, const char *ep, const char *sep)
++{
++ bool valid = false;
++ debug_decl(valid_separator, SUDO_DEBUG_UTIL)
++
++ if (ep != p) {
++ /* check for valid separator (including '\0') */
++ if (sep == NULL)
++ sep = "";
++ do {
++ if (*ep == *sep)
++ valid = true;
++ } while (*sep++ != '\0');
++ }
++ debug_return_bool(valid);
++}
++
++/*
+ * Parse a uid/gid in string form.
+ * If sep is non-NULL, it contains valid separator characters (e.g. comma, space)
+ * If endp is non-NULL it is set to the next char after the ID.
+@@ -60,38 +81,35 @@ sudo_strtoid_v1(const char *p, const cha
+ char *ep;
+ id_t ret = 0;
+ long long llval;
+- bool valid = false;
+ debug_decl(sudo_strtoid, SUDO_DEBUG_UTIL)
+
+ /* skip leading space so we can pick up the sign, if any */
+ while (isspace((unsigned char)*p))
+ p++;
+- if (sep == NULL)
+- sep = "";
++
++ /* While id_t may be 64-bit signed, uid_t and gid_t are 32-bit unsigned. */
+ errno = 0;
+ llval = strtoll(p, &ep, 10);
+- if (ep != p) {
+- /* check for valid separator (including '\0') */
+- do {
+- if (*ep == *sep)
+- valid = true;
+- } while (*sep++ != '\0');
++ if ((errno == ERANGE && llval == LLONG_MAX) || llval > (id_t)UINT_MAX) {
++ errno = ERANGE;
++ if (errstr != NULL)
++ *errstr = N_("value too large");
++ goto done;
+ }
+- if (!valid) {
++ if ((errno == ERANGE && llval == LLONG_MIN) || llval < INT_MIN) {
++ errno = ERANGE;
++ if (errstr != NULL)
++ *errstr = N_("value too small");
++ goto done;
++ }
++
++ /* Disallow id -1, which means "no change". */
++ if (!valid_separator(p, ep, sep) || llval == -1 || llval == (id_t)UINT_MAX) {
+ if (errstr != NULL)
+ *errstr = N_("invalid value");
+ errno = EINVAL;
+ goto done;
+ }
+- if (errno == ERANGE) {
+- if (errstr != NULL) {
+- if (llval == LLONG_MAX)
+- *errstr = N_("value too large");
+- else
+- *errstr = N_("value too small");
+- }
+- goto done;
+- }
+ ret = (id_t)llval;
+ if (errstr != NULL)
+ *errstr = NULL;
+@@ -106,30 +124,15 @@ sudo_strtoid_v1(const char *p, const cha
+ {
+ char *ep;
+ id_t ret = 0;
+- bool valid = false;
+ debug_decl(sudo_strtoid, SUDO_DEBUG_UTIL)
+
+ /* skip leading space so we can pick up the sign, if any */
+ while (isspace((unsigned char)*p))
+ p++;
+- if (sep == NULL)
+- sep = "";
++
+ errno = 0;
+ if (*p == '-') {
+ long lval = strtol(p, &ep, 10);
+- if (ep != p) {
+- /* check for valid separator (including '\0') */
+- do {
+- if (*ep == *sep)
+- valid = true;
+- } while (*sep++ != '\0');
+- }
+- if (!valid) {
+- if (errstr != NULL)
+- *errstr = N_("invalid value");
+- errno = EINVAL;
+- goto done;
+- }
+ if ((errno == ERANGE && lval == LONG_MAX) || lval > INT_MAX) {
+ errno = ERANGE;
+ if (errstr != NULL)
+@@ -142,28 +145,31 @@ sudo_strtoid_v1(const char *p, const cha
+ *errstr = N_("value too small");
+ goto done;
+ }
+- ret = (id_t)lval;
+- } else {
+- unsigned long ulval = strtoul(p, &ep, 10);
+- if (ep != p) {
+- /* check for valid separator (including '\0') */
+- do {
+- if (*ep == *sep)
+- valid = true;
+- } while (*sep++ != '\0');
+- }
+- if (!valid) {
++
++ /* Disallow id -1, which means "no change". */
++ if (!valid_separator(p, ep, sep) || lval == -1) {
+ if (errstr != NULL)
+ *errstr = N_("invalid value");
+ errno = EINVAL;
+ goto done;
+ }
++ ret = (id_t)lval;
++ } else {
++ unsigned long ulval = strtoul(p, &ep, 10);
+ if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > UINT_MAX) {
+ errno = ERANGE;
+ if (errstr != NULL)
+ *errstr = N_("value too large");
+ goto done;
+ }
++
++ /* Disallow id -1, which means "no change". */
++ if (!valid_separator(p, ep, sep) || ulval == UINT_MAX) {
++ if (errstr != NULL)
++ *errstr = N_("invalid value");
++ errno = EINVAL;
++ goto done;
++ }
+ ret = (id_t)ulval;
+ }
+ if (errstr != NULL)
diff --git a/debian/patches/typo-in-classic-insults.diff b/debian/patches/typo-in-classic-insults.diff
new file mode 100644
index 0000000..57e78c6
--- /dev/null
+++ b/debian/patches/typo-in-classic-insults.diff
@@ -0,0 +1,11 @@
+--- a/plugins/sudoers/ins_classic.h
++++ b/plugins/sudoers/ins_classic.h
+@@ -30,7 +30,7 @@
+ "Where did you learn to type?",
+ "Are you on drugs?",
+ "My pet ferret can type better than you!",
+- "You type like i drive.",
++ "You type like I drive.",
+ "Do you think like you type?",
+ "Your mind just hasn't been the same since the electro-shock, has it?",
+