diff -up ./doc/sudoers.man.in.CVE-2019-19232 ./doc/sudoers.man.in --- ./doc/sudoers.man.in.CVE-2019-19232 2019-10-28 13:28:52.000000000 +0100 +++ ./doc/sudoers.man.in 2020-01-14 15:34:46.908027286 +0100 @@ -2942,6 +2942,23 @@ This flag is \fIoff\fR by default. .TP 18n +runas_allow_unknown_id +If enabled, allow matching of runas user and group IDs that are +not present in the password or group databases. +In addition to explicitly matching unknown user or group IDs in a +\fRRunas_List\fR, +this option also allows the +\fBALL\fR +alias to match unknown IDs. +This flag is +\fIoff\fR +by default. +.sp +This setting is only supported by version 1.8.29 or higher. +Older versions of +\fBsudo\fR +always allowed matching of unknown user and group IDs. +.TP 18n runaspw If set, \fBsudo\fR diff -up ./doc/sudoers.mdoc.in.CVE-2019-19232 ./doc/sudoers.mdoc.in --- ./doc/sudoers.mdoc.in.CVE-2019-19232 2019-10-28 13:28:52.000000000 +0100 +++ ./doc/sudoers.mdoc.in 2020-01-14 15:34:46.908027286 +0100 @@ -2768,6 +2768,22 @@ when running a command or editing a file This flag is .Em off by default. +.It runas_allow_unknown_id +If enabled, allow matching of runas user and group IDs that are +not present in the password or group databases. +In addition to explicitly matching unknown user or group IDs in a +.Li Runas_List , +this option also allows the +.Sy ALL +alias to match unknown IDs. +This flag is +.Em off +by default. +.Pp +This setting is only supported by version 1.8.29 or higher. +Older versions of +.Nm sudo +always allowed matching of unknown user and group IDs. .It runaspw If set, .Nm sudo diff -up ./plugins/sudoers/defaults.c.CVE-2019-19232 ./plugins/sudoers/defaults.c --- ./plugins/sudoers/defaults.c.CVE-2019-19232 2020-01-14 15:34:46.902027246 +0100 +++ ./plugins/sudoers/defaults.c 2020-01-14 15:34:46.909027293 +0100 @@ -581,6 +581,7 @@ init_defaults(void) def_fdexec = digest_only; def_log_allowed = true; def_log_denied = true; + def_runas_allow_unknown_id = false; /* Syslog options need special care since they both strings and ints */ #if (LOGGING & SLOG_SYSLOG) diff -up ./plugins/sudoers/def_data.c.CVE-2019-19232 ./plugins/sudoers/def_data.c --- ./plugins/sudoers/def_data.c.CVE-2019-19232 2020-01-14 15:34:46.908027286 +0100 +++ ./plugins/sudoers/def_data.c 2020-01-14 15:40:19.441555509 +0100 @@ -514,6 +514,10 @@ struct sudo_defs_types sudo_defs_table[] N_("Don't fork and wait for the command to finish, just exec it"), NULL, }, { + "runas_allow_unknown_id", T_FLAG, + N_("Allow the use of unknown runas user and/or group ID"), + NULL, + }, { NULL, 0, NULL } }; diff -up ./plugins/sudoers/def_data.h.CVE-2019-19232 ./plugins/sudoers/def_data.h --- ./plugins/sudoers/def_data.h.CVE-2019-19232 2020-01-14 15:34:46.909027293 +0100 +++ ./plugins/sudoers/def_data.h 2020-01-14 15:41:33.658012401 +0100 @@ -236,6 +236,8 @@ #define def_legacy_group_processing (sudo_defs_table[I_LEGACY_GROUP_PROCESSING].sd_un.flag) #define I_CMND_NO_WAIT 118 #define def_cmnd_no_wait (sudo_defs_table[I_CMND_NO_WAIT].sd_un.flag) +#define I_RUNAS_ALLOW_UNKNOWN_ID 119 +#define def_runas_allow_unknown_id (sudo_defs_table[I_RUNAS_ALLOW_UNKNOWN_ID].sd_un.flag) enum def_tuple { never, diff -up ./plugins/sudoers/def_data.in.CVE-2019-19232 ./plugins/sudoers/def_data.in --- ./plugins/sudoers/def_data.in.CVE-2019-19232 2020-01-14 15:34:46.909027293 +0100 +++ ./plugins/sudoers/def_data.in 2020-01-14 15:42:42.176481484 +0100 @@ -372,3 +372,6 @@ legacy_group_processing cmnd_no_wait T_FLAG "Don't fork and wait for the command to finish, just exec it" +runas_allow_unknown_id + T_FLAG + "Allow the use of unknown runas user and/or group ID" diff -up ./plugins/sudoers/sudoers.c.CVE-2019-19232 ./plugins/sudoers/sudoers.c --- ./plugins/sudoers/sudoers.c.CVE-2019-19232 2020-01-14 15:34:46.905027266 +0100 +++ ./plugins/sudoers/sudoers.c 2020-01-14 15:34:46.910027299 +0100 @@ -105,6 +105,8 @@ static char *prev_user; static char *runas_user; static char *runas_group; static struct sudo_nss_list *snl; +static bool unknown_runas_uid; +static bool unknown_runas_gid; #ifdef __linux__ static struct rlimit nproclimit; @@ -354,6 +356,22 @@ sudoers_policy_main(int argc, char * con } } + /* Defer uid/gid checks until after defaults have been updated. */ + if (unknown_runas_uid && !def_runas_allow_unknown_id) { + audit_failure(NewArgc, NewArgv, N_("unknown user: %s"), + runas_pw->pw_name); + sudo_warnx(U_("unknown user: %s"), runas_pw->pw_name); + goto done; + } + if (runas_gr != NULL) { + if (unknown_runas_gid && !def_runas_allow_unknown_id) { + audit_failure(NewArgc, NewArgv, N_("unknown group: %s"), + runas_gr->gr_name); + sudo_warnx(U_("unknown group: %s"), runas_gr->gr_name); + goto done; + } + } + /* * Look up the timestamp dir owner if one is specified. */ @@ -1167,12 +1185,15 @@ set_runaspw(const char *user, bool quiet struct passwd *pw = NULL; debug_decl(set_runaspw, SUDOERS_DEBUG_PLUGIN) + unknown_runas_uid = false; if (*user == '#') { const char *errstr; uid_t uid = sudo_strtoid(user + 1, &errstr); if (errstr == NULL) { - if ((pw = sudo_getpwuid(uid)) == NULL) + if ((pw = sudo_getpwuid(uid)) == NULL) { + unknown_runas_uid = true; pw = sudo_fakepwnam(user, user_gid); + } } } if (pw == NULL) { @@ -1198,12 +1219,15 @@ set_runasgr(const char *group, bool quie struct group *gr = NULL; debug_decl(set_runasgr, SUDOERS_DEBUG_PLUGIN) + unknown_runas_gid = false; if (*group == '#') { const char *errstr; gid_t gid = sudo_strtoid(group + 1, &errstr); if (errstr == NULL) { - if ((gr = sudo_getgrgid(gid)) == NULL) + if ((gr = sudo_getgrgid(gid)) == NULL) { + unknown_runas_gid = true; gr = sudo_fakegrnam(group); + } } } if (gr == NULL) {