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 */
 

Reply via email to