On Wed, Mar 15, 2023 at 11:08:10PM +0100, Sebastian Ramacher wrote: > The noise in the generated files makes the debdiff impossible to review. > Please provide a filtered debdiff without the noise in generated files.
Sure. Attaching - debdiff with just generated files removed - debdiff with generated files and debian noise (copyright, changelog) removed - debdiff with generated files, debian noise and testsuite changes removed I am not sure whether I am supposed to remove the moreinfo tag now, leaving it as it is to be safe. Greetings Marc
diff -Nru sudo-1.9.13p1/ChangeLog sudo-1.9.13p3/ChangeLog --- sudo-1.9.13p1/ChangeLog 2023-02-16 19:46:48.000000000 +0100 +++ sudo-1.9.13p3/ChangeLog 2023-03-04 18:00:50.000000000 +0100 @@ -1,8 +1,127 @@ +2023-03-04 Todd C. Miller <todd.mil...@sudo.ws> + + * .hgtags: + Added tag SUDO_1_9_13p3 for changeset 0bdd0b8469e3 + [fc4e872d6d89] [tip] <1.9> + + * NEWS, configure, configure.ac: + Sudo 1.9.13p3 + [0bdd0b8469e3] [SUDO_1_9_13p3] <1.9> + +2023-03-03 Todd C. Miller <todd.mil...@sudo.ws> + + * plugins/sudoers/match.c, plugins/sudoers/parse.c, + plugins/sudoers/parse.h: + A user with "list" privs for root may not list all users. A user + with "sudo ALL" for root _is_ allowed to list any user. + [a3f7301ba4d3] <1.9> + + * plugins/sudoers/policy.c: + sudoers_policy_list: do not set runas_pw to list_pw when listing + This change introduced in sudo 1.9.13 is not actually needed. The + "list" pseudo-command checks are performed via runas_matches_pw() + which does not use runas_pw. GitHub issue #248 + [84effa5ffaa1] <1.9> + + * plugins/sudoers/logging.c, plugins/sudoers/parse.c, + plugins/sudoers/sudoers.c: + Fix "sudo -l command args", broken in sudo 1.9.13. The value of + user_args should not contain the command to be run in "sudo -l + command args", only the arguments of the command being checked. This + restores the pre-1.9.13 behavior. GitHub issue #249 + [3e1225e7bf33] <1.9> + +2023-03-01 Todd C. Miller <todd.mil...@sudo.ws> + + * src/exec_nopty.c, src/exec_pty.c: + write_callback: only enable /dev/tty reader if the command is + running This fixes a hang when there is /dev/tty data in a buffer to + be flushed by the final call to del_io_events(). We do not want to + re-enable the reader when flushing the buffers as part of + pty_finish(). See PR #247 for analysis of the problem and how to + reproduce it. + [b7ea5b5e6a88] <1.9> + +2023-02-28 Todd C. Miller <todd.mil...@sudo.ws> + + * plugins/sudoers/regress/testsudoers/test12.out.ok, + plugins/sudoers/regress/testsudoers/test12.sh: + Test non-fully qualified path name. + [0a9e6e83fe15] <1.9> + + * plugins/sudoers/Makefile.in: + Fix removal of y.tab.[ch] when generating gram.[ch]. + [f69c86ecae66] <1.9> + + * MANIFEST, plugins/sudoers/regress/sudoers/test30.in, + plugins/sudoers/regress/sudoers/test30.json.ok, + plugins/sudoers/regress/sudoers/test30.ldif.ok, + plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok, + plugins/sudoers/regress/sudoers/test30.out.ok, + plugins/sudoers/regress/sudoers/test30.sudo.ok, + plugins/sudoers/regress/sudoers/test30.toke.ok: + Add test for using "list" as user, runas and host. + [ae2c84c73371] <1.9> + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Move handling of the "list" pseudo-command from lexer to parser. The + special handling of "list" in the lexer meant it could not be used + as a user, group or host, which was unintentional. GitHub issue + #246. + [efb3a4dea1da] <1.9> + +2023-02-27 Todd C. Miller <todd.mil...@sudo.ws> + + * include/sudo_compat.h: + Make the check for HAVE_DECL_NSIG consistent with other decl checks. + [616c42c4adce] <1.9> + +2023-02-25 Todd C. Miller <todd.mil...@sudo.ws> + + * .hgtags: + Added tag SUDO_1_9_13p2 for changeset 2db7cee1cb77 + [b0af73801130] <1.9> + + * NEWS, configure, configure.ac: + Sudo 1.9.13p2. + [2db7cee1cb77] [SUDO_1_9_13p2] <1.9> + +2023-02-23 Todd C. Miller <todd.mil...@sudo.ws> + + * lib/util/lbuf.c: + Add missing include of errno.h. + [65ddd70d0c18] <1.9> + + * lib/util/lbuf.c: + sudo_lbuf_expand: check for overflow when rounding to the nearest + power of 2. Problem deteced by oss-fuzz using the fuzz_sudoers + fuzzer. + [9357396fdaa0] <1.9> + + * src/load_plugins.c: + Fix --enable-static-sudoers, broken in sudo 1.9.13. + sudo_qualify_plugin() should not try to fully-qualify the path to a + statically-compiled plugin. GitHub issue #245 + [eca5f1f6555e] <1.9> + +2023-02-21 Todd C. Miller <todd.mil...@sudo.ws> + + * MANIFEST, plugins/sudoers/match_command.c, + plugins/sudoers/regress/fuzz/fuzz_sudoers.c, + plugins/sudoers/regress/testsudoers/test20.out.ok, + plugins/sudoers/regress/testsudoers/test20.sh, + plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c: + Fix potential double free for rules that include a CHROOT= option. + If a rule with a CHROOT= option matches the user, host and runas, + the user_cmnd variable could be freed twice. + [2c1477233f48] <1.9> + 2023-02-16 Todd C. Miller <todd.mil...@sudo.ws> * .hgtags: Added tag SUDO_1_9_13p1 for changeset 49e64402924f - [97ae12488007] [tip] <1.9> + [97ae12488007] <1.9> * NEWS, configure, configure.ac: Merge sudo 1.9.13p1 from tip. diff -Nru sudo-1.9.13p1/configure.ac sudo-1.9.13p3/configure.ac --- sudo-1.9.13p1/configure.ac 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/configure.ac 2023-03-04 17:59:59.000000000 +0100 @@ -18,7 +18,7 @@ dnl OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. dnl AC_PREREQ([2.69]) -AC_INIT([sudo], [1.9.13p1], [https://bugzilla.sudo.ws/], [sudo]) +AC_INIT([sudo], [1.9.13p3], [https://bugzilla.sudo.ws/], [sudo]) AC_CONFIG_HEADERS([config.h pathnames.h]) AC_CONFIG_SRCDIR([src/sudo.c]) AC_CONFIG_AUX_DIR([scripts]) diff -Nru sudo-1.9.13p1/include/sudo_compat.h sudo-1.9.13p3/include/sudo_compat.h --- sudo-1.9.13p1/include/sudo_compat.h 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/include/sudo_compat.h 2023-03-04 16:50:09.000000000 +0100 @@ -205,7 +205,7 @@ #endif /* !HAVE_DECL_ERRNO */ /* Not all systems define NSIG in signal.h */ -#if !defined(HAVE_DECL_NSIG) || !HAVE_DECL_NSIG +#if defined(HAVE_DECL_NSIG) && !HAVE_DECL_NSIG # if defined(HAVE_DECL__NSIG) && HAVE_DECL__NSIG # define NSIG _NSIG # elif defined(HAVE_DECL___NSIG) && HAVE_DECL___NSIG diff -Nru sudo-1.9.13p1/lib/util/lbuf.c sudo-1.9.13p3/lib/util/lbuf.c --- sudo-1.9.13p1/lib/util/lbuf.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/lib/util/lbuf.c 2023-02-23 17:14:45.000000000 +0100 @@ -26,6 +26,7 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <errno.h> #include "sudo_compat.h" #include "sudo_debug.h" @@ -70,6 +71,7 @@ debug_decl(sudo_lbuf_expand, SUDO_DEBUG_UTIL); if (lbuf->len + extra + 1 <= lbuf->len) { + errno = ENOMEM; sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "integer overflow updating lbuf->len"); lbuf->error = 1; @@ -80,6 +82,13 @@ unsigned int new_size = sudo_pow2_roundup(lbuf->len + extra + 1); char *new_buf; + if (new_size < lbuf->size) { + errno = ENOMEM; + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "integer overflow updating lbuf->size"); + lbuf->error = 1; + debug_return_bool(false); + } if (new_size < 1024) new_size = 1024; if ((new_buf = realloc(lbuf->buf, new_size)) == NULL) { diff -Nru sudo-1.9.13p1/MANIFEST sudo-1.9.13p3/MANIFEST --- sudo-1.9.13p1/MANIFEST 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/MANIFEST 2023-03-04 16:50:10.000000000 +0100 @@ -995,6 +995,13 @@ plugins/sudoers/regress/sudoers/test3.ldif2sudo.ok plugins/sudoers/regress/sudoers/test3.out.ok plugins/sudoers/regress/sudoers/test3.toke.ok +plugins/sudoers/regress/sudoers/test30.in +plugins/sudoers/regress/sudoers/test30.json.ok +plugins/sudoers/regress/sudoers/test30.ldif.ok +plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok +plugins/sudoers/regress/sudoers/test30.out.ok +plugins/sudoers/regress/sudoers/test30.sudo.ok +plugins/sudoers/regress/sudoers/test30.toke.ok plugins/sudoers/regress/sudoers/test4.in plugins/sudoers/regress/sudoers/test4.json.ok plugins/sudoers/regress/sudoers/test4.ldif.ok @@ -1052,6 +1059,8 @@ plugins/sudoers/regress/testsudoers/test2.inc plugins/sudoers/regress/testsudoers/test2.out.ok plugins/sudoers/regress/testsudoers/test2.sh +plugins/sudoers/regress/testsudoers/test20.out.ok +plugins/sudoers/regress/testsudoers/test20.sh plugins/sudoers/regress/testsudoers/test3.out.ok plugins/sudoers/regress/testsudoers/test3.sh plugins/sudoers/regress/testsudoers/test4.out.ok diff -Nru sudo-1.9.13p1/NEWS sudo-1.9.13p3/NEWS --- sudo-1.9.13p1/NEWS 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/NEWS 2023-03-04 17:59:59.000000000 +0100 @@ -1,3 +1,28 @@ +What's new in Sudo 1.9.13p3 + + * Fixed a bug introduced in sudo 1.9.13 that caused a syntax error + when "list" was used as a user or host name. GitHub issue #246. + + * Fixed a bug that could cause sudo to hang when running a command + in a pseudo-terminal when there is still input buffered after a + command has exited. + + * Fixed "sudo -U otheruser -l command". This is a regression in + sudo 1.9.13. GitHub issue #248. + + * Fixed "sudo -l command args" when matching a command in sudoers + with command line arguments. This is a regression in sudo 1.9.13. + GitHub issue #249. + +What's new in Sudo 1.9.13p2 + + * Fixed the --enable-static-sudoers option, broken in sudo 1.9.13. + GitHub issue #245. + + * Fixed a potential double-free bug when matching a sudoers rule + that contains a per-command chroot directive (CHROOT=dir). This + bug was introduced in sudo 1.9.8. + What's new in Sudo 1.9.13p1 * Fixed a typo in the configure script that resulted in a line diff -Nru sudo-1.9.13p1/plugins/sudoers/gram.y sudo-1.9.13p3/plugins/sudoers/gram.y --- sudo-1.9.13p1/plugins/sudoers/gram.y 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/gram.y 2023-03-04 16:50:10.000000000 +0100 @@ -978,6 +978,27 @@ parser_leak_remove(LEAK_PTR, $1.args); parser_leak_add(LEAK_MEMBER, $$); } + | WORD { + if (strcmp($1, "list") == 0) { + struct sudo_command *c; + + if ((c = new_command($1, NULL)) == NULL) { + sudoerserror(N_("unable to allocate memory")); + YYERROR; + } + $$ = new_member((char *)c, COMMAND); + if ($$ == NULL) { + free(c); + sudoerserror(N_("unable to allocate memory")); + YYERROR; + } + parser_leak_remove(LEAK_PTR, $1); + parser_leak_add(LEAK_MEMBER, $$); + } else { + sudoerserror(N_("expected a fully-qualified path name")); + YYERROR; + } + } ; hostaliases : hostalias diff -Nru sudo-1.9.13p1/plugins/sudoers/logging.c sudo-1.9.13p3/plugins/sudoers/logging.c --- sudo-1.9.13p1/plugins/sudoers/logging.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/logging.c 2023-03-04 16:50:12.000000000 +0100 @@ -322,9 +322,9 @@ "sudo on %s.\n"), user_name, user_srunhost); } else { sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s is not allowed " - "to execute '%s%s%s' as %s%s%s on %s.\n"), - user_name, user_cmnd, user_args ? " " : "", - user_args ? user_args : "", + "to execute '%s%s%s%s' as %s%s%s on %s.\n"), + user_name, user_cmnd, list_cmnd ? list_cmnd : "", + user_args ? " " : "", user_args ? user_args : "", list_pw ? list_pw->pw_name : runas_pw ? runas_pw->pw_name : user_name, runas_gr ? ":" : "", runas_gr ? runas_gr->gr_name : "", user_host); diff -Nru sudo-1.9.13p1/plugins/sudoers/Makefile.in sudo-1.9.13p3/plugins/sudoers/Makefile.in --- sudo-1.9.13p1/plugins/sudoers/Makefile.in 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/Makefile.in 2023-03-04 16:50:11.000000000 +0100 @@ -505,7 +505,7 @@ else \ gram_y="$(srcdir)/gram.y"; \ fi; \ - cmd='$(YACC) -d -p sudoers '"$$gram_y"'; cp prologue $(devdir)/gram.c; $(SED) -e "s/^\\(#line .*\\) \"y\\.tab\\.c\"/\1 \"gram.c\"/" -e "/^# *include <limits.h>/{N;s/__STDC_VERSION__ && 199901 <= __STDC_VERSION__/HAVE_STDINT_H/;}" y.tab.c >> $(devdir)/gram.c; sed -e "s/^\\(#line .*\\) \"y\\.tab\\.h\"/\1 \"gram.h\"/" y.tab.h > $(devdir)/gram.h'; rm -f y.tab.[ch]; \ + cmd='$(YACC) -d -p sudoers '"$$gram_y"'; cp prologue $(devdir)/gram.c; $(SED) -e "s/^\\(#line .*\\) \"y\\.tab\\.c\"/\1 \"gram.c\"/" -e "/^# *include <limits.h>/{N;s/__STDC_VERSION__ && 199901 <= __STDC_VERSION__/HAVE_STDINT_H/;}" y.tab.c >> $(devdir)/gram.c; sed -e "s/^\\(#line .*\\) \"y\\.tab\\.h\"/\1 \"gram.h\"/" y.tab.h > $(devdir)/gram.h; rm -f y.tab.[ch]'; \ echo "$$cmd"; eval $$cmd; \ fi diff -Nru sudo-1.9.13p1/plugins/sudoers/match.c sudo-1.9.13p3/plugins/sudoers/match.c --- sudo-1.9.13p1/plugins/sudoers/match.c 2023-02-14 17:52:37.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/match.c 2023-03-04 16:50:14.000000000 +0100 @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 1996, 1998-2005, 2007-2019 + * Copyright (c) 1996, 1998-2005, 2007-2023 * Todd C. Miller <todd.mil...@sudo.ws> * * Permission to use, copy, modify, and distribute this software for any @@ -414,6 +414,44 @@ alias_put(a); } break; + } + debug_return_int(matched); +} + +/* + * Like cmnd_matches() but only matches against the ALL command. + * Returns ALLOW, DENY or UNSPEC. + */ +int +cmnd_matches_all(struct sudoers_parse_tree *parse_tree, const struct member *m, + const char *runchroot, struct cmnd_info *info) +{ + const bool negated = m->negated; + struct sudo_command *c; + int matched = UNSPEC; + struct alias *a; + debug_decl(cmnd_matches_all, SUDOERS_DEBUG_MATCH); + + switch (m->type) { + case ALL: + c = (struct sudo_command *)m->name; + if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests)) + matched = !negated; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, CMNDALIAS); + if (a != NULL) { + TAILQ_FOREACH_REVERSE(m, &a->members, member_list, entries) { + matched = cmnd_matches_all(parse_tree, m, runchroot, info); + if (matched != UNSPEC) { + if (negated) + matched = !matched; + break; + } + } + alias_put(a); + } + break; } debug_return_int(matched); } diff -Nru sudo-1.9.13p1/plugins/sudoers/match_command.c sudo-1.9.13p3/plugins/sudoers/match_command.c --- sudo-1.9.13p1/plugins/sudoers/match_command.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/match_command.c 2023-02-25 19:22:35.000000000 +0100 @@ -818,12 +818,16 @@ /* Rule-specific runchroot, reset user_cmnd and user_stat. */ int status; + /* Save old user_cmnd first, set_cmnd_path() will free it. */ saved_user_cmnd = user_cmnd; + user_cmnd = NULL; if (user_stat != NULL) saved_user_stat = *user_stat; status = set_cmnd_path(runchroot); - if (status != FOUND) + if (status != FOUND) { + user_cmnd = saved_user_cmnd; saved_user_cmnd = NULL; + } if (info != NULL) info->status = status; } diff -Nru sudo-1.9.13p1/plugins/sudoers/parse.c sudo-1.9.13p3/plugins/sudoers/parse.c --- sudo-1.9.13p1/plugins/sudoers/parse.c 2023-02-14 17:53:34.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/parse.c 2023-03-04 16:50:14.000000000 +0100 @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2004-2005, 2007-2021 Todd C. Miller <todd.mil...@sudo.ws> + * Copyright (c) 2004-2005, 2007-2023 Todd C. Miller <todd.mil...@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 @@ -67,7 +67,7 @@ struct privilege *priv; struct userspec *us; struct defaults *def; - int nopass, match = DENY; + int cmnd_match, nopass, match = DENY; enum def_tuple pwcheck; debug_decl(sudoers_lookup_pseudo, SUDOERS_DEBUG_PARSER); @@ -133,26 +133,40 @@ */ switch (runas_matches_pw(nss->parse_tree, cs, list_pw)) { case DENY: - continue; + break; case ALLOW: + /* + * RunAs user matches list user. + * Match on command "list" or ALL. + */ + cmnd_match = cmnd_matches(nss->parse_tree, + cs->cmnd, cs->runchroot, NULL); + if (cmnd_match != UNSPEC) { + match = cmnd_match; + goto done; + } break; default: + /* + * RunAs user doesn't match list user. Only allow + * listing if the user has "sudo ALL" for root. + */ if (root_pw != NULL && runas_matches_pw(nss->parse_tree, cs, root_pw) == ALLOW) { - break; + cmnd_match = cmnd_matches_all(nss->parse_tree, + cs->cmnd, cs->runchroot, NULL); + if (cmnd_match != UNSPEC) { + match = cmnd_match; + goto done; + } } - continue; - } - - /* Match command: "list" or ALL. */ - if (cmnd_matches(nss->parse_tree, cs->cmnd, cs->runchroot, - NULL) == ALLOW) { - match = ALLOW; + break; } } } } } +done: if (root_pw != NULL) sudo_pw_delref(root_pw); if (match == ALLOW || user_uid == 0) { @@ -1067,8 +1081,8 @@ break; } if (match == ALLOW) { - /* For "sudo -l cmd" user_args includes the command being checked. */ - const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", user_args); + const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n", + list_cmnd, user_args ? " " : "", user_args ? user_args : ""); ret = len < 0 ? -1 : true; } debug_return_int(ret); diff -Nru sudo-1.9.13p1/plugins/sudoers/parse.h sudo-1.9.13p3/plugins/sudoers/parse.h --- sudo-1.9.13p1/plugins/sudoers/parse.h 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/parse.h 2023-03-04 16:50:14.000000000 +0100 @@ -405,6 +405,7 @@ bool usergr_matches(const char *group, const char *user, const struct passwd *pw); bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw); int cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot, struct cmnd_info *info); +int cmnd_matches_all(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot, struct cmnd_info *info); int cmndlist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *list, const char *runchroot, struct cmnd_info *info); int host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const char *host, const char *shost, const struct member *m); int hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const struct member_list *list); diff -Nru sudo-1.9.13p1/plugins/sudoers/policy.c sudo-1.9.13p3/plugins/sudoers/policy.c --- sudo-1.9.13p1/plugins/sudoers/policy.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/policy.c 2023-03-04 16:50:13.000000000 +0100 @@ -1270,11 +1270,6 @@ sudo_warnx(U_("unknown user %s"), list_user); debug_return_int(-1); } - /* A user may only list another user they have runas access to. */ - if (runas_pw != NULL) - sudo_pw_delref(runas_pw); - runas_pw = list_pw; - sudo_pw_addref(list_pw); } ret = sudoers_policy_main(argc, argv, I_LISTPW, NULL, verbose, NULL); if (list_user) { diff -Nru sudo-1.9.13p1/plugins/sudoers/sudoers.c sudo-1.9.13p3/plugins/sudoers/sudoers.c --- sudo-1.9.13p1/plugins/sudoers/sudoers.c 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/sudoers.c 2023-03-04 16:50:12.000000000 +0100 @@ -1079,7 +1079,14 @@ /* set user_args */ free(user_args); user_args = NULL; - if (NewArgc > 1) { + if (ISSET(sudo_mode, MODE_CHECK)) { + if (NewArgc > 2) { + /* Skip the command being listed in NewArgv[1]. */ + user_args = strvec_join(NewArgv + 2, ' ', NULL); + if (user_args == NULL) + debug_return_int(NOT_FOUND_ERROR); + } + } else if (NewArgc > 1) { if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) && ISSET(sudo_mode, MODE_RUN)) { /* diff -Nru sudo-1.9.13p1/plugins/sudoers/testsudoers.c sudo-1.9.13p3/plugins/sudoers/testsudoers.c --- sudo-1.9.13p1/plugins/sudoers/testsudoers.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/testsudoers.c 2023-02-25 19:21:47.000000000 +0100 @@ -82,6 +82,7 @@ */ struct sudo_user sudo_user; struct passwd *list_pw; +static const char *orig_cmnd; static char *runas_group, *runas_user; #if defined(SUDO_DEVEL) && defined(__OpenBSD__) @@ -203,14 +204,18 @@ if (!dflag) usage(); user_name = argc ? *argv++ : (char *)"root"; - user_cmnd = user_base = (char *)"true"; + orig_cmnd = "true"; argc = 0; } else { user_name = *argv++; - user_cmnd = *argv++; - user_base = sudo_basename(user_cmnd); + orig_cmnd = *argv++; argc -= 2; } + user_cmnd = strdup(orig_cmnd); + if (user_cmnd == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + user_base = sudo_basename(user_cmnd); + if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) sudo_fatalx(U_("unknown user %s"), user_name); @@ -509,8 +514,13 @@ int set_cmnd_path(const char *runchroot) { - /* Cannot return FOUND without also setting user_cmnd to a new value. */ - return NOT_FOUND; + /* Reallocate user_cmnd to catch bugs in command_matches(). */ + char *new_cmnd = strdup(orig_cmnd); + if (new_cmnd == NULL) + return NOT_FOUND_ERROR; + free(user_cmnd); + user_cmnd = new_cmnd; + return FOUND; } static bool diff -Nru sudo-1.9.13p1/plugins/sudoers/toke.l sudo-1.9.13p3/plugins/sudoers/toke.l --- sudo-1.9.13p1/plugins/sudoers/toke.l 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/toke.l 2023-03-04 16:50:10.000000000 +0100 @@ -750,14 +750,6 @@ return SHA512_TOK; } -list { - /* No command line args. */ - LEXTRACE("COMMAND "); - if (!fill_cmnd(sudoerstext, sudoersleng)) - yyterminate(); - return COMMAND; - } /* sudo -l -U otheruser */ - sudoedit { BEGIN GOTCMND; LEXTRACE("COMMAND "); diff -Nru sudo-1.9.13p1/plugins/sudoers/visudo.c sudo-1.9.13p3/plugins/sudoers/visudo.c --- sudo-1.9.13p1/plugins/sudoers/visudo.c 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/visudo.c 2023-02-25 19:21:47.000000000 +0100 @@ -260,7 +260,9 @@ } /* Mock up a fake sudo_user struct. */ - user_cmnd = user_base = (char *)""; + user_cmnd = user_base = strdup("true"); + if (user_cmnd == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); if (geteuid() == 0) { const char *user = getenv("SUDO_USER"); if (user != NULL && *user != '\0') diff -Nru sudo-1.9.13p1/src/exec_nopty.c sudo-1.9.13p3/src/exec_nopty.c --- sudo-1.9.13p1/src/exec_nopty.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/exec_nopty.c 2023-03-04 16:50:12.000000000 +0100 @@ -447,10 +447,15 @@ ev_free_by_fd(evbase, fd); } } - /* Enable reader if buffer is not full. */ + /* + * Enable reader if buffer is not full but avoid reading + * /dev/tty if the command is no longer running. + */ if (iob->revent != NULL && iob->len != sizeof(iob->buf)) { - if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) - sudo_fatal("%s", U_("unable to add event to queue")); + if (!USERTTY_EVENT(iob->revent) || iob->ec->cmnd_pid != -1) { + if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) + sudo_fatal("%s", U_("unable to add event to queue")); + } } } diff -Nru sudo-1.9.13p1/src/exec_pty.c sudo-1.9.13p3/src/exec_pty.c --- sudo-1.9.13p1/src/exec_pty.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/exec_pty.c 2023-03-04 16:50:12.000000000 +0100 @@ -469,10 +469,13 @@ ev_free_by_fd(evbase, fd); } } - /* Enable reader if buffer is not full. */ - if (iob->revent != NULL && - (ttymode == TERM_RAW || !USERTTY_EVENT(iob->revent))) { - if (iob->len != sizeof(iob->buf)) { + /* + * Enable reader if buffer is not full but avoid reading /dev/tty + * if not in raw mode or the command is no longer running. + */ + if (iob->revent != NULL && iob->len != sizeof(iob->buf)) { + if (!USERTTY_EVENT(iob->revent) || + (ttymode == TERM_RAW && iob->ec->cmnd_pid != -1)) { if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) sudo_fatal("%s", U_("unable to add event to queue")); } diff -Nru sudo-1.9.13p1/src/load_plugins.c sudo-1.9.13p3/src/load_plugins.c --- sudo-1.9.13p1/src/load_plugins.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/load_plugins.c 2023-02-23 17:09:38.000000000 +0100 @@ -55,6 +55,8 @@ errno = ENAMETOOLONG; goto bad; } + /* Plugin is static, do not fully-qualify. */ + debug_return_bool(true); } #endif /* STATIC_SUDOERS_PLUGIN */
diff -Nru sudo-1.9.13p1/ChangeLog sudo-1.9.13p3/ChangeLog --- sudo-1.9.13p1/ChangeLog 2023-02-16 19:46:48.000000000 +0100 +++ sudo-1.9.13p3/ChangeLog 2023-03-04 18:00:50.000000000 +0100 @@ -1,8 +1,127 @@ +2023-03-04 Todd C. Miller <todd.mil...@sudo.ws> + + * .hgtags: + Added tag SUDO_1_9_13p3 for changeset 0bdd0b8469e3 + [fc4e872d6d89] [tip] <1.9> + + * NEWS, configure, configure.ac: + Sudo 1.9.13p3 + [0bdd0b8469e3] [SUDO_1_9_13p3] <1.9> + +2023-03-03 Todd C. Miller <todd.mil...@sudo.ws> + + * plugins/sudoers/match.c, plugins/sudoers/parse.c, + plugins/sudoers/parse.h: + A user with "list" privs for root may not list all users. A user + with "sudo ALL" for root _is_ allowed to list any user. + [a3f7301ba4d3] <1.9> + + * plugins/sudoers/policy.c: + sudoers_policy_list: do not set runas_pw to list_pw when listing + This change introduced in sudo 1.9.13 is not actually needed. The + "list" pseudo-command checks are performed via runas_matches_pw() + which does not use runas_pw. GitHub issue #248 + [84effa5ffaa1] <1.9> + + * plugins/sudoers/logging.c, plugins/sudoers/parse.c, + plugins/sudoers/sudoers.c: + Fix "sudo -l command args", broken in sudo 1.9.13. The value of + user_args should not contain the command to be run in "sudo -l + command args", only the arguments of the command being checked. This + restores the pre-1.9.13 behavior. GitHub issue #249 + [3e1225e7bf33] <1.9> + +2023-03-01 Todd C. Miller <todd.mil...@sudo.ws> + + * src/exec_nopty.c, src/exec_pty.c: + write_callback: only enable /dev/tty reader if the command is + running This fixes a hang when there is /dev/tty data in a buffer to + be flushed by the final call to del_io_events(). We do not want to + re-enable the reader when flushing the buffers as part of + pty_finish(). See PR #247 for analysis of the problem and how to + reproduce it. + [b7ea5b5e6a88] <1.9> + +2023-02-28 Todd C. Miller <todd.mil...@sudo.ws> + + * plugins/sudoers/regress/testsudoers/test12.out.ok, + plugins/sudoers/regress/testsudoers/test12.sh: + Test non-fully qualified path name. + [0a9e6e83fe15] <1.9> + + * plugins/sudoers/Makefile.in: + Fix removal of y.tab.[ch] when generating gram.[ch]. + [f69c86ecae66] <1.9> + + * MANIFEST, plugins/sudoers/regress/sudoers/test30.in, + plugins/sudoers/regress/sudoers/test30.json.ok, + plugins/sudoers/regress/sudoers/test30.ldif.ok, + plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok, + plugins/sudoers/regress/sudoers/test30.out.ok, + plugins/sudoers/regress/sudoers/test30.sudo.ok, + plugins/sudoers/regress/sudoers/test30.toke.ok: + Add test for using "list" as user, runas and host. + [ae2c84c73371] <1.9> + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Move handling of the "list" pseudo-command from lexer to parser. The + special handling of "list" in the lexer meant it could not be used + as a user, group or host, which was unintentional. GitHub issue + #246. + [efb3a4dea1da] <1.9> + +2023-02-27 Todd C. Miller <todd.mil...@sudo.ws> + + * include/sudo_compat.h: + Make the check for HAVE_DECL_NSIG consistent with other decl checks. + [616c42c4adce] <1.9> + +2023-02-25 Todd C. Miller <todd.mil...@sudo.ws> + + * .hgtags: + Added tag SUDO_1_9_13p2 for changeset 2db7cee1cb77 + [b0af73801130] <1.9> + + * NEWS, configure, configure.ac: + Sudo 1.9.13p2. + [2db7cee1cb77] [SUDO_1_9_13p2] <1.9> + +2023-02-23 Todd C. Miller <todd.mil...@sudo.ws> + + * lib/util/lbuf.c: + Add missing include of errno.h. + [65ddd70d0c18] <1.9> + + * lib/util/lbuf.c: + sudo_lbuf_expand: check for overflow when rounding to the nearest + power of 2. Problem deteced by oss-fuzz using the fuzz_sudoers + fuzzer. + [9357396fdaa0] <1.9> + + * src/load_plugins.c: + Fix --enable-static-sudoers, broken in sudo 1.9.13. + sudo_qualify_plugin() should not try to fully-qualify the path to a + statically-compiled plugin. GitHub issue #245 + [eca5f1f6555e] <1.9> + +2023-02-21 Todd C. Miller <todd.mil...@sudo.ws> + + * MANIFEST, plugins/sudoers/match_command.c, + plugins/sudoers/regress/fuzz/fuzz_sudoers.c, + plugins/sudoers/regress/testsudoers/test20.out.ok, + plugins/sudoers/regress/testsudoers/test20.sh, + plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c: + Fix potential double free for rules that include a CHROOT= option. + If a rule with a CHROOT= option matches the user, host and runas, + the user_cmnd variable could be freed twice. + [2c1477233f48] <1.9> + 2023-02-16 Todd C. Miller <todd.mil...@sudo.ws> * .hgtags: Added tag SUDO_1_9_13p1 for changeset 49e64402924f - [97ae12488007] [tip] <1.9> + [97ae12488007] <1.9> * NEWS, configure, configure.ac: Merge sudo 1.9.13p1 from tip. diff -Nru sudo-1.9.13p1/configure.ac sudo-1.9.13p3/configure.ac --- sudo-1.9.13p1/configure.ac 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/configure.ac 2023-03-04 17:59:59.000000000 +0100 @@ -18,7 +18,7 @@ dnl OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. dnl AC_PREREQ([2.69]) -AC_INIT([sudo], [1.9.13p1], [https://bugzilla.sudo.ws/], [sudo]) +AC_INIT([sudo], [1.9.13p3], [https://bugzilla.sudo.ws/], [sudo]) AC_CONFIG_HEADERS([config.h pathnames.h]) AC_CONFIG_SRCDIR([src/sudo.c]) AC_CONFIG_AUX_DIR([scripts]) diff -Nru sudo-1.9.13p1/include/sudo_compat.h sudo-1.9.13p3/include/sudo_compat.h --- sudo-1.9.13p1/include/sudo_compat.h 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/include/sudo_compat.h 2023-03-04 16:50:09.000000000 +0100 @@ -205,7 +205,7 @@ #endif /* !HAVE_DECL_ERRNO */ /* Not all systems define NSIG in signal.h */ -#if !defined(HAVE_DECL_NSIG) || !HAVE_DECL_NSIG +#if defined(HAVE_DECL_NSIG) && !HAVE_DECL_NSIG # if defined(HAVE_DECL__NSIG) && HAVE_DECL__NSIG # define NSIG _NSIG # elif defined(HAVE_DECL___NSIG) && HAVE_DECL___NSIG diff -Nru sudo-1.9.13p1/lib/util/lbuf.c sudo-1.9.13p3/lib/util/lbuf.c --- sudo-1.9.13p1/lib/util/lbuf.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/lib/util/lbuf.c 2023-02-23 17:14:45.000000000 +0100 @@ -26,6 +26,7 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <errno.h> #include "sudo_compat.h" #include "sudo_debug.h" @@ -70,6 +71,7 @@ debug_decl(sudo_lbuf_expand, SUDO_DEBUG_UTIL); if (lbuf->len + extra + 1 <= lbuf->len) { + errno = ENOMEM; sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "integer overflow updating lbuf->len"); lbuf->error = 1; @@ -80,6 +82,13 @@ unsigned int new_size = sudo_pow2_roundup(lbuf->len + extra + 1); char *new_buf; + if (new_size < lbuf->size) { + errno = ENOMEM; + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "integer overflow updating lbuf->size"); + lbuf->error = 1; + debug_return_bool(false); + } if (new_size < 1024) new_size = 1024; if ((new_buf = realloc(lbuf->buf, new_size)) == NULL) { diff -Nru sudo-1.9.13p1/MANIFEST sudo-1.9.13p3/MANIFEST --- sudo-1.9.13p1/MANIFEST 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/MANIFEST 2023-03-04 16:50:10.000000000 +0100 @@ -995,6 +995,13 @@ plugins/sudoers/regress/sudoers/test3.ldif2sudo.ok plugins/sudoers/regress/sudoers/test3.out.ok plugins/sudoers/regress/sudoers/test3.toke.ok +plugins/sudoers/regress/sudoers/test30.in +plugins/sudoers/regress/sudoers/test30.json.ok +plugins/sudoers/regress/sudoers/test30.ldif.ok +plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok +plugins/sudoers/regress/sudoers/test30.out.ok +plugins/sudoers/regress/sudoers/test30.sudo.ok +plugins/sudoers/regress/sudoers/test30.toke.ok plugins/sudoers/regress/sudoers/test4.in plugins/sudoers/regress/sudoers/test4.json.ok plugins/sudoers/regress/sudoers/test4.ldif.ok @@ -1052,6 +1059,8 @@ plugins/sudoers/regress/testsudoers/test2.inc plugins/sudoers/regress/testsudoers/test2.out.ok plugins/sudoers/regress/testsudoers/test2.sh +plugins/sudoers/regress/testsudoers/test20.out.ok +plugins/sudoers/regress/testsudoers/test20.sh plugins/sudoers/regress/testsudoers/test3.out.ok plugins/sudoers/regress/testsudoers/test3.sh plugins/sudoers/regress/testsudoers/test4.out.ok diff -Nru sudo-1.9.13p1/NEWS sudo-1.9.13p3/NEWS --- sudo-1.9.13p1/NEWS 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/NEWS 2023-03-04 17:59:59.000000000 +0100 @@ -1,3 +1,28 @@ +What's new in Sudo 1.9.13p3 + + * Fixed a bug introduced in sudo 1.9.13 that caused a syntax error + when "list" was used as a user or host name. GitHub issue #246. + + * Fixed a bug that could cause sudo to hang when running a command + in a pseudo-terminal when there is still input buffered after a + command has exited. + + * Fixed "sudo -U otheruser -l command". This is a regression in + sudo 1.9.13. GitHub issue #248. + + * Fixed "sudo -l command args" when matching a command in sudoers + with command line arguments. This is a regression in sudo 1.9.13. + GitHub issue #249. + +What's new in Sudo 1.9.13p2 + + * Fixed the --enable-static-sudoers option, broken in sudo 1.9.13. + GitHub issue #245. + + * Fixed a potential double-free bug when matching a sudoers rule + that contains a per-command chroot directive (CHROOT=dir). This + bug was introduced in sudo 1.9.8. + What's new in Sudo 1.9.13p1 * Fixed a typo in the configure script that resulted in a line diff -Nru sudo-1.9.13p1/plugins/sudoers/gram.y sudo-1.9.13p3/plugins/sudoers/gram.y --- sudo-1.9.13p1/plugins/sudoers/gram.y 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/gram.y 2023-03-04 16:50:10.000000000 +0100 @@ -978,6 +978,27 @@ parser_leak_remove(LEAK_PTR, $1.args); parser_leak_add(LEAK_MEMBER, $$); } + | WORD { + if (strcmp($1, "list") == 0) { + struct sudo_command *c; + + if ((c = new_command($1, NULL)) == NULL) { + sudoerserror(N_("unable to allocate memory")); + YYERROR; + } + $$ = new_member((char *)c, COMMAND); + if ($$ == NULL) { + free(c); + sudoerserror(N_("unable to allocate memory")); + YYERROR; + } + parser_leak_remove(LEAK_PTR, $1); + parser_leak_add(LEAK_MEMBER, $$); + } else { + sudoerserror(N_("expected a fully-qualified path name")); + YYERROR; + } + } ; hostaliases : hostalias diff -Nru sudo-1.9.13p1/plugins/sudoers/logging.c sudo-1.9.13p3/plugins/sudoers/logging.c --- sudo-1.9.13p1/plugins/sudoers/logging.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/logging.c 2023-03-04 16:50:12.000000000 +0100 @@ -322,9 +322,9 @@ "sudo on %s.\n"), user_name, user_srunhost); } else { sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s is not allowed " - "to execute '%s%s%s' as %s%s%s on %s.\n"), - user_name, user_cmnd, user_args ? " " : "", - user_args ? user_args : "", + "to execute '%s%s%s%s' as %s%s%s on %s.\n"), + user_name, user_cmnd, list_cmnd ? list_cmnd : "", + user_args ? " " : "", user_args ? user_args : "", list_pw ? list_pw->pw_name : runas_pw ? runas_pw->pw_name : user_name, runas_gr ? ":" : "", runas_gr ? runas_gr->gr_name : "", user_host); diff -Nru sudo-1.9.13p1/plugins/sudoers/Makefile.in sudo-1.9.13p3/plugins/sudoers/Makefile.in --- sudo-1.9.13p1/plugins/sudoers/Makefile.in 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/Makefile.in 2023-03-04 16:50:11.000000000 +0100 @@ -505,7 +505,7 @@ else \ gram_y="$(srcdir)/gram.y"; \ fi; \ - cmd='$(YACC) -d -p sudoers '"$$gram_y"'; cp prologue $(devdir)/gram.c; $(SED) -e "s/^\\(#line .*\\) \"y\\.tab\\.c\"/\1 \"gram.c\"/" -e "/^# *include <limits.h>/{N;s/__STDC_VERSION__ && 199901 <= __STDC_VERSION__/HAVE_STDINT_H/;}" y.tab.c >> $(devdir)/gram.c; sed -e "s/^\\(#line .*\\) \"y\\.tab\\.h\"/\1 \"gram.h\"/" y.tab.h > $(devdir)/gram.h'; rm -f y.tab.[ch]; \ + cmd='$(YACC) -d -p sudoers '"$$gram_y"'; cp prologue $(devdir)/gram.c; $(SED) -e "s/^\\(#line .*\\) \"y\\.tab\\.c\"/\1 \"gram.c\"/" -e "/^# *include <limits.h>/{N;s/__STDC_VERSION__ && 199901 <= __STDC_VERSION__/HAVE_STDINT_H/;}" y.tab.c >> $(devdir)/gram.c; sed -e "s/^\\(#line .*\\) \"y\\.tab\\.h\"/\1 \"gram.h\"/" y.tab.h > $(devdir)/gram.h; rm -f y.tab.[ch]'; \ echo "$$cmd"; eval $$cmd; \ fi diff -Nru sudo-1.9.13p1/plugins/sudoers/match.c sudo-1.9.13p3/plugins/sudoers/match.c --- sudo-1.9.13p1/plugins/sudoers/match.c 2023-02-14 17:52:37.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/match.c 2023-03-04 16:50:14.000000000 +0100 @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 1996, 1998-2005, 2007-2019 + * Copyright (c) 1996, 1998-2005, 2007-2023 * Todd C. Miller <todd.mil...@sudo.ws> * * Permission to use, copy, modify, and distribute this software for any @@ -414,6 +414,44 @@ alias_put(a); } break; + } + debug_return_int(matched); +} + +/* + * Like cmnd_matches() but only matches against the ALL command. + * Returns ALLOW, DENY or UNSPEC. + */ +int +cmnd_matches_all(struct sudoers_parse_tree *parse_tree, const struct member *m, + const char *runchroot, struct cmnd_info *info) +{ + const bool negated = m->negated; + struct sudo_command *c; + int matched = UNSPEC; + struct alias *a; + debug_decl(cmnd_matches_all, SUDOERS_DEBUG_MATCH); + + switch (m->type) { + case ALL: + c = (struct sudo_command *)m->name; + if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests)) + matched = !negated; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, CMNDALIAS); + if (a != NULL) { + TAILQ_FOREACH_REVERSE(m, &a->members, member_list, entries) { + matched = cmnd_matches_all(parse_tree, m, runchroot, info); + if (matched != UNSPEC) { + if (negated) + matched = !matched; + break; + } + } + alias_put(a); + } + break; } debug_return_int(matched); } diff -Nru sudo-1.9.13p1/plugins/sudoers/match_command.c sudo-1.9.13p3/plugins/sudoers/match_command.c --- sudo-1.9.13p1/plugins/sudoers/match_command.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/match_command.c 2023-02-25 19:22:35.000000000 +0100 @@ -818,12 +818,16 @@ /* Rule-specific runchroot, reset user_cmnd and user_stat. */ int status; + /* Save old user_cmnd first, set_cmnd_path() will free it. */ saved_user_cmnd = user_cmnd; + user_cmnd = NULL; if (user_stat != NULL) saved_user_stat = *user_stat; status = set_cmnd_path(runchroot); - if (status != FOUND) + if (status != FOUND) { + user_cmnd = saved_user_cmnd; saved_user_cmnd = NULL; + } if (info != NULL) info->status = status; } diff -Nru sudo-1.9.13p1/plugins/sudoers/parse.c sudo-1.9.13p3/plugins/sudoers/parse.c --- sudo-1.9.13p1/plugins/sudoers/parse.c 2023-02-14 17:53:34.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/parse.c 2023-03-04 16:50:14.000000000 +0100 @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2004-2005, 2007-2021 Todd C. Miller <todd.mil...@sudo.ws> + * Copyright (c) 2004-2005, 2007-2023 Todd C. Miller <todd.mil...@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 @@ -67,7 +67,7 @@ struct privilege *priv; struct userspec *us; struct defaults *def; - int nopass, match = DENY; + int cmnd_match, nopass, match = DENY; enum def_tuple pwcheck; debug_decl(sudoers_lookup_pseudo, SUDOERS_DEBUG_PARSER); @@ -133,26 +133,40 @@ */ switch (runas_matches_pw(nss->parse_tree, cs, list_pw)) { case DENY: - continue; + break; case ALLOW: + /* + * RunAs user matches list user. + * Match on command "list" or ALL. + */ + cmnd_match = cmnd_matches(nss->parse_tree, + cs->cmnd, cs->runchroot, NULL); + if (cmnd_match != UNSPEC) { + match = cmnd_match; + goto done; + } break; default: + /* + * RunAs user doesn't match list user. Only allow + * listing if the user has "sudo ALL" for root. + */ if (root_pw != NULL && runas_matches_pw(nss->parse_tree, cs, root_pw) == ALLOW) { - break; + cmnd_match = cmnd_matches_all(nss->parse_tree, + cs->cmnd, cs->runchroot, NULL); + if (cmnd_match != UNSPEC) { + match = cmnd_match; + goto done; + } } - continue; - } - - /* Match command: "list" or ALL. */ - if (cmnd_matches(nss->parse_tree, cs->cmnd, cs->runchroot, - NULL) == ALLOW) { - match = ALLOW; + break; } } } } } +done: if (root_pw != NULL) sudo_pw_delref(root_pw); if (match == ALLOW || user_uid == 0) { @@ -1067,8 +1081,8 @@ break; } if (match == ALLOW) { - /* For "sudo -l cmd" user_args includes the command being checked. */ - const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", user_args); + const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n", + list_cmnd, user_args ? " " : "", user_args ? user_args : ""); ret = len < 0 ? -1 : true; } debug_return_int(ret); diff -Nru sudo-1.9.13p1/plugins/sudoers/parse.h sudo-1.9.13p3/plugins/sudoers/parse.h --- sudo-1.9.13p1/plugins/sudoers/parse.h 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/parse.h 2023-03-04 16:50:14.000000000 +0100 @@ -405,6 +405,7 @@ bool usergr_matches(const char *group, const char *user, const struct passwd *pw); bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw); int cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot, struct cmnd_info *info); +int cmnd_matches_all(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot, struct cmnd_info *info); int cmndlist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *list, const char *runchroot, struct cmnd_info *info); int host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const char *host, const char *shost, const struct member *m); int hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const struct member_list *list); diff -Nru sudo-1.9.13p1/plugins/sudoers/policy.c sudo-1.9.13p3/plugins/sudoers/policy.c --- sudo-1.9.13p1/plugins/sudoers/policy.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/policy.c 2023-03-04 16:50:13.000000000 +0100 @@ -1270,11 +1270,6 @@ sudo_warnx(U_("unknown user %s"), list_user); debug_return_int(-1); } - /* A user may only list another user they have runas access to. */ - if (runas_pw != NULL) - sudo_pw_delref(runas_pw); - runas_pw = list_pw; - sudo_pw_addref(list_pw); } ret = sudoers_policy_main(argc, argv, I_LISTPW, NULL, verbose, NULL); if (list_user) { diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/fuzz/fuzz_sudoers.c sudo-1.9.13p3/plugins/sudoers/regress/fuzz/fuzz_sudoers.c --- sudo-1.9.13p1/plugins/sudoers/regress/fuzz/fuzz_sudoers.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/fuzz/fuzz_sudoers.c 2023-02-25 19:21:47.000000000 +0100 @@ -45,6 +45,9 @@ static int fuzz_printf(int msg_type, const char *fmt, ...); int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +/* For set_cmnd_path() */ +static const char *orig_cmnd; + /* Required to link with parser. */ struct sudo_user sudo_user; struct passwd *list_pw; @@ -104,8 +107,13 @@ int set_cmnd_path(const char *runchroot) { - /* Cannot return FOUND without also setting user_cmnd to a new value. */ - return NOT_FOUND; + /* Reallocate user_cmnd to catch bugs in command_matches(). */ + char *new_cmnd = strdup(orig_cmnd); + if (new_cmnd == NULL) + return NOT_FOUND_ERROR; + free(user_cmnd); + user_cmnd = new_cmnd; + return FOUND; } /* STUB */ @@ -277,11 +285,12 @@ /* The minimum needed to perform matching (user_cmnd must be dynamic). */ user_host = user_shost = user_runhost = user_srunhost = (char *)"localhost"; - user_cmnd = strdup("/usr/bin/id"); + orig_cmnd = (char *)"/usr/bin/id"; + user_cmnd = strdup(orig_cmnd); if (user_cmnd == NULL) goto done; user_args = (char *)"-u"; - user_base = (char *)"id"; + user_base = sudo_basename(user_cmnd); /* Add a fake network interfaces. */ interfaces = get_interfaces(); diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.in sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.in --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.in 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.in 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,10 @@ +# Test parsing of "list" pseudo-command. +# It should be allowed as a command but also as a user or host. + +user1 ALL = list + +list ALL = ALL + +user2 ALL = (list : list) ALL + +user3 list = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.json.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.json.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.json.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.json.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,79 @@ +{ + "User_Specs": [ + { + "User_List": [ + { "username": "user1" } + ], + "Host_List": [ + { "hostname": "ALL" } + ], + "Cmnd_Specs": [ + { + "Commands": [ + { "command": "list" } + ] + } + ] + }, + { + "User_List": [ + { "username": "list" } + ], + "Host_List": [ + { "hostname": "ALL" } + ], + "Cmnd_Specs": [ + { + "Options": [ + { "setenv": true } + ], + "Commands": [ + { "command": "ALL" } + ] + } + ] + }, + { + "User_List": [ + { "username": "user2" } + ], + "Host_List": [ + { "hostname": "ALL" } + ], + "Cmnd_Specs": [ + { + "runasusers": [ + { "username": "list" } + ], + "runasgroups": [ + { "usergroup": "list" } + ], + "Options": [ + { "setenv": true } + ], + "Commands": [ + { "command": "ALL" } + ] + } + ] + }, + { + "User_List": [ + { "username": "user3" } + ], + "Host_List": [ + { "hostname": "list" } + ], + "Cmnd_Specs": [ + { + "Options": [ + { "setenv": true } + ], + "Commands": [ + { "command": "ALL" } + ] + } + ] + } + ] +} diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,11 @@ +# sudoRole user1 +user1 ALL = list + +# sudoRole list +list ALL = ALL + +# sudoRole user2 +user2 ALL = (list : list) ALL + +# sudoRole user3 +user3 list = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.ldif.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.ldif.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.ldif.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.ldif.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,38 @@ +dn: cn=user1,ou=SUDOers,dc=sudo,dc=ws +objectClass: top +objectClass: sudoRole +cn: user1 +sudoUser: user1 +sudoHost: ALL +sudoCommand: list +sudoOrder: 1 + +dn: cn=list,ou=SUDOers,dc=sudo,dc=ws +objectClass: top +objectClass: sudoRole +cn: list +sudoUser: list +sudoHost: ALL +sudoCommand: ALL +sudoOrder: 2 + +dn: cn=user2,ou=SUDOers,dc=sudo,dc=ws +objectClass: top +objectClass: sudoRole +cn: user2 +sudoUser: user2 +sudoHost: ALL +sudoRunAsUser: list +sudoRunAsGroup: list +sudoCommand: ALL +sudoOrder: 3 + +dn: cn=user3,ou=SUDOers,dc=sudo,dc=ws +objectClass: top +objectClass: sudoRole +cn: user3 +sudoUser: user3 +sudoHost: list +sudoCommand: ALL +sudoOrder: 4 + diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.out.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.out.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.out.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.out.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,6 @@ +Parses OK + +user1 ALL = list +list ALL = ALL +user2 ALL = (list : list) ALL +user3 list = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.sudo.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.sudo.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.sudo.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.sudo.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,7 @@ +user1 ALL = list + +list ALL = ALL + +user2 ALL = (list : list) ALL + +user3 list = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.toke.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.toke.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.toke.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.toke.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,10 @@ +# +# + +WORD(6) ALL = WORD(6) + +WORD(6) ALL = ALL + +WORD(6) ALL = ( WORD(6) : WORD(6) ) ALL + +WORD(6) WORD(6) = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test12.out.ok sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test12.out.ok --- sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test12.out.ok 2023-02-14 17:52:38.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test12.out.ok 2023-03-04 16:50:11.000000000 +0100 @@ -9,6 +9,9 @@ sudoers:5:16: syntax error root ALL = ALL bar ^~~ +sudoers:7:12: expected a fully-qualified path name +root ALL = baz + ^~~ User_Alias A1 = u1 diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test12.sh sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test12.sh --- sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test12.sh 2023-02-14 17:52:38.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test12.sh 2023-03-04 16:50:11.000000000 +0100 @@ -14,4 +14,6 @@ millert ALL = /fail : foo root ALL = ALL bar + +root ALL = baz EOF diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test20.out.ok sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test20.out.ok --- sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test20.out.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test20.out.ok 2023-02-25 19:21:47.000000000 +0100 @@ -0,0 +1,15 @@ +Parses OK + +Entries for user root: + +ALL = CHROOT=/ /bin/ls + host matched + runas matched + cmnd allowed + +ALL = CWD=/ /bin/pwd + host matched + runas matched + cmnd allowed + +Command allowed diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test20.sh sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test20.sh --- sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test20.sh 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test20.sh 2023-02-25 19:21:47.000000000 +0100 @@ -0,0 +1,18 @@ +#!/bin/sh +# +# Verify CHROOT and CWD support +# This will catch an unpatched double-free in set_cmnd_path() under ASAN. +# + +: ${TESTSUDOERS=testsudoers} + +exec 2>&1 + +# Exercise double free of user_cmnd in set_cmnd_path() under ASAN. +# We need more than one rule where the last rule matches and has CHROOT. +$TESTSUDOERS root /bin/ls <<'EOF' +root ALL = CWD=/ /bin/pwd +root ALL = CHROOT=/ /bin/ls +EOF + +exit 0 diff -Nru sudo-1.9.13p1/plugins/sudoers/sudoers.c sudo-1.9.13p3/plugins/sudoers/sudoers.c --- sudo-1.9.13p1/plugins/sudoers/sudoers.c 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/sudoers.c 2023-03-04 16:50:12.000000000 +0100 @@ -1079,7 +1079,14 @@ /* set user_args */ free(user_args); user_args = NULL; - if (NewArgc > 1) { + if (ISSET(sudo_mode, MODE_CHECK)) { + if (NewArgc > 2) { + /* Skip the command being listed in NewArgv[1]. */ + user_args = strvec_join(NewArgv + 2, ' ', NULL); + if (user_args == NULL) + debug_return_int(NOT_FOUND_ERROR); + } + } else if (NewArgc > 1) { if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) && ISSET(sudo_mode, MODE_RUN)) { /* diff -Nru sudo-1.9.13p1/plugins/sudoers/testsudoers.c sudo-1.9.13p3/plugins/sudoers/testsudoers.c --- sudo-1.9.13p1/plugins/sudoers/testsudoers.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/testsudoers.c 2023-02-25 19:21:47.000000000 +0100 @@ -82,6 +82,7 @@ */ struct sudo_user sudo_user; struct passwd *list_pw; +static const char *orig_cmnd; static char *runas_group, *runas_user; #if defined(SUDO_DEVEL) && defined(__OpenBSD__) @@ -203,14 +204,18 @@ if (!dflag) usage(); user_name = argc ? *argv++ : (char *)"root"; - user_cmnd = user_base = (char *)"true"; + orig_cmnd = "true"; argc = 0; } else { user_name = *argv++; - user_cmnd = *argv++; - user_base = sudo_basename(user_cmnd); + orig_cmnd = *argv++; argc -= 2; } + user_cmnd = strdup(orig_cmnd); + if (user_cmnd == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + user_base = sudo_basename(user_cmnd); + if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) sudo_fatalx(U_("unknown user %s"), user_name); @@ -509,8 +514,13 @@ int set_cmnd_path(const char *runchroot) { - /* Cannot return FOUND without also setting user_cmnd to a new value. */ - return NOT_FOUND; + /* Reallocate user_cmnd to catch bugs in command_matches(). */ + char *new_cmnd = strdup(orig_cmnd); + if (new_cmnd == NULL) + return NOT_FOUND_ERROR; + free(user_cmnd); + user_cmnd = new_cmnd; + return FOUND; } static bool diff -Nru sudo-1.9.13p1/plugins/sudoers/toke.l sudo-1.9.13p3/plugins/sudoers/toke.l --- sudo-1.9.13p1/plugins/sudoers/toke.l 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/toke.l 2023-03-04 16:50:10.000000000 +0100 @@ -750,14 +750,6 @@ return SHA512_TOK; } -list { - /* No command line args. */ - LEXTRACE("COMMAND "); - if (!fill_cmnd(sudoerstext, sudoersleng)) - yyterminate(); - return COMMAND; - } /* sudo -l -U otheruser */ - sudoedit { BEGIN GOTCMND; LEXTRACE("COMMAND "); diff -Nru sudo-1.9.13p1/plugins/sudoers/visudo.c sudo-1.9.13p3/plugins/sudoers/visudo.c --- sudo-1.9.13p1/plugins/sudoers/visudo.c 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/visudo.c 2023-02-25 19:21:47.000000000 +0100 @@ -260,7 +260,9 @@ } /* Mock up a fake sudo_user struct. */ - user_cmnd = user_base = (char *)""; + user_cmnd = user_base = strdup("true"); + if (user_cmnd == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); if (geteuid() == 0) { const char *user = getenv("SUDO_USER"); if (user != NULL && *user != '\0') diff -Nru sudo-1.9.13p1/src/exec_nopty.c sudo-1.9.13p3/src/exec_nopty.c --- sudo-1.9.13p1/src/exec_nopty.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/exec_nopty.c 2023-03-04 16:50:12.000000000 +0100 @@ -447,10 +447,15 @@ ev_free_by_fd(evbase, fd); } } - /* Enable reader if buffer is not full. */ + /* + * Enable reader if buffer is not full but avoid reading + * /dev/tty if the command is no longer running. + */ if (iob->revent != NULL && iob->len != sizeof(iob->buf)) { - if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) - sudo_fatal("%s", U_("unable to add event to queue")); + if (!USERTTY_EVENT(iob->revent) || iob->ec->cmnd_pid != -1) { + if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) + sudo_fatal("%s", U_("unable to add event to queue")); + } } } diff -Nru sudo-1.9.13p1/src/exec_pty.c sudo-1.9.13p3/src/exec_pty.c --- sudo-1.9.13p1/src/exec_pty.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/exec_pty.c 2023-03-04 16:50:12.000000000 +0100 @@ -469,10 +469,13 @@ ev_free_by_fd(evbase, fd); } } - /* Enable reader if buffer is not full. */ - if (iob->revent != NULL && - (ttymode == TERM_RAW || !USERTTY_EVENT(iob->revent))) { - if (iob->len != sizeof(iob->buf)) { + /* + * Enable reader if buffer is not full but avoid reading /dev/tty + * if not in raw mode or the command is no longer running. + */ + if (iob->revent != NULL && iob->len != sizeof(iob->buf)) { + if (!USERTTY_EVENT(iob->revent) || + (ttymode == TERM_RAW && iob->ec->cmnd_pid != -1)) { if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) sudo_fatal("%s", U_("unable to add event to queue")); } diff -Nru sudo-1.9.13p1/src/load_plugins.c sudo-1.9.13p3/src/load_plugins.c --- sudo-1.9.13p1/src/load_plugins.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/load_plugins.c 2023-02-23 17:09:38.000000000 +0100 @@ -55,6 +55,8 @@ errno = ENAMETOOLONG; goto bad; } + /* Plugin is static, do not fully-qualify. */ + debug_return_bool(true); } #endif /* STATIC_SUDOERS_PLUGIN */
diff -Nru sudo-1.9.13p1/ChangeLog sudo-1.9.13p3/ChangeLog --- sudo-1.9.13p1/ChangeLog 2023-02-16 19:46:48.000000000 +0100 +++ sudo-1.9.13p3/ChangeLog 2023-03-04 18:00:50.000000000 +0100 @@ -1,8 +1,127 @@ +2023-03-04 Todd C. Miller <todd.mil...@sudo.ws> + + * .hgtags: + Added tag SUDO_1_9_13p3 for changeset 0bdd0b8469e3 + [fc4e872d6d89] [tip] <1.9> + + * NEWS, configure, configure.ac: + Sudo 1.9.13p3 + [0bdd0b8469e3] [SUDO_1_9_13p3] <1.9> + +2023-03-03 Todd C. Miller <todd.mil...@sudo.ws> + + * plugins/sudoers/match.c, plugins/sudoers/parse.c, + plugins/sudoers/parse.h: + A user with "list" privs for root may not list all users. A user + with "sudo ALL" for root _is_ allowed to list any user. + [a3f7301ba4d3] <1.9> + + * plugins/sudoers/policy.c: + sudoers_policy_list: do not set runas_pw to list_pw when listing + This change introduced in sudo 1.9.13 is not actually needed. The + "list" pseudo-command checks are performed via runas_matches_pw() + which does not use runas_pw. GitHub issue #248 + [84effa5ffaa1] <1.9> + + * plugins/sudoers/logging.c, plugins/sudoers/parse.c, + plugins/sudoers/sudoers.c: + Fix "sudo -l command args", broken in sudo 1.9.13. The value of + user_args should not contain the command to be run in "sudo -l + command args", only the arguments of the command being checked. This + restores the pre-1.9.13 behavior. GitHub issue #249 + [3e1225e7bf33] <1.9> + +2023-03-01 Todd C. Miller <todd.mil...@sudo.ws> + + * src/exec_nopty.c, src/exec_pty.c: + write_callback: only enable /dev/tty reader if the command is + running This fixes a hang when there is /dev/tty data in a buffer to + be flushed by the final call to del_io_events(). We do not want to + re-enable the reader when flushing the buffers as part of + pty_finish(). See PR #247 for analysis of the problem and how to + reproduce it. + [b7ea5b5e6a88] <1.9> + +2023-02-28 Todd C. Miller <todd.mil...@sudo.ws> + + * plugins/sudoers/regress/testsudoers/test12.out.ok, + plugins/sudoers/regress/testsudoers/test12.sh: + Test non-fully qualified path name. + [0a9e6e83fe15] <1.9> + + * plugins/sudoers/Makefile.in: + Fix removal of y.tab.[ch] when generating gram.[ch]. + [f69c86ecae66] <1.9> + + * MANIFEST, plugins/sudoers/regress/sudoers/test30.in, + plugins/sudoers/regress/sudoers/test30.json.ok, + plugins/sudoers/regress/sudoers/test30.ldif.ok, + plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok, + plugins/sudoers/regress/sudoers/test30.out.ok, + plugins/sudoers/regress/sudoers/test30.sudo.ok, + plugins/sudoers/regress/sudoers/test30.toke.ok: + Add test for using "list" as user, runas and host. + [ae2c84c73371] <1.9> + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Move handling of the "list" pseudo-command from lexer to parser. The + special handling of "list" in the lexer meant it could not be used + as a user, group or host, which was unintentional. GitHub issue + #246. + [efb3a4dea1da] <1.9> + +2023-02-27 Todd C. Miller <todd.mil...@sudo.ws> + + * include/sudo_compat.h: + Make the check for HAVE_DECL_NSIG consistent with other decl checks. + [616c42c4adce] <1.9> + +2023-02-25 Todd C. Miller <todd.mil...@sudo.ws> + + * .hgtags: + Added tag SUDO_1_9_13p2 for changeset 2db7cee1cb77 + [b0af73801130] <1.9> + + * NEWS, configure, configure.ac: + Sudo 1.9.13p2. + [2db7cee1cb77] [SUDO_1_9_13p2] <1.9> + +2023-02-23 Todd C. Miller <todd.mil...@sudo.ws> + + * lib/util/lbuf.c: + Add missing include of errno.h. + [65ddd70d0c18] <1.9> + + * lib/util/lbuf.c: + sudo_lbuf_expand: check for overflow when rounding to the nearest + power of 2. Problem deteced by oss-fuzz using the fuzz_sudoers + fuzzer. + [9357396fdaa0] <1.9> + + * src/load_plugins.c: + Fix --enable-static-sudoers, broken in sudo 1.9.13. + sudo_qualify_plugin() should not try to fully-qualify the path to a + statically-compiled plugin. GitHub issue #245 + [eca5f1f6555e] <1.9> + +2023-02-21 Todd C. Miller <todd.mil...@sudo.ws> + + * MANIFEST, plugins/sudoers/match_command.c, + plugins/sudoers/regress/fuzz/fuzz_sudoers.c, + plugins/sudoers/regress/testsudoers/test20.out.ok, + plugins/sudoers/regress/testsudoers/test20.sh, + plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c: + Fix potential double free for rules that include a CHROOT= option. + If a rule with a CHROOT= option matches the user, host and runas, + the user_cmnd variable could be freed twice. + [2c1477233f48] <1.9> + 2023-02-16 Todd C. Miller <todd.mil...@sudo.ws> * .hgtags: Added tag SUDO_1_9_13p1 for changeset 49e64402924f - [97ae12488007] [tip] <1.9> + [97ae12488007] <1.9> * NEWS, configure, configure.ac: Merge sudo 1.9.13p1 from tip. diff -Nru sudo-1.9.13p1/configure.ac sudo-1.9.13p3/configure.ac --- sudo-1.9.13p1/configure.ac 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/configure.ac 2023-03-04 17:59:59.000000000 +0100 @@ -18,7 +18,7 @@ dnl OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. dnl AC_PREREQ([2.69]) -AC_INIT([sudo], [1.9.13p1], [https://bugzilla.sudo.ws/], [sudo]) +AC_INIT([sudo], [1.9.13p3], [https://bugzilla.sudo.ws/], [sudo]) AC_CONFIG_HEADERS([config.h pathnames.h]) AC_CONFIG_SRCDIR([src/sudo.c]) AC_CONFIG_AUX_DIR([scripts]) diff -Nru sudo-1.9.13p1/debian/changelog sudo-1.9.13p3/debian/changelog --- sudo-1.9.13p1/debian/changelog 2023-02-18 13:03:19.000000000 +0100 +++ sudo-1.9.13p3/debian/changelog 2023-03-08 21:17:05.000000000 +0100 @@ -1,3 +1,18 @@ +sudo (1.9.13p3-1) unstable; urgency=medium + + * new upstream version: + * Fix potential double free for CHROOT= rules + CVE-2023-27320. (Closes: #1032163) + * Fix --enable-static-sudoers regression + * check for overflow as result of fuzzing efforts + * Fix parser regression disallowing rules for user "list" + * Fix eventloop hang if there is /dev/tty data + * Fix sudo -l command args regression + * Fix sudo -l -U someuser regression + * Fix list privs regression + + -- Marc Haber <mh+debian-packa...@zugschlus.de> Wed, 08 Mar 2023 21:17:05 +0100 + sudo (1.9.13p1-1) unstable; urgency=medium * new upstream version 1.9.13p1 diff -Nru sudo-1.9.13p1/debian/copyright sudo-1.9.13p3/debian/copyright --- sudo-1.9.13p1/debian/copyright 2023-02-18 13:03:19.000000000 +0100 +++ sudo-1.9.13p3/debian/copyright 2023-03-08 21:17:05.000000000 +0100 @@ -4,7 +4,7 @@ Source: https://www.sudo.ws/ Files: * -Copyright: 1994-1996, 1998-2022 Todd C. Miller <todd.mil...@sudo.ws> +Copyright: 1994-1996, 1998-2023 Todd C. Miller <todd.mil...@sudo.ws> License: ISC Files: src/selinux.c @@ -55,10 +55,123 @@ Copyright: 2014, Oracle and/or its affiliates. License: ISC +Files: plugins/sudoers/po/cs.po +Copyright: 2013-2023 Petr Pisar <petr.pi...@atlas.cz> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: ISC + +Files: po/cs.po +Copyright: 2013-2023 Petr Pisar <petr.pi...@atlas.cz> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: plugins/sudoers/po/de.po +Copyright: 2001-2023 Jochen Hein <joc...@jochen.org> + 2013 Hendrik Knackstedt <hendrik.knackst...@t-online.de> + 2015 Mario Blättermann <mario.blaetterm...@gmail.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: po/de.po +Copyright: 2012-2014 Jakob Kramer <jakob.kra...@gmx.de> + 2012, 2014-2017, 2019-2022 Mario Blättermann <mario.blaetterm...@gmail.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: ISC + +Files: plugins/sudoers/po/eo.po + po/eo.po +Copyright: 2013-2019 Felipe Castro <fef...@gmail.com> + 2012, 2019-2023 Keith Bowes <zoop...@gmail.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: ISC + +Files: plugins/sudoers/po/fr.po +Copyright: 2014-2016 Frédéric Hantrais <fhantr...@gmail.com> + 2023 Frédéric Marchal <fmarc...@perso.be> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: po/fr.po +Copyright: 2022-2023 Frédéric Marchal <fmarc...@perso.be> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: po/fur.po +Copyright: 2017, 2023 Fabio Tomat <f.t.pub...@gmail.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: plugins/sudoers/po/hr.po +Copyright: 2016-2023 Božidar Putanec <bozid...@yahoo.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: po/hr.po +Copyright: 2012-2013 Tomislav Krznar <tomislav.krz...@gmail.com> + 2016-2023 Božidar Putanec <bozid...@yahoo.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: plugins/sudoers/po/ja.po + po/ja.po +Copyright: 2011 Yasuaki Taniguchi <yasua...@gmail.com> + 2012, 2015-2023 Takeshi Hamasaki <hmat...@users.sourceforge.jp> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: plugins/sudoers/po/ko.po + po/ko.po +Copyright: 2016-2023 Seong-ho Cho <darkcircle.0...@gmail.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: ISC + +Files: plugins/sudoers/po/pl.po + po/pl.po +Copyright: 2011-2023 Jakub Bogusz <qbo...@pld-linux.org> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: plugins/sudoers/po/ro.po + po/ro.po +Copyright: 2020 Florentina Mușat <florentina.musat...@gmail.com> + 2021-2023 Remus-Gabriel Chelu <remusgabriel.ch...@disroot.org> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: ISC + +Files: plugins/sudoers/po/ru.po +Copyright: 2015 Artem Vorotnikov <ar...@vorotnikov.me> + 2015, 2022 Pavel Maryanov <a...@jack.kiev.ua> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: ISC + Files: plugins/sudoers/po/sv.po po/sv.po Copyright: 2012 Daniel Nylander <p...@danielnylander.se> 2016-2022 Sebastian Rasmussen <seb...@gmail.com> + 2021 Luna Jernberg <droidbit...@gmail.com> +License: public-domain + +Files: plugins/sudoers/po/uk.po +Copyright: 2011-2023 Yuri Chornoivan <yurc...@ukr.net> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: plugins/sudoers/po/zh_CN.po +Copyright: 2011-2018i Wylmer Wang <wantingh...@gmail.com> + 2019-2022 Boyuan Yang <073p...@gmail.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: plugins/sudoers/po/zh_TW.po +Copyright: 2019 Hugwalk <baozou0...@gmail.com> + 2019-2021 Yi-Jyun Pan <pan93...@gmail.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> +License: public-domain + +Files: po/zh_TW.po +Copyright: 2018 林博仁 (Buo-ren, Lin) <buo.ren....@gmail.com> + 2019-2021 Yi-Jyun Pan <pan93...@gmail.com> + 2011-2013 Todd C. Miller <todd.mil...@courtesan.com> License: public-domain Files: lib/util/mmap_alloc.c diff -Nru sudo-1.9.13p1/include/sudo_compat.h sudo-1.9.13p3/include/sudo_compat.h --- sudo-1.9.13p1/include/sudo_compat.h 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/include/sudo_compat.h 2023-03-04 16:50:09.000000000 +0100 @@ -205,7 +205,7 @@ #endif /* !HAVE_DECL_ERRNO */ /* Not all systems define NSIG in signal.h */ -#if !defined(HAVE_DECL_NSIG) || !HAVE_DECL_NSIG +#if defined(HAVE_DECL_NSIG) && !HAVE_DECL_NSIG # if defined(HAVE_DECL__NSIG) && HAVE_DECL__NSIG # define NSIG _NSIG # elif defined(HAVE_DECL___NSIG) && HAVE_DECL___NSIG diff -Nru sudo-1.9.13p1/lib/util/lbuf.c sudo-1.9.13p3/lib/util/lbuf.c --- sudo-1.9.13p1/lib/util/lbuf.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/lib/util/lbuf.c 2023-02-23 17:14:45.000000000 +0100 @@ -26,6 +26,7 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <errno.h> #include "sudo_compat.h" #include "sudo_debug.h" @@ -70,6 +71,7 @@ debug_decl(sudo_lbuf_expand, SUDO_DEBUG_UTIL); if (lbuf->len + extra + 1 <= lbuf->len) { + errno = ENOMEM; sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "integer overflow updating lbuf->len"); lbuf->error = 1; @@ -80,6 +82,13 @@ unsigned int new_size = sudo_pow2_roundup(lbuf->len + extra + 1); char *new_buf; + if (new_size < lbuf->size) { + errno = ENOMEM; + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "integer overflow updating lbuf->size"); + lbuf->error = 1; + debug_return_bool(false); + } if (new_size < 1024) new_size = 1024; if ((new_buf = realloc(lbuf->buf, new_size)) == NULL) { diff -Nru sudo-1.9.13p1/MANIFEST sudo-1.9.13p3/MANIFEST --- sudo-1.9.13p1/MANIFEST 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/MANIFEST 2023-03-04 16:50:10.000000000 +0100 @@ -995,6 +995,13 @@ plugins/sudoers/regress/sudoers/test3.ldif2sudo.ok plugins/sudoers/regress/sudoers/test3.out.ok plugins/sudoers/regress/sudoers/test3.toke.ok +plugins/sudoers/regress/sudoers/test30.in +plugins/sudoers/regress/sudoers/test30.json.ok +plugins/sudoers/regress/sudoers/test30.ldif.ok +plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok +plugins/sudoers/regress/sudoers/test30.out.ok +plugins/sudoers/regress/sudoers/test30.sudo.ok +plugins/sudoers/regress/sudoers/test30.toke.ok plugins/sudoers/regress/sudoers/test4.in plugins/sudoers/regress/sudoers/test4.json.ok plugins/sudoers/regress/sudoers/test4.ldif.ok @@ -1052,6 +1059,8 @@ plugins/sudoers/regress/testsudoers/test2.inc plugins/sudoers/regress/testsudoers/test2.out.ok plugins/sudoers/regress/testsudoers/test2.sh +plugins/sudoers/regress/testsudoers/test20.out.ok +plugins/sudoers/regress/testsudoers/test20.sh plugins/sudoers/regress/testsudoers/test3.out.ok plugins/sudoers/regress/testsudoers/test3.sh plugins/sudoers/regress/testsudoers/test4.out.ok diff -Nru sudo-1.9.13p1/NEWS sudo-1.9.13p3/NEWS --- sudo-1.9.13p1/NEWS 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/NEWS 2023-03-04 17:59:59.000000000 +0100 @@ -1,3 +1,28 @@ +What's new in Sudo 1.9.13p3 + + * Fixed a bug introduced in sudo 1.9.13 that caused a syntax error + when "list" was used as a user or host name. GitHub issue #246. + + * Fixed a bug that could cause sudo to hang when running a command + in a pseudo-terminal when there is still input buffered after a + command has exited. + + * Fixed "sudo -U otheruser -l command". This is a regression in + sudo 1.9.13. GitHub issue #248. + + * Fixed "sudo -l command args" when matching a command in sudoers + with command line arguments. This is a regression in sudo 1.9.13. + GitHub issue #249. + +What's new in Sudo 1.9.13p2 + + * Fixed the --enable-static-sudoers option, broken in sudo 1.9.13. + GitHub issue #245. + + * Fixed a potential double-free bug when matching a sudoers rule + that contains a per-command chroot directive (CHROOT=dir). This + bug was introduced in sudo 1.9.8. + What's new in Sudo 1.9.13p1 * Fixed a typo in the configure script that resulted in a line diff -Nru sudo-1.9.13p1/plugins/sudoers/gram.y sudo-1.9.13p3/plugins/sudoers/gram.y --- sudo-1.9.13p1/plugins/sudoers/gram.y 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/gram.y 2023-03-04 16:50:10.000000000 +0100 @@ -978,6 +978,27 @@ parser_leak_remove(LEAK_PTR, $1.args); parser_leak_add(LEAK_MEMBER, $$); } + | WORD { + if (strcmp($1, "list") == 0) { + struct sudo_command *c; + + if ((c = new_command($1, NULL)) == NULL) { + sudoerserror(N_("unable to allocate memory")); + YYERROR; + } + $$ = new_member((char *)c, COMMAND); + if ($$ == NULL) { + free(c); + sudoerserror(N_("unable to allocate memory")); + YYERROR; + } + parser_leak_remove(LEAK_PTR, $1); + parser_leak_add(LEAK_MEMBER, $$); + } else { + sudoerserror(N_("expected a fully-qualified path name")); + YYERROR; + } + } ; hostaliases : hostalias diff -Nru sudo-1.9.13p1/plugins/sudoers/logging.c sudo-1.9.13p3/plugins/sudoers/logging.c --- sudo-1.9.13p1/plugins/sudoers/logging.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/logging.c 2023-03-04 16:50:12.000000000 +0100 @@ -322,9 +322,9 @@ "sudo on %s.\n"), user_name, user_srunhost); } else { sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s is not allowed " - "to execute '%s%s%s' as %s%s%s on %s.\n"), - user_name, user_cmnd, user_args ? " " : "", - user_args ? user_args : "", + "to execute '%s%s%s%s' as %s%s%s on %s.\n"), + user_name, user_cmnd, list_cmnd ? list_cmnd : "", + user_args ? " " : "", user_args ? user_args : "", list_pw ? list_pw->pw_name : runas_pw ? runas_pw->pw_name : user_name, runas_gr ? ":" : "", runas_gr ? runas_gr->gr_name : "", user_host); diff -Nru sudo-1.9.13p1/plugins/sudoers/Makefile.in sudo-1.9.13p3/plugins/sudoers/Makefile.in --- sudo-1.9.13p1/plugins/sudoers/Makefile.in 2023-02-16 19:43:30.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/Makefile.in 2023-03-04 16:50:11.000000000 +0100 @@ -505,7 +505,7 @@ else \ gram_y="$(srcdir)/gram.y"; \ fi; \ - cmd='$(YACC) -d -p sudoers '"$$gram_y"'; cp prologue $(devdir)/gram.c; $(SED) -e "s/^\\(#line .*\\) \"y\\.tab\\.c\"/\1 \"gram.c\"/" -e "/^# *include <limits.h>/{N;s/__STDC_VERSION__ && 199901 <= __STDC_VERSION__/HAVE_STDINT_H/;}" y.tab.c >> $(devdir)/gram.c; sed -e "s/^\\(#line .*\\) \"y\\.tab\\.h\"/\1 \"gram.h\"/" y.tab.h > $(devdir)/gram.h'; rm -f y.tab.[ch]; \ + cmd='$(YACC) -d -p sudoers '"$$gram_y"'; cp prologue $(devdir)/gram.c; $(SED) -e "s/^\\(#line .*\\) \"y\\.tab\\.c\"/\1 \"gram.c\"/" -e "/^# *include <limits.h>/{N;s/__STDC_VERSION__ && 199901 <= __STDC_VERSION__/HAVE_STDINT_H/;}" y.tab.c >> $(devdir)/gram.c; sed -e "s/^\\(#line .*\\) \"y\\.tab\\.h\"/\1 \"gram.h\"/" y.tab.h > $(devdir)/gram.h; rm -f y.tab.[ch]'; \ echo "$$cmd"; eval $$cmd; \ fi diff -Nru sudo-1.9.13p1/plugins/sudoers/match.c sudo-1.9.13p3/plugins/sudoers/match.c --- sudo-1.9.13p1/plugins/sudoers/match.c 2023-02-14 17:52:37.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/match.c 2023-03-04 16:50:14.000000000 +0100 @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 1996, 1998-2005, 2007-2019 + * Copyright (c) 1996, 1998-2005, 2007-2023 * Todd C. Miller <todd.mil...@sudo.ws> * * Permission to use, copy, modify, and distribute this software for any @@ -414,6 +414,44 @@ alias_put(a); } break; + } + debug_return_int(matched); +} + +/* + * Like cmnd_matches() but only matches against the ALL command. + * Returns ALLOW, DENY or UNSPEC. + */ +int +cmnd_matches_all(struct sudoers_parse_tree *parse_tree, const struct member *m, + const char *runchroot, struct cmnd_info *info) +{ + const bool negated = m->negated; + struct sudo_command *c; + int matched = UNSPEC; + struct alias *a; + debug_decl(cmnd_matches_all, SUDOERS_DEBUG_MATCH); + + switch (m->type) { + case ALL: + c = (struct sudo_command *)m->name; + if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests)) + matched = !negated; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, CMNDALIAS); + if (a != NULL) { + TAILQ_FOREACH_REVERSE(m, &a->members, member_list, entries) { + matched = cmnd_matches_all(parse_tree, m, runchroot, info); + if (matched != UNSPEC) { + if (negated) + matched = !matched; + break; + } + } + alias_put(a); + } + break; } debug_return_int(matched); } diff -Nru sudo-1.9.13p1/plugins/sudoers/match_command.c sudo-1.9.13p3/plugins/sudoers/match_command.c --- sudo-1.9.13p1/plugins/sudoers/match_command.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/match_command.c 2023-02-25 19:22:35.000000000 +0100 @@ -818,12 +818,16 @@ /* Rule-specific runchroot, reset user_cmnd and user_stat. */ int status; + /* Save old user_cmnd first, set_cmnd_path() will free it. */ saved_user_cmnd = user_cmnd; + user_cmnd = NULL; if (user_stat != NULL) saved_user_stat = *user_stat; status = set_cmnd_path(runchroot); - if (status != FOUND) + if (status != FOUND) { + user_cmnd = saved_user_cmnd; saved_user_cmnd = NULL; + } if (info != NULL) info->status = status; } diff -Nru sudo-1.9.13p1/plugins/sudoers/parse.c sudo-1.9.13p3/plugins/sudoers/parse.c --- sudo-1.9.13p1/plugins/sudoers/parse.c 2023-02-14 17:53:34.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/parse.c 2023-03-04 16:50:14.000000000 +0100 @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2004-2005, 2007-2021 Todd C. Miller <todd.mil...@sudo.ws> + * Copyright (c) 2004-2005, 2007-2023 Todd C. Miller <todd.mil...@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 @@ -67,7 +67,7 @@ struct privilege *priv; struct userspec *us; struct defaults *def; - int nopass, match = DENY; + int cmnd_match, nopass, match = DENY; enum def_tuple pwcheck; debug_decl(sudoers_lookup_pseudo, SUDOERS_DEBUG_PARSER); @@ -133,26 +133,40 @@ */ switch (runas_matches_pw(nss->parse_tree, cs, list_pw)) { case DENY: - continue; + break; case ALLOW: + /* + * RunAs user matches list user. + * Match on command "list" or ALL. + */ + cmnd_match = cmnd_matches(nss->parse_tree, + cs->cmnd, cs->runchroot, NULL); + if (cmnd_match != UNSPEC) { + match = cmnd_match; + goto done; + } break; default: + /* + * RunAs user doesn't match list user. Only allow + * listing if the user has "sudo ALL" for root. + */ if (root_pw != NULL && runas_matches_pw(nss->parse_tree, cs, root_pw) == ALLOW) { - break; + cmnd_match = cmnd_matches_all(nss->parse_tree, + cs->cmnd, cs->runchroot, NULL); + if (cmnd_match != UNSPEC) { + match = cmnd_match; + goto done; + } } - continue; - } - - /* Match command: "list" or ALL. */ - if (cmnd_matches(nss->parse_tree, cs->cmnd, cs->runchroot, - NULL) == ALLOW) { - match = ALLOW; + break; } } } } } +done: if (root_pw != NULL) sudo_pw_delref(root_pw); if (match == ALLOW || user_uid == 0) { @@ -1067,8 +1081,8 @@ break; } if (match == ALLOW) { - /* For "sudo -l cmd" user_args includes the command being checked. */ - const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", user_args); + const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n", + list_cmnd, user_args ? " " : "", user_args ? user_args : ""); ret = len < 0 ? -1 : true; } debug_return_int(ret); diff -Nru sudo-1.9.13p1/plugins/sudoers/parse.h sudo-1.9.13p3/plugins/sudoers/parse.h --- sudo-1.9.13p1/plugins/sudoers/parse.h 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/parse.h 2023-03-04 16:50:14.000000000 +0100 @@ -405,6 +405,7 @@ bool usergr_matches(const char *group, const char *user, const struct passwd *pw); bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw); int cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot, struct cmnd_info *info); +int cmnd_matches_all(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot, struct cmnd_info *info); int cmndlist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *list, const char *runchroot, struct cmnd_info *info); int host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const char *host, const char *shost, const struct member *m); int hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const struct member_list *list); diff -Nru sudo-1.9.13p1/plugins/sudoers/policy.c sudo-1.9.13p3/plugins/sudoers/policy.c --- sudo-1.9.13p1/plugins/sudoers/policy.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/policy.c 2023-03-04 16:50:13.000000000 +0100 @@ -1270,11 +1270,6 @@ sudo_warnx(U_("unknown user %s"), list_user); debug_return_int(-1); } - /* A user may only list another user they have runas access to. */ - if (runas_pw != NULL) - sudo_pw_delref(runas_pw); - runas_pw = list_pw; - sudo_pw_addref(list_pw); } ret = sudoers_policy_main(argc, argv, I_LISTPW, NULL, verbose, NULL); if (list_user) { diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/fuzz/fuzz_sudoers.c sudo-1.9.13p3/plugins/sudoers/regress/fuzz/fuzz_sudoers.c --- sudo-1.9.13p1/plugins/sudoers/regress/fuzz/fuzz_sudoers.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/fuzz/fuzz_sudoers.c 2023-02-25 19:21:47.000000000 +0100 @@ -45,6 +45,9 @@ static int fuzz_printf(int msg_type, const char *fmt, ...); int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +/* For set_cmnd_path() */ +static const char *orig_cmnd; + /* Required to link with parser. */ struct sudo_user sudo_user; struct passwd *list_pw; @@ -104,8 +107,13 @@ int set_cmnd_path(const char *runchroot) { - /* Cannot return FOUND without also setting user_cmnd to a new value. */ - return NOT_FOUND; + /* Reallocate user_cmnd to catch bugs in command_matches(). */ + char *new_cmnd = strdup(orig_cmnd); + if (new_cmnd == NULL) + return NOT_FOUND_ERROR; + free(user_cmnd); + user_cmnd = new_cmnd; + return FOUND; } /* STUB */ @@ -277,11 +285,12 @@ /* The minimum needed to perform matching (user_cmnd must be dynamic). */ user_host = user_shost = user_runhost = user_srunhost = (char *)"localhost"; - user_cmnd = strdup("/usr/bin/id"); + orig_cmnd = (char *)"/usr/bin/id"; + user_cmnd = strdup(orig_cmnd); if (user_cmnd == NULL) goto done; user_args = (char *)"-u"; - user_base = (char *)"id"; + user_base = sudo_basename(user_cmnd); /* Add a fake network interfaces. */ interfaces = get_interfaces(); diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.in sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.in --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.in 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.in 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,10 @@ +# Test parsing of "list" pseudo-command. +# It should be allowed as a command but also as a user or host. + +user1 ALL = list + +list ALL = ALL + +user2 ALL = (list : list) ALL + +user3 list = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.json.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.json.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.json.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.json.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,79 @@ +{ + "User_Specs": [ + { + "User_List": [ + { "username": "user1" } + ], + "Host_List": [ + { "hostname": "ALL" } + ], + "Cmnd_Specs": [ + { + "Commands": [ + { "command": "list" } + ] + } + ] + }, + { + "User_List": [ + { "username": "list" } + ], + "Host_List": [ + { "hostname": "ALL" } + ], + "Cmnd_Specs": [ + { + "Options": [ + { "setenv": true } + ], + "Commands": [ + { "command": "ALL" } + ] + } + ] + }, + { + "User_List": [ + { "username": "user2" } + ], + "Host_List": [ + { "hostname": "ALL" } + ], + "Cmnd_Specs": [ + { + "runasusers": [ + { "username": "list" } + ], + "runasgroups": [ + { "usergroup": "list" } + ], + "Options": [ + { "setenv": true } + ], + "Commands": [ + { "command": "ALL" } + ] + } + ] + }, + { + "User_List": [ + { "username": "user3" } + ], + "Host_List": [ + { "hostname": "list" } + ], + "Cmnd_Specs": [ + { + "Options": [ + { "setenv": true } + ], + "Commands": [ + { "command": "ALL" } + ] + } + ] + } + ] +} diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.ldif2sudo.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,11 @@ +# sudoRole user1 +user1 ALL = list + +# sudoRole list +list ALL = ALL + +# sudoRole user2 +user2 ALL = (list : list) ALL + +# sudoRole user3 +user3 list = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.ldif.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.ldif.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.ldif.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.ldif.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,38 @@ +dn: cn=user1,ou=SUDOers,dc=sudo,dc=ws +objectClass: top +objectClass: sudoRole +cn: user1 +sudoUser: user1 +sudoHost: ALL +sudoCommand: list +sudoOrder: 1 + +dn: cn=list,ou=SUDOers,dc=sudo,dc=ws +objectClass: top +objectClass: sudoRole +cn: list +sudoUser: list +sudoHost: ALL +sudoCommand: ALL +sudoOrder: 2 + +dn: cn=user2,ou=SUDOers,dc=sudo,dc=ws +objectClass: top +objectClass: sudoRole +cn: user2 +sudoUser: user2 +sudoHost: ALL +sudoRunAsUser: list +sudoRunAsGroup: list +sudoCommand: ALL +sudoOrder: 3 + +dn: cn=user3,ou=SUDOers,dc=sudo,dc=ws +objectClass: top +objectClass: sudoRole +cn: user3 +sudoUser: user3 +sudoHost: list +sudoCommand: ALL +sudoOrder: 4 + diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.out.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.out.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.out.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.out.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,6 @@ +Parses OK + +user1 ALL = list +list ALL = ALL +user2 ALL = (list : list) ALL +user3 list = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.sudo.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.sudo.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.sudo.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.sudo.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,7 @@ +user1 ALL = list + +list ALL = ALL + +user2 ALL = (list : list) ALL + +user3 list = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.toke.ok sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.toke.ok --- sudo-1.9.13p1/plugins/sudoers/regress/sudoers/test30.toke.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/sudoers/test30.toke.ok 2023-03-04 16:50:10.000000000 +0100 @@ -0,0 +1,10 @@ +# +# + +WORD(6) ALL = WORD(6) + +WORD(6) ALL = ALL + +WORD(6) ALL = ( WORD(6) : WORD(6) ) ALL + +WORD(6) WORD(6) = ALL diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test12.out.ok sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test12.out.ok --- sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test12.out.ok 2023-02-14 17:52:38.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test12.out.ok 2023-03-04 16:50:11.000000000 +0100 @@ -9,6 +9,9 @@ sudoers:5:16: syntax error root ALL = ALL bar ^~~ +sudoers:7:12: expected a fully-qualified path name +root ALL = baz + ^~~ User_Alias A1 = u1 diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test12.sh sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test12.sh --- sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test12.sh 2023-02-14 17:52:38.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test12.sh 2023-03-04 16:50:11.000000000 +0100 @@ -14,4 +14,6 @@ millert ALL = /fail : foo root ALL = ALL bar + +root ALL = baz EOF diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test20.out.ok sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test20.out.ok --- sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test20.out.ok 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test20.out.ok 2023-02-25 19:21:47.000000000 +0100 @@ -0,0 +1,15 @@ +Parses OK + +Entries for user root: + +ALL = CHROOT=/ /bin/ls + host matched + runas matched + cmnd allowed + +ALL = CWD=/ /bin/pwd + host matched + runas matched + cmnd allowed + +Command allowed diff -Nru sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test20.sh sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test20.sh --- sudo-1.9.13p1/plugins/sudoers/regress/testsudoers/test20.sh 1970-01-01 01:00:00.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/regress/testsudoers/test20.sh 2023-02-25 19:21:47.000000000 +0100 @@ -0,0 +1,18 @@ +#!/bin/sh +# +# Verify CHROOT and CWD support +# This will catch an unpatched double-free in set_cmnd_path() under ASAN. +# + +: ${TESTSUDOERS=testsudoers} + +exec 2>&1 + +# Exercise double free of user_cmnd in set_cmnd_path() under ASAN. +# We need more than one rule where the last rule matches and has CHROOT. +$TESTSUDOERS root /bin/ls <<'EOF' +root ALL = CWD=/ /bin/pwd +root ALL = CHROOT=/ /bin/ls +EOF + +exit 0 diff -Nru sudo-1.9.13p1/plugins/sudoers/sudoers.c sudo-1.9.13p3/plugins/sudoers/sudoers.c --- sudo-1.9.13p1/plugins/sudoers/sudoers.c 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/sudoers.c 2023-03-04 16:50:12.000000000 +0100 @@ -1079,7 +1079,14 @@ /* set user_args */ free(user_args); user_args = NULL; - if (NewArgc > 1) { + if (ISSET(sudo_mode, MODE_CHECK)) { + if (NewArgc > 2) { + /* Skip the command being listed in NewArgv[1]. */ + user_args = strvec_join(NewArgv + 2, ' ', NULL); + if (user_args == NULL) + debug_return_int(NOT_FOUND_ERROR); + } + } else if (NewArgc > 1) { if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) && ISSET(sudo_mode, MODE_RUN)) { /* diff -Nru sudo-1.9.13p1/plugins/sudoers/testsudoers.c sudo-1.9.13p3/plugins/sudoers/testsudoers.c --- sudo-1.9.13p1/plugins/sudoers/testsudoers.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/testsudoers.c 2023-02-25 19:21:47.000000000 +0100 @@ -82,6 +82,7 @@ */ struct sudo_user sudo_user; struct passwd *list_pw; +static const char *orig_cmnd; static char *runas_group, *runas_user; #if defined(SUDO_DEVEL) && defined(__OpenBSD__) @@ -203,14 +204,18 @@ if (!dflag) usage(); user_name = argc ? *argv++ : (char *)"root"; - user_cmnd = user_base = (char *)"true"; + orig_cmnd = "true"; argc = 0; } else { user_name = *argv++; - user_cmnd = *argv++; - user_base = sudo_basename(user_cmnd); + orig_cmnd = *argv++; argc -= 2; } + user_cmnd = strdup(orig_cmnd); + if (user_cmnd == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + user_base = sudo_basename(user_cmnd); + if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) sudo_fatalx(U_("unknown user %s"), user_name); @@ -509,8 +514,13 @@ int set_cmnd_path(const char *runchroot) { - /* Cannot return FOUND without also setting user_cmnd to a new value. */ - return NOT_FOUND; + /* Reallocate user_cmnd to catch bugs in command_matches(). */ + char *new_cmnd = strdup(orig_cmnd); + if (new_cmnd == NULL) + return NOT_FOUND_ERROR; + free(user_cmnd); + user_cmnd = new_cmnd; + return FOUND; } static bool diff -Nru sudo-1.9.13p1/plugins/sudoers/toke.l sudo-1.9.13p3/plugins/sudoers/toke.l --- sudo-1.9.13p1/plugins/sudoers/toke.l 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/toke.l 2023-03-04 16:50:10.000000000 +0100 @@ -750,14 +750,6 @@ return SHA512_TOK; } -list { - /* No command line args. */ - LEXTRACE("COMMAND "); - if (!fill_cmnd(sudoerstext, sudoersleng)) - yyterminate(); - return COMMAND; - } /* sudo -l -U otheruser */ - sudoedit { BEGIN GOTCMND; LEXTRACE("COMMAND "); diff -Nru sudo-1.9.13p1/plugins/sudoers/visudo.c sudo-1.9.13p3/plugins/sudoers/visudo.c --- sudo-1.9.13p1/plugins/sudoers/visudo.c 2023-02-14 17:53:06.000000000 +0100 +++ sudo-1.9.13p3/plugins/sudoers/visudo.c 2023-02-25 19:21:47.000000000 +0100 @@ -260,7 +260,9 @@ } /* Mock up a fake sudo_user struct. */ - user_cmnd = user_base = (char *)""; + user_cmnd = user_base = strdup("true"); + if (user_cmnd == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); if (geteuid() == 0) { const char *user = getenv("SUDO_USER"); if (user != NULL && *user != '\0') diff -Nru sudo-1.9.13p1/src/exec_nopty.c sudo-1.9.13p3/src/exec_nopty.c --- sudo-1.9.13p1/src/exec_nopty.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/exec_nopty.c 2023-03-04 16:50:12.000000000 +0100 @@ -447,10 +447,15 @@ ev_free_by_fd(evbase, fd); } } - /* Enable reader if buffer is not full. */ + /* + * Enable reader if buffer is not full but avoid reading + * /dev/tty if the command is no longer running. + */ if (iob->revent != NULL && iob->len != sizeof(iob->buf)) { - if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) - sudo_fatal("%s", U_("unable to add event to queue")); + if (!USERTTY_EVENT(iob->revent) || iob->ec->cmnd_pid != -1) { + if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) + sudo_fatal("%s", U_("unable to add event to queue")); + } } } diff -Nru sudo-1.9.13p1/src/exec_pty.c sudo-1.9.13p3/src/exec_pty.c --- sudo-1.9.13p1/src/exec_pty.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/exec_pty.c 2023-03-04 16:50:12.000000000 +0100 @@ -469,10 +469,13 @@ ev_free_by_fd(evbase, fd); } } - /* Enable reader if buffer is not full. */ - if (iob->revent != NULL && - (ttymode == TERM_RAW || !USERTTY_EVENT(iob->revent))) { - if (iob->len != sizeof(iob->buf)) { + /* + * Enable reader if buffer is not full but avoid reading /dev/tty + * if not in raw mode or the command is no longer running. + */ + if (iob->revent != NULL && iob->len != sizeof(iob->buf)) { + if (!USERTTY_EVENT(iob->revent) || + (ttymode == TERM_RAW && iob->ec->cmnd_pid != -1)) { if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1) sudo_fatal("%s", U_("unable to add event to queue")); } diff -Nru sudo-1.9.13p1/src/load_plugins.c sudo-1.9.13p3/src/load_plugins.c --- sudo-1.9.13p1/src/load_plugins.c 2023-02-14 17:53:02.000000000 +0100 +++ sudo-1.9.13p3/src/load_plugins.c 2023-02-23 17:09:38.000000000 +0100 @@ -55,6 +55,8 @@ errno = ENAMETOOLONG; goto bad; } + /* Plugin is static, do not fully-qualify. */ + debug_return_bool(true); } #endif /* STATIC_SUDOERS_PLUGIN */