diff --git a/SOURCES/sudo-1.8.29-CVE-2019-18634.patch b/SOURCES/sudo-1.8.29-CVE-2019-18634.patch new file mode 100644 index 0000000..cc6fa49 --- /dev/null +++ b/SOURCES/sudo-1.8.29-CVE-2019-18634.patch @@ -0,0 +1,77 @@ +diff -up ./src/tgetpass.c.CVE-2019-18634 ./src/tgetpass.c +--- ./src/tgetpass.c.CVE-2019-18634 2019-10-28 13:27:39.000000000 +0100 ++++ ./src/tgetpass.c 2020-02-05 14:08:27.516101197 +0100 +@@ -61,7 +61,7 @@ enum tgetpass_errval { + static volatile sig_atomic_t signo[NSIG]; + + 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 +@@ -125,6 +125,7 @@ tgetpass(const char *prompt, int timeout + static char buf[SUDO_CONV_REPL_MAX + 1]; + int i, input, output, save_errno, ttyfd; + bool need_restart, neednl = false; ++ bool feedback = ISSET(flags, TGP_MASK); + enum tgetpass_errval errval; + debug_decl(tgetpass, SUDO_DEBUG_CONV) + +@@ -180,7 +181,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); +@@ -194,6 +195,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 +@@ -224,7 +228,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; + +@@ -360,7 +364,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; +@@ -389,15 +393,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/SOURCES/sudo-1.8.29-CVE-2019-19232.patch b/SOURCES/sudo-1.8.29-CVE-2019-19232.patch new file mode 100644 index 0000000..f7a006f --- /dev/null +++ b/SOURCES/sudo-1.8.29-CVE-2019-19232.patch @@ -0,0 +1,169 @@ +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) { diff --git a/SOURCES/sudo-1.8.29-CVE-2019-19234.patch b/SOURCES/sudo-1.8.29-CVE-2019-19234.patch new file mode 100644 index 0000000..264db7f --- /dev/null +++ b/SOURCES/sudo-1.8.29-CVE-2019-19234.patch @@ -0,0 +1,439 @@ +diff -up ./config.h.in.CVE-2019-19234 ./config.h.in +--- ./config.h.in.CVE-2019-19234 2019-10-28 13:28:52.000000000 +0100 ++++ ./config.h.in 2020-01-14 15:53:40.506988064 +0100 +@@ -334,6 +334,9 @@ + /* Define to 1 if you have the `getuserattr' function. */ + #undef HAVE_GETUSERATTR + ++/* Define to 1 if you have the `getusershell' function. */ ++#undef HAVE_GETUSERSHELL ++ + /* Define to 1 if you have the `getutid' function. */ + #undef HAVE_GETUTID + +diff -up ./configure.ac.CVE-2019-19234 ./configure.ac +--- ./configure.ac.CVE-2019-19234 2020-01-14 15:53:40.496987995 +0100 ++++ ./configure.ac 2020-01-14 15:53:40.509988084 +0100 +@@ -2562,6 +2562,10 @@ AC_CHECK_FUNCS([getdelim], [], [ + SUDO_APPEND_COMPAT_EXP(sudo_getdelim) + COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }getdelim_test" + ]) ++AC_CHECK_FUNCS([getusershell], [], [ ++ AC_LIBOBJ(getusershell) ++ SUDO_APPEND_COMPAT_EXP(sudo_getusershell) ++]) + AC_CHECK_FUNCS([reallocarray], [], [ + AC_LIBOBJ(reallocarray) + SUDO_APPEND_COMPAT_EXP(sudo_reallocarray) +diff -up ./configure.CVE-2019-19234 ./configure +--- ./configure.CVE-2019-19234 2019-10-28 13:29:14.000000000 +0100 ++++ ./configure 2020-01-14 15:53:40.509988084 +0100 +@@ -19395,6 +19395,32 @@ esac + fi + done + ++for ac_func in getusershell ++do : ++ ac_fn_c_check_func "$LINENO" "getusershell" "ac_cv_func_getusershell" ++if test "x$ac_cv_func_getusershell" = xyes; then : ++ cat >>confdefs.h <<_ACEOF ++#define HAVE_GETUSERSHELL 1 ++_ACEOF ++ ++else ++ ++ case " $LIBOBJS " in ++ *" getusershell.$ac_objext "* ) ;; ++ *) LIBOBJS="$LIBOBJS getusershell.$ac_objext" ++ ;; ++esac ++ ++ ++ for _sym in sudo_getusershell; do ++ COMPAT_EXP="${COMPAT_EXP}${_sym} ++" ++ done ++ ++ ++fi ++done ++ + for ac_func in reallocarray + do : + ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" +diff -up ./doc/sudoers.man.in.CVE-2019-19234 ./doc/sudoers.man.in +--- ./doc/sudoers.man.in.CVE-2019-19234 2020-01-14 15:53:40.503988043 +0100 ++++ ./doc/sudoers.man.in 2020-01-14 15:53:40.510988091 +0100 +@@ -2959,6 +2959,28 @@ Older versions of + \fBsudo\fR + always allowed matching of unknown user and group IDs. + .TP 18n ++runas_check_shell ++.br ++If enabled, ++\fBsudo\fR ++will only run commands as a user whose shell appears in the ++\fI/etc/shells\fR ++file, even if the invoking user's ++\fRRunas_List\fR ++would otherwise permit it. ++If no ++\fI/etc/shells\fR ++file is present, a system-dependent list of built-in default shells is used. ++On many operating systems, system users such as ++\(lqbin\(rq, ++do not have a valid shell and this flag can be used to prevent ++commands from being run as those users. ++This flag is ++\fIoff\fR ++by default. ++.sp ++This setting is only supported by version 1.8.29 or higher. ++.TP 18n + runaspw + If set, + \fBsudo\fR +diff -up ./doc/sudoers.mdoc.in.CVE-2019-19234 ./doc/sudoers.mdoc.in +--- ./doc/sudoers.mdoc.in.CVE-2019-19234 2020-01-14 15:53:40.504988050 +0100 ++++ ./doc/sudoers.mdoc.in 2020-01-14 15:53:40.510988091 +0100 +@@ -2784,6 +2784,26 @@ This setting is only supported by versio + Older versions of + .Nm sudo + always allowed matching of unknown user and group IDs. ++.It runas_check_shell ++If enabled, ++.Nm sudo ++will only run commands as a user whose shell appears in the ++.Pa /etc/shells ++file, even if the invoking user's ++.Li Runas_List ++would otherwise permit it. ++If no ++.Pa /etc/shells ++file is present, a system-dependent list of built-in default shells is used. ++On many operating systems, system users such as ++.Dq bin , ++do not have a valid shell and this flag can be used to prevent ++commands from being run as those users. ++This flag is ++.Em off ++by default. ++.Pp ++This setting is only supported by version 1.8.29 or higher. + .It runaspw + If set, + .Nm sudo +diff -up ./include/sudo_compat.h.CVE-2019-19234 ./include/sudo_compat.h +--- ./include/sudo_compat.h.CVE-2019-19234 2019-10-28 13:28:52.000000000 +0100 ++++ ./include/sudo_compat.h 2020-01-14 15:53:40.511988098 +0100 +@@ -407,6 +407,17 @@ __dso_public ssize_t sudo_getdelim(char + # undef getdelim + # define getdelim(_a, _b, _c, _d) sudo_getdelim((_a), (_b), (_c), (_d)) + #endif /* HAVE_GETDELIM */ ++#ifndef HAVE_GETUSERSHELL ++__dso_public char *sudo_getusershell(void); ++# undef getusershell ++# define getusershell() sudo_getusershell() ++__dso_public void sudo_setusershell(void); ++# undef setusershell ++# define setusershell() sudo_setusershell() ++__dso_public void sudo_endusershell(void); ++# undef endusershell ++# define endusershell() sudo_endusershell() ++#endif /* HAVE_GETUSERSHELL */ + #ifndef HAVE_UTIMENSAT + __dso_public int sudo_utimensat(int fd, const char *file, const struct timespec *times, int flag); + # undef utimensat +diff -up ./lib/util/getusershell.c.CVE-2019-19234 ./lib/util/getusershell.c +--- ./lib/util/getusershell.c.CVE-2019-19234 2020-01-14 15:53:40.511988098 +0100 ++++ ./lib/util/getusershell.c 2020-01-14 15:53:40.511988098 +0100 +@@ -0,0 +1,138 @@ ++/* ++ * SPDX-License-Identifier: ISC ++ * ++ * Copyright (c) 2019 Todd C. Miller ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * This is an open source non-commercial project. Dear PVS-Studio, please check it. ++ * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com ++ */ ++ ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define DEFAULT_TEXT_DOMAIN "sudo" ++#include "sudo_gettext.h" /* must be included before sudo_compat.h */ ++ ++#include "sudo_compat.h" ++#include "sudo_debug.h" ++#include "sudo_util.h" ++ ++static char **allowed_shells, **current_shell; ++static char *default_shells[] = { ++ "/bin/sh", ++ "/bin/ksh", ++ "/bin/ksh93", ++ "/bin/bash", ++ "/bin/dash", ++ "/bin/zsh", ++ "/bin/csh", ++ "/bin/tcsh", ++ NULL ++}; ++ ++static char ** ++read_shells(void) ++{ ++ size_t maxshells = 16, nshells = 0; ++ size_t linesize = 0; ++ char *line = NULL; ++ FILE *fp; ++ debug_decl(read_shells, SUDO_DEBUG_UTIL) ++ ++ if ((fp = fopen("/etc/shells", "r")) == NULL) ++ goto bad; ++ ++ free(allowed_shells); ++ allowed_shells = reallocarray(NULL, maxshells, sizeof(char *)); ++ if (allowed_shells == NULL) ++ goto bad; ++ ++ while (sudo_parseln(&line, &linesize, NULL, fp, PARSELN_CONT_IGN) != -1) { ++ if (nshells + 1 >= maxshells) { ++ char **new_shells; ++ ++ new_shells = reallocarray(NULL, maxshells + 16, sizeof(char *)); ++ if (new_shells == NULL) ++ goto bad; ++ allowed_shells = new_shells; ++ maxshells += 16; ++ } ++ if ((allowed_shells[nshells] = strdup(line)) == NULL) ++ goto bad; ++ nshells++; ++ } ++ allowed_shells[nshells] = NULL; ++ ++ free(line); ++ fclose(fp); ++ debug_return_ptr(allowed_shells); ++bad: ++ free(line); ++ if (fp != NULL) ++ fclose(fp); ++ while (nshells != 0) ++ free(allowed_shells[--nshells]); ++ free(allowed_shells); ++ allowed_shells = NULL; ++ debug_return_ptr(default_shells); ++} ++ ++void ++sudo_setusershell(void) ++{ ++ debug_decl(setusershell, SUDO_DEBUG_UTIL) ++ ++ current_shell = read_shells(); ++ ++ debug_return; ++} ++ ++void ++sudo_endusershell(void) ++{ ++ debug_decl(endusershell, SUDO_DEBUG_UTIL) ++ ++ if (allowed_shells != NULL) { ++ char **shell; ++ ++ for (shell = allowed_shells; *shell != NULL; shell++) ++ free(*shell); ++ free(allowed_shells); ++ allowed_shells = NULL; ++ } ++ current_shell = NULL; ++ ++ debug_return; ++} ++ ++char * ++sudo_getusershell(void) ++{ ++ debug_decl(getusershell, SUDO_DEBUG_UTIL) ++ ++ if (current_shell == NULL) ++ current_shell = read_shells(); ++ ++ debug_return_str(*current_shell++); ++} +diff -up ./lib/util/Makefile.in.CVE-2019-19234 ./lib/util/Makefile.in +--- ./lib/util/Makefile.in.CVE-2019-19234 2019-10-28 13:28:53.000000000 +0100 ++++ ./lib/util/Makefile.in 2020-01-14 15:53:40.511988098 +0100 +@@ -678,6 +678,18 @@ gettime.i: $(srcdir)/gettime.c $(incdir) + $(CC) -E -o $@ $(CPPFLAGS) $< + gettime.plog: gettime.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/gettime.c --i-file $< --output-file $@ ++getusershell.lo: $(srcdir)/getusershell.c $(incdir)/compat/stdbool.h \ ++ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ ++ $(incdir)/sudo_gettext.h $(incdir)/sudo_queue.h \ ++ $(incdir)/sudo_util.h $(top_builddir)/config.h ++ $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/getusershell.c ++getusershell.i: $(srcdir)/getusershell.c $(incdir)/compat/stdbool.h \ ++ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ ++ $(incdir)/sudo_gettext.h $(incdir)/sudo_queue.h \ ++ $(incdir)/sudo_util.h $(top_builddir)/config.h ++ $(CC) -E -o $@ $(CPPFLAGS) $< ++getusershell.plog: getusershell.i ++ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/getusershell.c --i-file $< --output-file $@ + gidlist.lo: $(srcdir)/gidlist.c $(incdir)/compat/stdbool.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ +diff -up ./MANIFEST.CVE-2019-19234 ./MANIFEST +--- ./MANIFEST.CVE-2019-19234 2019-10-28 13:28:52.000000000 +0100 ++++ ./MANIFEST 2020-01-14 15:53:40.506988064 +0100 +@@ -103,6 +103,7 @@ lib/util/getgrouplist.c + lib/util/gethostname.c + lib/util/getopt_long.c + lib/util/gettime.c ++lib/util/getusershell.c + lib/util/gidlist.c + lib/util/glob.c + lib/util/inet_ntop.c +diff -up ./mkdep.pl.CVE-2019-19234 ./mkdep.pl +--- ./mkdep.pl.CVE-2019-19234 2019-10-28 13:28:52.000000000 +0100 ++++ ./mkdep.pl 2020-01-14 15:53:40.511988098 +0100 +@@ -116,7 +116,7 @@ sub mkdep { + # XXX - fill in AUTH_OBJS from contents of the auth dir instead + $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:; + $makefile =~ s:\@DIGEST\@:digest.lo digest_openssl.lo digest_gcrypt.lo:; +- $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.lo getopt_long.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo utimens.lo vsyslog.lo pipe2.lo:; ++ $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.lo getopt_long.lo getusershell.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo utimens.lo vsyslog.lo pipe2.lo:; + + # Parse OBJS lines + my %objs; +diff -up ./plugins/sudoers/check.c.CVE-2019-19234 ./plugins/sudoers/check.c +--- ./plugins/sudoers/check.c.CVE-2019-19234 2019-10-28 13:27:45.000000000 +0100 ++++ ./plugins/sudoers/check.c 2020-01-14 15:53:40.511988098 +0100 +@@ -333,3 +333,28 @@ get_authpw(int mode) + + debug_return_ptr(pw); + } ++ ++/* ++ * Returns true if the specified shell is allowed by /etc/shells, else false. ++ */ ++bool ++check_user_shell(const struct passwd *pw) ++{ ++ const char *shell; ++ debug_decl(check_user_shell, SUDOERS_DEBUG_AUTH) ++ ++ if (!def_runas_check_shell) ++ debug_return_bool(true); ++ ++ sudo_debug_printf(SUDO_DEBUG_INFO, ++ "%s: checking /etc/shells for %s", __func__, pw->pw_shell); ++ ++ setusershell(); ++ while ((shell = getusershell()) != NULL) { ++ if (strcmp(shell, pw->pw_shell) == 0) ++ debug_return_bool(true); ++ } ++ endusershell(); ++ ++ debug_return_bool(false); ++} +diff -up ./plugins/sudoers/def_data.c.CVE-2019-19234 ./plugins/sudoers/def_data.c +--- ./plugins/sudoers/def_data.c.CVE-2019-19234 2020-01-14 15:53:40.504988050 +0100 ++++ ./plugins/sudoers/def_data.c 2020-01-14 15:53:40.511988098 +0100 +@@ -518,6 +518,10 @@ struct sudo_defs_types sudo_defs_table[] + N_("Allow the use of unknown runas user and/or group ID"), + NULL, + }, { ++ "runas_check_shell", T_FLAG, ++ N_("Only permit running commands as a user with a valid shell"), ++ NULL, ++ }, { + NULL, 0, NULL + } + }; +diff -up ./plugins/sudoers/def_data.h.CVE-2019-19234 ./plugins/sudoers/def_data.h +--- ./plugins/sudoers/def_data.h.CVE-2019-19234 2020-01-14 15:53:40.512988105 +0100 ++++ ./plugins/sudoers/def_data.h 2020-01-14 15:58:06.927808982 +0100 +@@ -238,6 +238,8 @@ + #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) ++#define I_RUNAS_CHECK_SHELL 120 ++#define def_runas_check_shell (sudo_defs_table[I_RUNAS_CHECK_SHELL].sd_un.flag) + + enum def_tuple { + never, +diff -up ./plugins/sudoers/def_data.in.CVE-2019-19234 ./plugins/sudoers/def_data.in +--- ./plugins/sudoers/def_data.in.CVE-2019-19234 2020-01-14 15:53:40.505988057 +0100 ++++ ./plugins/sudoers/def_data.in 2020-01-14 15:53:40.512988105 +0100 +@@ -375,3 +375,7 @@ cmnd_no_wait + runas_allow_unknown_id + T_FLAG + "Allow the use of unknown runas user and/or group ID" ++runas_check_shell ++ T_FLAG ++ "Only permit running commands as a user with a valid shell" ++ +diff -up ./plugins/sudoers/sudoers.c.CVE-2019-19234 ./plugins/sudoers/sudoers.c +--- ./plugins/sudoers/sudoers.c.CVE-2019-19234 2020-01-14 15:53:40.505988057 +0100 ++++ ./plugins/sudoers/sudoers.c 2020-01-14 15:53:40.512988105 +0100 +@@ -273,7 +273,7 @@ sudoers_policy_main(int argc, char * con + /* Not an audit event. */ + sudo_warnx(U_("sudoers specifies that root is not allowed to sudo")); + goto bad; +- } ++ } + + if (!set_perms(PERM_INITIAL)) + goto bad; +@@ -412,6 +412,13 @@ sudoers_policy_main(int argc, char * con + goto bad; + } + ++ /* Check runas user's shell. */ ++ if (!check_user_shell(runas_pw)) { ++ log_warningx(SLOG_RAW_MSG, N_("invalid shell for user %s: %s"), ++ runas_pw->pw_name, runas_pw->pw_shell); ++ goto bad; ++ } ++ + /* + * We don't reset the environment for sudoedit or if the user + * specified the -E command line flag and they have setenv privs. +diff -up ./plugins/sudoers/sudoers.h.CVE-2019-19234 ./plugins/sudoers/sudoers.h +--- ./plugins/sudoers/sudoers.h.CVE-2019-19234 2020-01-14 15:53:40.502988036 +0100 ++++ ./plugins/sudoers/sudoers.h 2020-01-14 15:53:40.512988105 +0100 +@@ -264,6 +264,7 @@ int find_path(const char *infile, char * + + /* check.c */ + int check_user(int validate, int mode); ++bool check_user_shell(const struct passwd *pw); + bool user_is_exempt(void); + + /* prompt.c */ diff --git a/SOURCES/sudo-1.8.29-expired-password-part1.patch b/SOURCES/sudo-1.8.29-expired-password-part1.patch new file mode 100644 index 0000000..8c8a0bb --- /dev/null +++ b/SOURCES/sudo-1.8.29-expired-password-part1.patch @@ -0,0 +1,154 @@ +From 4b6de608c25a6ffbdb507be958e12f814b43077c Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Wed, 4 Dec 2019 12:38:22 -0700 +Subject: [PATCH] Only update the time stamp entry after the approval function + has succeeded. Bug #910 + +--- + plugins/sudoers/check.c | 59 +++++++++++++++++++---------------------- + 1 file changed, 27 insertions(+), 32 deletions(-) + +diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c +index db8e05161..ea1d89085 100644 +--- a/plugins/sudoers/check.c ++++ b/plugins/sudoers/check.c +@@ -51,6 +51,7 @@ static bool display_lecture(int); + static struct passwd *get_authpw(int); + + struct getpass_closure { ++ int tstat; + void *cookie; + struct passwd *auth_pw; + }; +@@ -89,27 +90,20 @@ getpass_resume(int signo, void *vclosure) + * or -1 on fatal error. + */ + static int +-check_user_interactive(int validated, int mode, struct passwd *auth_pw) ++check_user_interactive(int validated, int mode, struct getpass_closure *closure) + { + struct sudo_conv_callback cb, *callback = NULL; +- struct getpass_closure closure; +- int status = TS_ERROR; + int ret = -1; + char *prompt; + bool lectured; + debug_decl(check_user_interactive, SUDOERS_DEBUG_AUTH) + +- /* Setup closure for getpass_{suspend,resume} */ +- closure.auth_pw = auth_pw; +- closure.cookie = NULL; +- sudo_pw_addref(closure.auth_pw); +- + /* Open, lock and read time stamp file if we are using it. */ + if (!ISSET(mode, MODE_IGNORE_TICKET)) { + /* Open time stamp file and check its status. */ +- closure.cookie = timestamp_open(user_name, user_sid); +- if (timestamp_lock(closure.cookie, closure.auth_pw)) +- status = timestamp_status(closure.cookie, closure.auth_pw); ++ closure->cookie = timestamp_open(user_name, user_sid); ++ if (timestamp_lock(closure->cookie, closure->auth_pw)) ++ closure->tstat = timestamp_status(closure->cookie, closure->auth_pw); + + /* Construct callback for getpass function. */ + memset(&cb, 0, sizeof(cb)); +@@ -120,7 +114,7 @@ check_user_interactive(int validated, int mode, struct passwd *auth_pw) + callback = &cb; + } + +- switch (status) { ++ switch (closure->tstat) { + case TS_FATAL: + /* Fatal error (usually setuid failure), unsafe to proceed. */ + goto done; +@@ -144,32 +138,22 @@ check_user_interactive(int validated, int mode, struct passwd *auth_pw) + } + + /* XXX - should not lecture if askpass helper is being used. */ +- lectured = display_lecture(status); ++ lectured = display_lecture(closure->tstat); + + /* Expand any escapes in the prompt. */ + prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt, +- closure.auth_pw->pw_name); ++ closure->auth_pw->pw_name); + if (prompt == NULL) + goto done; + +- ret = verify_user(closure.auth_pw, prompt, validated, callback); ++ ret = verify_user(closure->auth_pw, prompt, validated, callback); + if (ret == true && lectured) + (void)set_lectured(); /* lecture error not fatal */ + free(prompt); + break; + } + +- /* +- * Only update time stamp if user was validated. +- * Failure to update the time stamp is not a fatal error. +- */ +- if (ret == true && ISSET(validated, VALIDATE_SUCCESS) && status != TS_ERROR) +- (void)timestamp_update(closure.cookie, closure.auth_pw); + done: +- if (closure.cookie != NULL) +- timestamp_close(closure.cookie); +- sudo_pw_delref(closure.auth_pw); +- + debug_return_int(ret); + } + +@@ -180,7 +164,7 @@ done: + int + check_user(int validated, int mode) + { +- struct passwd *auth_pw; ++ struct getpass_closure closure = { TS_ERROR }; + int ret = -1; + bool exempt = false; + debug_decl(check_user, SUDOERS_DEBUG_AUTH) +@@ -189,9 +173,9 @@ check_user(int validated, int mode) + * Init authentication system regardless of whether we need a password. + * Required for proper PAM session support. + */ +- if ((auth_pw = get_authpw(mode)) == NULL) ++ if ((closure.auth_pw = get_authpw(mode)) == NULL) + goto done; +- if (sudo_auth_init(auth_pw) == -1) ++ if (sudo_auth_init(closure.auth_pw) == -1) + goto done; + + /* +@@ -222,15 +206,26 @@ check_user(int validated, int mode) + } + } + +- ret = check_user_interactive(validated, mode, auth_pw); ++ ret = check_user_interactive(validated, mode, &closure); + + done: + if (ret == true) { + /* The approval function may disallow a user post-authentication. */ +- ret = sudo_auth_approval(auth_pw, validated, exempt); ++ ret = sudo_auth_approval(closure.auth_pw, validated, exempt); ++ ++ /* ++ * Only update time stamp if user validated and was approved. ++ * Failure to update the time stamp is not a fatal error. ++ */ ++ if (ret == true && closure.tstat != TS_ERROR) { ++ if (ISSET(validated, VALIDATE_SUCCESS)) ++ (void)timestamp_update(closure.cookie, closure.auth_pw); ++ } + } +- sudo_auth_cleanup(auth_pw); +- sudo_pw_delref(auth_pw); ++ timestamp_close(closure.cookie); ++ sudo_auth_cleanup(closure.auth_pw); ++ if (closure.auth_pw != NULL) ++ sudo_pw_delref(closure.auth_pw); + + debug_return_int(ret); + } +-- +2.25.1 + diff --git a/SOURCES/sudo-1.8.29-expired-password-part2.patch b/SOURCES/sudo-1.8.29-expired-password-part2.patch new file mode 100644 index 0000000..47f94d4 --- /dev/null +++ b/SOURCES/sudo-1.8.29-expired-password-part2.patch @@ -0,0 +1,29 @@ +From 5472b1751645f750e42a0ba6daac667983b1a56c Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Fri, 24 Jan 2020 11:13:55 -0700 +Subject: [PATCH] Fix crash in sudo 1.8.30 when suspending sudo at the password + prompt. The closure pointer in sudo_conv_callback was being filled in with a + struct getpass_closure ** instead of a struct getpass_closure *. The bug was + introduced in the fix for Bug #910; previously the closure variable was a + struct getpass_closure, not a pointer. Fix from Michael Norton; Bug #914. + +--- + plugins/sudoers/check.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c +index 72e87eef6..9b03c7a05 100644 +--- a/plugins/sudoers/check.c ++++ b/plugins/sudoers/check.c +@@ -108,7 +108,7 @@ check_user_interactive(int validated, int mode, struct getpass_closure *closure) + /* Construct callback for getpass function. */ + memset(&cb, 0, sizeof(cb)); + cb.version = SUDO_CONV_CALLBACK_VERSION; +- cb.closure = &closure; ++ cb.closure = closure; + cb.on_suspend = getpass_suspend; + cb.on_resume = getpass_resume; + callback = &cb; +-- +2.25.1 + diff --git a/SPECS/sudo.spec b/SPECS/sudo.spec index aac09cf..6e9b263 100644 --- a/SPECS/sudo.spec +++ b/SPECS/sudo.spec @@ -1,7 +1,7 @@ Summary: Allows restricted root access for specified users Name: sudo Version: 1.8.29 -Release: 2%{?dist} +Release: 6%{?dist} License: ISC Group: Applications/System URL: http://www.courtesan.com/sudo/ @@ -44,6 +44,17 @@ Patch4: sudo-1.8.23-legacy-group-processing.patch Patch5: sudo-1.8.23-nowaitopt.patch # 1312486 - RHEL7 sudo logs username "root" instead of realuser in /var/log/secure Patch6: sudo-1.8.6p7-logsudouser.patch +# 1786987 - CVE-2019-19232 sudo: attacker with access to a Runas ALL sudoer account +# can impersonate a nonexistent user [rhel-8] +Patch7: sudo-1.8.29-CVE-2019-19232.patch +# 1796518 - [RFE] add optional check for the target user shell +Patch8: sudo-1.8.29-CVE-2019-19234.patch +# 1798093 - CVE-2019-18634 sudo: Stack based buffer overflow in when pwfeedback is enabled [rhel-8.2.0] +Patch9: sudo-1.8.29-CVE-2019-18634.patch + +# 1815164 - sudo allows privilege escalation with expire password +Patch10: sudo-1.8.29-expired-password-part1.patch +Patch11: sudo-1.8.29-expired-password-part2.patch %description Sudo (superuser do) allows a system administrator to give certain @@ -74,6 +85,12 @@ plugins that use %{name}. %patch4 -p1 -b .legacy-processing %patch5 -p1 -b .nowait %patch6 -p1 -b .logsudouser +%patch7 -p1 -b .CVE-2019-19232 +%patch8 -p1 -b .target-shell +%patch9 -p1 -b .CVE-2019-18634 + +%patch10 -p1 -b .expired1 +%patch11 -p1 -b .expired2 %build # Remove bundled copy of zlib @@ -233,6 +250,22 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/sudo_plugin.8* %changelog +* Tue Apr 28 2020 Radovan Sroka - 1.8.29-6 +- RHEL 8.3 ERRATUM +- sudo allows privilege escalation with expire password +Resolves: rhbz#1815164 + +* Wed Feb 05 2020 Radovan Sroka - 1.8.29-5 +- RHEL 8.2 ERRATUM +- CVE-2019-18634 +Resolves: rhbz#1798093 + +* Tue Jan 14 2020 Radovan Sroka - 1.8.29-4 +- RHEL 8.2 ERRATUM +- CVE-2019-19232 +Resolves: rhbz#1786987 +Resolves: rhbz#1796518 + * Wed Oct 30 2019 Radovan Sroka - 1.8.29-2 - RHEL 8.2 ERRATUM - rebase to 1.8.29