diff -urN sudo-1.8.10/common/atoid.c sudo-1.8.10.patched/common/atoid.c --- sudo-1.8.10/common/atoid.c Fri Mar 7 14:51:19 2014 +++ sudo-1.8.10.patched/common/atoid.c Tue Oct 15 14:51:52 2019 @@ -37,6 +37,7 @@ #else # include "compat/stdbool.h" #endif +#include #include #include @@ -48,6 +49,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. @@ -59,27 +81,15 @@ { char *ep; id_t rval = 0; - bool valid = false; debug_decl(atoid, SUDO_DEBUG_UTIL) - if (sep == NULL) - sep = ""; + /* skip leading space so we can pick up the sign, if any */ + while (isspace((unsigned char)*p)) + p++; + 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) @@ -92,26 +102,29 @@ *errstr = N_("value too small"); goto done; } - rval = (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; } + rval = (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; } rval = (id_t)ulval; diff -urN sudo-1.8.10/plugins/sudoers/regress/testsudoers/test5.out.ok sudo-1.8.10.patched/plugins/sudoers/regress/testsudoers/test5.out.ok --- sudo-1.8.10/plugins/sudoers/regress/testsudoers/test5.out.ok Fri Mar 7 14:50:56 2014 +++ sudo-1.8.10.patched/plugins/sudoers/regress/testsudoers/test5.out.ok Tue Oct 15 14:33:30 2019 @@ -4,7 +4,7 @@ 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 -urN sudo-1.8.10/plugins/sudoers/regress/testsudoers/test5.sh sudo-1.8.10.patched/plugins/sudoers/regress/testsudoers/test5.sh --- sudo-1.8.10/plugins/sudoers/regress/testsudoers/test5.sh Fri Mar 7 14:50:56 2014 +++ sudo-1.8.10.patched/plugins/sudoers/regress/testsudoers/test5.sh Tue Oct 15 14:33:33 2019 @@ -21,7 +21,7 @@ # Test group writable chmod 664 $TESTFILE -./testsudoers -U $MYUID -G -1 root id <