Skip to content

Commit

Permalink
Treat an ID of -1 as invalid since that means "no change".
Browse files Browse the repository at this point in the history
Fixes CVE-2019-14287.
Found by Joe Vennix from Apple Information Security.
  • Loading branch information
millert committed Oct 10, 2019
1 parent fd5d0f5 commit f752ae5
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 47 deletions.
4 changes: 4 additions & 0 deletions NEWS
Expand Up @@ -76,6 +76,10 @@ What's new in Sudo 1.8.28
* Fixed a bug where the terminal's file context was not restored
when using SELinux RBAC. Bug #898.

* Fixed CVE-2019-14287, a bug where a sudo user may be able to
run a command as root when the Runas specification explicitly
disallows root access as long as the ALL keyword is listed first.

What's new in Sudo 1.8.27

* On HP-UX, sudo will now update the utmps file when running a command
Expand Down
100 changes: 53 additions & 47 deletions lib/util/strtoid.c
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: ISC
*
* 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
Expand Down Expand Up @@ -48,6 +48,27 @@
#include "sudo_debug.h"
#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)
Expand All @@ -62,36 +83,33 @@ sudo_strtoid_v1(const char *p, const char *sep, char **endp, const char **errstr
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_("invalid value");
errno = EINVAL;
*errstr = N_("value too small");
goto done;
}
if (errno == ERANGE) {
if (errstr != NULL) {
if (llval == LLONG_MAX)
*errstr = N_("value too large");
else
*errstr = N_("value too small");
}

/* 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;
}
ret = (id_t)llval;
Expand All @@ -108,30 +126,15 @@ sudo_strtoid_v1(const char *p, const char *sep, char **endp, const char **errstr
{
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)
Expand All @@ -144,28 +147,31 @@ sudo_strtoid_v1(const char *p, const char *sep, char **endp, const char **errstr
*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)
Expand Down

0 comments on commit f752ae5

Please sign in to comment.