update to 1.9.2

This commit is contained in:
yixiangzhike 2020-07-28 19:44:17 +08:00
parent ff315ff92c
commit b5334876c7
8 changed files with 87 additions and 959 deletions

View File

@ -1,199 +0,0 @@
From 807e17ceedf2500aeca67b37f62463ee112d63c4 Mon Sep 17 00:00:00 2001
From: Todd C. Miller <Todd.Miller@sudo.ws>
Date: Mon, 09 Dec 2019 17:14:06 -0700
Subject: [PATCH] Fix CVE-2019-19234
Add a new flag "allow_unknown_runas_id" to control matching of unknown IDs.
Previous, sudo would always allow unknown user or group IDs if the
sudoers entry permitted it. This included the "ALL" alias.
With this change, the admin must explicitly enable support for unknown IDs.
---
doc/sudoers.man.in | 17 +++++++++++++++++
doc/sudoers.mdoc.in | 16 ++++++++++++++++
plugins/sudoers/def_data.c | 4 ++++
plugins/sudoers/def_data.h | 2 ++
plugins/sudoers/def_data.in | 3 +++
plugins/sudoers/defaults.c | 1 +
plugins/sudoers/sudoers.c | 28 ++++++++++++++++++++++++++--
7 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in
index e2470b5..45a600f 100644
--- a/doc/sudoers.man.in
+++ b/doc/sudoers.man.in
@@ -2869,6 +2869,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.30 or higher.
+Older versions of
+\fBsudo\fR
+always allowed matching of unknown user and group IDs.
+.TP 18n
runaspw
If set,
\fBsudo\fR
diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in
index 2053b5d..6a511d9 100644
--- a/doc/sudoers.mdoc.in
+++ b/doc/sudoers.mdoc.in
@@ -2698,6 +2698,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.30 or higher.
+Older versions of
+.Nm sudo
+always allowed matching of unknown user and group IDs.
.It runaspw
If set,
.Nm sudo
diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c
index 07e3433..97eaf79 100644
--- a/plugins/sudoers/def_data.c
+++ b/plugins/sudoers/def_data.c
@@ -494,6 +494,10 @@ struct sudo_defs_types sudo_defs_table[] = {
N_("Ignore case when matching group names"),
NULL,
}, {
+ "runas_allow_unknown_id", T_FLAG,
+ N_("Allow the use of unknown runas user and/or group ID"),
+ NULL,
+ }, {
NULL, 0, NULL
}
};
diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h
index 65f10c3..55878c9 100644
--- a/plugins/sudoers/def_data.h
+++ b/plugins/sudoers/def_data.h
@@ -226,6 +226,8 @@
#define def_case_insensitive_user (sudo_defs_table[I_CASE_INSENSITIVE_USER].sd_un.flag)
#define I_CASE_INSENSITIVE_GROUP 113
#define def_case_insensitive_group (sudo_defs_table[I_CASE_INSENSITIVE_GROUP].sd_un.flag)
+#define I_RUNAS_ALLOW_UNKNOWN_ID 114
+#define def_runas_allow_unknown_id (sudo_defs_table[I_RUNAS_ALLOW_UNKNOWN_ID].sd_un.flag)
enum def_tuple {
never,
diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in
index 99d4360..cf0eead 100644
--- a/plugins/sudoers/def_data.in
+++ b/plugins/sudoers/def_data.in
@@ -357,3 +357,6 @@ case_insensitive_user
case_insensitive_group
T_FLAG
"Ignore case when matching group names"
+runas_allow_unknown_id
+ T_FLAG
+ "Allow the use of unknown runas user and/or group ID"
diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c
index 4c8c262..d5b1d9c 100644
--- a/plugins/sudoers/defaults.c
+++ b/plugins/sudoers/defaults.c
@@ -574,6 +574,7 @@ init_defaults(void)
def_sudoedit_checkdir = true;
def_iolog_mode = S_IRUSR|S_IWUSR;
def_fdexec = digest_only;
+ def_runas_allow_unknown_id = false;
/* Syslog options need special care since they both strings and ints */
#if (LOGGING & SLOG_SYSLOG)
diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c
index 1267949..b393d70 100644
--- a/plugins/sudoers/sudoers.c
+++ b/plugins/sudoers/sudoers.c
@@ -101,6 +101,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;
@@ -332,6 +334,22 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
}
}
+ /* 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.
*/
@@ -1124,12 +1142,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, NULL, NULL, &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) {
@@ -1155,12 +1176,15 @@ set_runasgr(const char *group, bool quiet)
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, NULL, NULL, &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) {
--
1.8.3.1

View File

@ -1,485 +0,0 @@
From 1078336fb8769eb9e022d088f5b2db443bb775d6 Mon Sep 17 00:00:00 2001
From: Todd C. Miller <Todd.Miller@sudo.ws>
Date: Mon, 09 Dec 2019 19:29:45 -0700
Subject: [PATCH] Fix CVE-2019-19234
Add runas_check_shell flag to require a runas user to have a valid shell.
Not enabled by default.
---
MANIFEST | 1 +
config.h.in | 3 +
configure | 26 +++++++++
configure.ac | 6 +-
doc/sudoers.man.in | 22 +++++++
doc/sudoers.mdoc.in | 20 +++++++
include/sudo_compat.h | 11 ++++
lib/util/Makefile.in | 12 ++++
lib/util/getusershell.c | 138 ++++++++++++++++++++++++++++++++++++++++++++
mkdep.pl | 2 +-
plugins/sudoers/check.c | 25 ++++++++
plugins/sudoers/def_data.c | 4 ++
plugins/sudoers/def_data.h | 2 +
plugins/sudoers/def_data.in | 3 +
plugins/sudoers/sudoers.c | 7 +++
plugins/sudoers/sudoers.h | 1 +
16 files changed, 281 insertions(+), 2 deletions(-)
create mode 100644 lib/util/getusershell.c
diff --git a/MANIFEST b/MANIFEST
index 08d7f25..d883174 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -111,6 +111,7 @@ lib/util/gethostname.c
lib/util/getline.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 --git a/config.h.in b/config.h.in
index 9b83b12..c65a6f7 100644
--- a/config.h.in
+++ b/config.h.in
@@ -337,6 +337,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 --git a/configure b/configure
index e1b5dbb..658768e 100755
--- a/configure
+++ b/configure
@@ -19418,6 +19418,32 @@ done
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 --git a/configure.ac b/configure.ac
index 962a032..c6d6c55 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
dnl
dnl Use the top-level autogen.sh script to generate configure and config.h.in
dnl
-dnl Copyright (c) 1994-1996,1998-2018 Todd C. Miller <Todd.Miller@sudo.ws>
+dnl Copyright (c) 1994-1996,1998-2019 Todd C. Miller <Todd.Miller@sudo.ws>
dnl
AC_PREREQ([2.59])
AC_INIT([sudo], [1.8.27], [https://bugzilla.sudo.ws/], [sudo])
@@ -2839,6 +2839,10 @@ AC_CHECK_FUNCS([vsyslog], [], [
SUDO_APPEND_COMPAT_EXP(sudo_vsyslog)
COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }vsyslog_test"
])
+AC_CHECK_FUNCS([getusershell], [], [
+ AC_LIBOBJ(getusershell)
+ SUDO_APPEND_COMPAT_EXP(sudo_getusershell)
+])
dnl
dnl 4.4BSD-based systems can force the password or group file to be held open
dnl
diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in
index 45a600f..8a97a55 100644
--- a/doc/sudoers.man.in
+++ b/doc/sudoers.man.in
@@ -2886,6 +2886,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.30 or higher.
+.TP 18n
runaspw
If set,
\fBsudo\fR
diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in
index 6a511d9..ec7ed4f 100644
--- a/doc/sudoers.mdoc.in
+++ b/doc/sudoers.mdoc.in
@@ -2714,6 +2714,26 @@ This setting is only supported by version 1.8.30 or higher.
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.30 or higher.
.It runaspw
If set,
.Nm sudo
diff --git a/include/sudo_compat.h b/include/sudo_compat.h
index 5c32840..3faa167 100644
--- a/include/sudo_compat.h
+++ b/include/sudo_compat.h
@@ -409,6 +409,17 @@ __dso_public ssize_t sudo_getline(char **bufp, size_t *bufsizep, FILE *fp);
# undef getline
# define getline(_a, _b, _c) sudo_getline((_a), (_b), (_c))
#endif /* HAVE_GETLINE */
+#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 --git a/lib/util/Makefile.in b/lib/util/Makefile.in
index cadfcf2..aa21ac9 100644
--- a/lib/util/Makefile.in
+++ b/lib/util/Makefile.in
@@ -630,6 +630,18 @@ gettime.i: $(srcdir)/gettime.c $(incdir)/compat/stdbool.h \
$(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 --git a/lib/util/getusershell.c b/lib/util/getusershell.c
new file mode 100644
index 0000000..6aeae3b
--- /dev/null
+++ b/lib/util/getusershell.c
@@ -0,0 +1,138 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2019 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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 <config.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#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 --git a/mkdep.pl b/mkdep.pl
index 2040320..02b5f41 100755
--- a/mkdep.pl
+++ b/mkdep.pl
@@ -112,7 +112,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 getline.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 strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo strtonum.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 getline.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 strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo strtonum.lo utimens.lo vsyslog.lo pipe2.lo:;
# Parse OBJS lines
my %objs;
diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c
index 92f859c..31d2615 100644
--- a/plugins/sudoers/check.c
+++ b/plugins/sudoers/check.c
@@ -331,3 +331,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 --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c
index 97eaf79..7b111f8 100644
--- a/plugins/sudoers/def_data.c
+++ b/plugins/sudoers/def_data.c
@@ -498,6 +498,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 --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h
index 55878c9..50725e6 100644
--- a/plugins/sudoers/def_data.h
+++ b/plugins/sudoers/def_data.h
@@ -228,6 +228,8 @@
#define def_case_insensitive_group (sudo_defs_table[I_CASE_INSENSITIVE_GROUP].sd_un.flag)
#define I_RUNAS_ALLOW_UNKNOWN_ID 114
#define def_runas_allow_unknown_id (sudo_defs_table[I_RUNAS_ALLOW_UNKNOWN_ID].sd_un.flag)
+#define I_RUNAS_CHECK_SHELL 115
+#define def_runas_check_shell (sudo_defs_table[I_RUNAS_CHECK_SHELL].sd_un.flag)
enum def_tuple {
never,
diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in
index cf0eead..bb81d8b 100644
--- a/plugins/sudoers/def_data.in
+++ b/plugins/sudoers/def_data.in
@@ -360,3 +360,6 @@ case_insensitive_group
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 --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c
index b393d70..a791942 100644
--- a/plugins/sudoers/sudoers.c
+++ b/plugins/sudoers/sudoers.c
@@ -390,6 +390,13 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
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 --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h
index 28dbbb3..d33c4ef 100644
--- a/plugins/sudoers/sudoers.h
+++ b/plugins/sudoers/sudoers.h
@@ -250,6 +250,7 @@ int find_path(const char *infile, char **outfile, struct stat *sbp,
/* check.c */
int check_user(int validate, int mode);
+bool check_user_shell(const struct passwd *pw);
bool user_is_exempt(void);
/* prompt.c */
--
1.8.3.1

View File

@ -1,96 +0,0 @@
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

Binary file not shown.

BIN
sudo-1.9.2.tar.gz Normal file

Binary file not shown.

View File

@ -1,6 +1,6 @@
Name: sudo Name: sudo
Version: 1.8.27 Version: 1.9.2
Release: 5 Release: 1
Summary: Allows restricted root access for specified users Summary: Allows restricted root access for specified users
License: ISC License: ISC
URL: http://www.courtesan.com/sudo/ URL: http://www.courtesan.com/sudo/
@ -10,11 +10,6 @@ Source1: sudoers
Source2: sudo Source2: sudo
Source3: sudo-i Source3: sudo-i
Patch6000: sudo_minus_1_uid.patch
Patch6001: strtoid_minus_1_test_fix.patch
Patch6002: Fix-CVE-2019-19232-control-matching-of-unknown-IDs.patch
Patch6003: Fix-CVE-2019-19234-add-runas_check_shell-flag.patch
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: pam Requires: pam
Recommends: vim-minimal Recommends: vim-minimal
@ -51,6 +46,8 @@ export CFLAGS="$RPM_OPT_FLAGS -fpie" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now"
--libdir=%{_libdir} \ --libdir=%{_libdir} \
--docdir=%{_pkgdocdir} \ --docdir=%{_pkgdocdir} \
--disable-root-mailer \ --disable-root-mailer \
--disable-log-server \
--disable-log-client \
--with-logging=syslog \ --with-logging=syslog \
--with-logfac=authpriv \ --with-logfac=authpriv \
--with-pam \ --with-pam \
@ -117,6 +114,7 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
%attr(0750,root,root) %dir /etc/sudoers.d/ %attr(0750,root,root) %dir /etc/sudoers.d/
%attr(0644,root,root) %{_tmpfilesdir}/sudo.conf %attr(0644,root,root) %{_tmpfilesdir}/sudo.conf
%attr(0644,root,root) /etc/dnf/protected.d/sudo.conf %attr(0644,root,root) /etc/dnf/protected.d/sudo.conf
%attr(0640,root,root) /etc/sudo.conf
%attr(4111,root,root) %{_bindir}/sudo %attr(4111,root,root) %{_bindir}/sudo
%attr(0111,root,root) %{_bindir}/sudoreplay %attr(0111,root,root) %{_bindir}/sudoreplay
%{_bindir}/sudoedit %{_bindir}/sudoedit
@ -127,6 +125,8 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
%attr(0644,root,root) %{_libexecdir}/sudo/sudoers.so %attr(0644,root,root) %{_libexecdir}/sudo/sudoers.so
%attr(0644,root,root) %{_libexecdir}/sudo/group_file.so %attr(0644,root,root) %{_libexecdir}/sudo/group_file.so
%attr(0644,root,root) %{_libexecdir}/sudo/system_group.so %attr(0644,root,root) %{_libexecdir}/sudo/system_group.so
%attr(0644,root,root) %{_libexecdir}/sudo/audit_json.so
%attr(0644,root,root) %{_libexecdir}/sudo/sample_approval.so
%attr(0644,root,root) %{_libexecdir}/sudo/libsudo_util.so* %attr(0644,root,root) %{_libexecdir}/sudo/libsudo_util.so*
%dir /var/db/sudo %dir /var/db/sudo
%dir /var/db/sudo/lectured %dir /var/db/sudo/lectured
@ -149,6 +149,9 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
%exclude %{_pkgdocdir}/ChangeLog %exclude %{_pkgdocdir}/ChangeLog
%changelog %changelog
* Wed Jul 29 2020 zhangxingliang <zhangxingliang3@huawei.com> - 1.9.2-1
- update to 1.9.2
* Fri Apr 17 2020 Anakin Zhang <nbztx@126.com> - 1.8.27-5 * Fri Apr 17 2020 Anakin Zhang <nbztx@126.com> - 1.8.27-5
- Read drop-in files from /etc/sudoers.d - Read drop-in files from /etc/sudoers.d

View File

@ -1,172 +0,0 @@
Treat an ID of -1 as invalid since that means "no change".
Fixes CVE-2019-14287.
Found by Joe Vennix from Apple Information Security.
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)

77
sudoers
View File

@ -7,6 +7,45 @@
## ##
## This file must be edited with the 'visudo' command. ## This file must be edited with the 'visudo' command.
## Host Aliases
## Groups of machines. You may prefer to use hostnames (perhaps using
## wildcards for entire domains) or IP addresses instead.
# Host_Alias FILESERVERS = fs1, fs2
# Host_Alias MAILSERVERS = smtp, smtp2
## User Aliases
## These aren't often necessary, as you can use regular groups
## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname
## rather than USERALIAS
# User_Alias ADMINS = jsmith, mikem
## Command Aliases
## These are groups of related commands...
## Networking
# Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool
## Installation and management of software
# Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum
## Services
# Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, /usr/bin/systemctl start, /usr/bin/systemctl stop, /usr/bin/systemctl reload, /usr/bin/systemctl restart, /usr/bin/systemctl status, /usr/bin/systemctl enable, /usr/bin/systemctl disable
## Updating the locate database
# Cmnd_Alias LOCATE = /usr/bin/updatedb
## Storage
# Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount
## Delegating permissions
# Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp
## Processes
# Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall
## Drivers
# Cmnd_Alias DRIVERS = /sbin/modprobe
# Defaults specification # Defaults specification
@ -15,6 +54,24 @@
# #
Defaults !visiblepw Defaults !visiblepw
#
# Preserving HOME has security implications since many programs
# use it when searching for configuration files. Note that HOME
# is already set when the the env_reset option is enabled, so
# this option is only effective for configurations where either
# env_reset is disabled or HOME is present in the env_keep list.
#
Defaults always_set_home
Defaults match_group_by_gid
# Prior to version 1.8.15, groups listed in sudoers that were not
# found in the system group database were passed to the group
# plugin, if any. Starting with 1.8.15, only groups of the form
# %:group are resolved via the group plugin by default.
# We enable always_query_group_plugin to restore old behavior.
# Disable this option for new behavior.
Defaults always_query_group_plugin
Defaults env_reset Defaults env_reset
Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS" Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE" Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
@ -22,6 +79,12 @@ Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES
Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
#
# Adding HOME to env_keep may enable a user to run unrestricted
# commands via sudo.
#
# Defaults env_keep += "HOME"
Defaults secure_path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin Defaults secure_path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
## Next comes the main part: which users can run what software on ## Next comes the main part: which users can run what software on
@ -36,8 +99,22 @@ Defaults secure_path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbi
## Allow root to run any commands anywhere ## Allow root to run any commands anywhere
root ALL=(ALL) ALL root ALL=(ALL) ALL
## Allows members of the 'sys' group to run networking, software,
## service management apps and more.
# %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS
## Allows people in group wheel to run all commands ## Allows people in group wheel to run all commands
%wheel ALL=(ALL) ALL %wheel ALL=(ALL) ALL
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
## Allows members of the users group to mount and unmount the
## cdrom as root
# %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom
## Allows members of the users group to shutdown this system
# %users localhost=/sbin/shutdown -h now
## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment)
#includedir /etc/sudoers.d #includedir /etc/sudoers.d