This patch will upgrade Sudo version 1.8.9 patchlevel 3 to Sudo version 1.8.9 patchlevel 4. To apply: $ cd sudo-1.8.9p3 $ patch -p1 < sudo-1.8.9p4.patch diff -urNa sudo-1.8.9p3/ChangeLog sudo-1.8.9p4/ChangeLog --- sudo-1.8.9p3/ChangeLog Mon Jan 13 11:14:26 2014 +++ sudo-1.8.9p4/ChangeLog Wed Jan 15 06:21:07 2014 @@ -1,3 +1,43 @@ +2014-01-15 Todd C. Miller + + * NEWS, configure, configure.ac: + Update for sudo 1.8.9p4 + [f79ab7c6c1c5] + + * common/sudo_debug.c, include/sudo_debug.h, src/preserve_fds.c: + When relocating fds, update the debug fd if it is set so we are + guaranteed to get debugging output. + [b1deaa472aa6] + +2014-01-14 Todd C. Miller + + * src/exec.c: + If the event loop exits due to an error and we are not logging I/O, + kill the command if still running. Fixes a bug where sudo could exit + while the command was still running. + [844018ff8a8c] + + * src/preserve_fds.c: + When relocating preserved fds, start with the highest ones first to + avoid moving fds around more than we have to. Now uses a bitmap to + keep track of which fds are being preserved. Fixes a bug where the + debugging fd could be relocated to the same fd as the error + backchannel temporarily, resulting in debugging output being printed + to the backchannel if util@debug was enabled. + [55e006dbeaf3] + + * src/preserve_fds.c: + When restoring fds traverse list from high -> low, not low -> high + to avoid implicitly closing an fd we want to relocate. + [6351225f47d7] + + * src/exec.c: + If not logging I/O we may get EOF when the command is executed and + the other end of the backchannel is closed. Just remove the + backchannel event in this case or we will continue to receive the + event. Bug #631 + [a204b69d91f7] + 2014-01-13 Todd C. Miller * src/ttyname.c: diff -urNa sudo-1.8.9p3/NEWS sudo-1.8.9p4/NEWS --- sudo-1.8.9p3/NEWS Mon Jan 13 11:12:10 2014 +++ sudo-1.8.9p4/NEWS Wed Jan 15 06:02:28 2014 @@ -1,3 +1,12 @@ +What's new in Sudo 1.8.9p4? + + * Fixed a bug where sudo could consume large amounts of CPU while + the command was running when I/O logging is not enabled. Bug #631 + + * Fixed a bug where sudo would exit with an error when the debug + level is set to util@debug or all@debug and I/O logging is not + enabled. The command would continue runnning after sudo exited. + What's new in Sudo 1.8.9p3? * Fixed a bug introduced in sudo 1.8.9 that prevented the tty name diff -urNa sudo-1.8.9p3/common/sudo_debug.c sudo-1.8.9p4/common/sudo_debug.c --- sudo-1.8.9p3/common/sudo_debug.c Tue Jan 7 11:08:52 2014 +++ sudo-1.8.9p4/common/sudo_debug.c Wed Jan 15 06:02:18 2014 @@ -570,3 +570,19 @@ { return sudo_debug_fd; } + +/* + * Setter for the debug descriptor. + */ +int +sudo_debug_fd_set(int fd) +{ + if (sudo_debug_fd != -1 && fd != sudo_debug_fd) { + if (dup2(sudo_debug_fd, fd) == -1) + return -1; + (void)fcntl(fd, F_SETFD, FD_CLOEXEC); + close(sudo_debug_fd); + sudo_debug_fd = fd; + } + return sudo_debug_fd; +} diff -urNa sudo-1.8.9p3/configure sudo-1.8.9p4/configure --- sudo-1.8.9p3/configure Mon Jan 13 11:12:11 2014 +++ sudo-1.8.9p4/configure Wed Jan 15 06:02:29 2014 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for sudo 1.8.9p3. +# Generated by GNU Autoconf 2.69 for sudo 1.8.9p4. # # Report bugs to . # @@ -590,8 +590,8 @@ # Identity of this package. PACKAGE_NAME='sudo' PACKAGE_TARNAME='sudo' -PACKAGE_VERSION='1.8.9p3' -PACKAGE_STRING='sudo 1.8.9p3' +PACKAGE_VERSION='1.8.9p4' +PACKAGE_STRING='sudo 1.8.9p4' PACKAGE_BUGREPORT='http://www.sudo.ws/bugs/' PACKAGE_URL='' @@ -1498,7 +1498,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures sudo 1.8.9p3 to adapt to many kinds of systems. +\`configure' configures sudo 1.8.9p4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1563,7 +1563,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sudo 1.8.9p3:";; + short | recursive ) echo "Configuration of sudo 1.8.9p4:";; esac cat <<\_ACEOF @@ -1793,7 +1793,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sudo configure 1.8.9p3 +sudo configure 1.8.9p4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2502,7 +2502,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sudo $as_me 1.8.9p3, which was +It was created by sudo $as_me 1.8.9p4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -22766,7 +22766,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sudo $as_me 1.8.9p3, which was +This file was extended by sudo $as_me 1.8.9p4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -22832,7 +22832,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -sudo config.status 1.8.9p3 +sudo config.status 1.8.9p4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -urNa sudo-1.8.9p3/configure.ac sudo-1.8.9p4/configure.ac --- sudo-1.8.9p3/configure.ac Mon Jan 13 11:12:11 2014 +++ sudo-1.8.9p4/configure.ac Wed Jan 15 06:02:29 2014 @@ -4,7 +4,7 @@ dnl Copyright (c) 1994-1996,1998-2014 Todd C. Miller dnl AC_PREREQ([2.59]) -AC_INIT([sudo], [1.8.9p3], [http://www.sudo.ws/bugs/], [sudo]) +AC_INIT([sudo], [1.8.9p4], [http://www.sudo.ws/bugs/], [sudo]) AC_CONFIG_HEADER([config.h pathnames.h]) AC_CONFIG_SRCDIR([src/sudo.c]) dnl diff -urNa sudo-1.8.9p3/include/sudo_debug.h sudo-1.8.9p4/include/sudo_debug.h --- sudo-1.8.9p3/include/sudo_debug.h Tue Jan 7 11:08:51 2014 +++ sudo-1.8.9p4/include/sudo_debug.h Wed Jan 15 06:02:18 2014 @@ -219,6 +219,7 @@ void sudo_debug_exit_str_masked(const char *func, const char *file, int line, int subsys, const char *rval); void sudo_debug_exit_ptr(const char *func, const char *file, int line, int subsys, const void *rval); int sudo_debug_fd_get(void); +int sudo_debug_fd_set(int fd); int sudo_debug_init(const char *debugfile, const char *settings); void sudo_debug_printf_nvm(int pri, const char *fmt, ...) __printf0like(2, 3); void sudo_debug_printf2(const char *func, const char *file, int line, int level, const char *fmt, ...) __printf0like(5, 6); diff -urNa sudo-1.8.9p3/src/exec.c sudo-1.8.9p4/src/exec.c --- sudo-1.8.9p3/src/exec.c Tue Jan 7 11:09:20 2014 +++ sudo-1.8.9p4/src/exec.c Tue Jan 14 20:38:09 2014 @@ -230,11 +230,14 @@ /* Short read or EOF. */ sudo_debug_printf(SUDO_DEBUG_ERROR, "failed to read child status: %s", n ? "short read" : "EOF"); - /* - * If not logging I/O we may get EOF when the command is - * executed and sv is closed. It is safe to ignore this. - */ - if (ec->log_io || n != 0) { + if (!ec->log_io && n == 0) { + /* + * If not logging I/O we may get EOF when the command is + * executed and the other end of the backchannel is closed. + * Just remove the event in this case. + */ + (void)sudo_ev_del(ec->evbase, backchannel_event); + } else { /* XXX - need new CMD_ type for monitor errors. */ errno = n ? EIO : ECONNRESET; ec->cstat->type = CMD_ERRNO; @@ -480,6 +483,9 @@ if (sudo_ev_got_break(evbase)) { /* error from callback */ sudo_debug_printf(SUDO_DEBUG_ERROR, "event loop exited prematurely"); + /* kill command if still running and not I/O logging */ + if (!log_io && kill(child, 0) == 0) + terminate_command(child, true); } if (log_io) { diff -urNa sudo-1.8.9p3/src/preserve_fds.c sudo-1.8.9p4/src/preserve_fds.c --- sudo-1.8.9p3/src/preserve_fds.c Tue Jan 7 11:09:20 2014 +++ sudo-1.8.9p4/src/preserve_fds.c Wed Jan 15 06:02:18 2014 @@ -16,7 +16,13 @@ #include -#include +#include /* for howmany() on Linux */ +#ifdef HAVE_SYS_SYSMACROS_H +# include /* for howmany() on Solaris */ +#endif /* HAVE_SYS_SYSMACROS_H */ +#ifdef HAVE_SYS_SELECT_H +# include /* for FD_* macros */ +#endif /* HAVE_SYS_SELECT_H */ #include #ifdef STDC_HEADERS # include @@ -65,6 +71,8 @@ TAILQ_FOREACH(pfd, pfds, entries) { if (fd == pfd->highfd) { /* already preserved */ + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, + "fd %d already preserved", fd); efree(pfd_new); break; } @@ -85,57 +93,41 @@ } /* - * Close fds in the range [from,to] - */ -static void -closefrom_range(int from, int to) -{ - debug_decl(closefrom_range, SUDO_DEBUG_UTIL) - - sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, - "closing fds [%d, %d]", from, to); - while (from <= to) { -#ifdef __APPLE__ - /* Avoid potential libdispatch crash when we close its fds. */ - (void) fcntl(from, F_SETFD, FD_CLOEXEC); -#else - (void) close(from); -#endif - from++; - } - debug_return; -} - -/* * Close all descriptors, startfd and higher except those listed * in pfds. */ void closefrom_except(int startfd, struct preserved_fd_list *pfds) { - int tmpfd; + int debug_fd, fd, lastfd = -1; struct preserved_fd *pfd, *pfd_next; + fd_set *fdsp; debug_decl(closefrom_except, SUDO_DEBUG_UTIL) - /* - * First, relocate preserved fds to be as contiguous as possible. - */ - TAILQ_FOREACH_SAFE(pfd, pfds, entries, pfd_next) { + debug_fd = sudo_debug_fd_get(); + + /* First, relocate preserved fds to be as contiguous as possible. */ + TAILQ_FOREACH_REVERSE_SAFE(pfd, pfds, preserved_fd_list, entries, pfd_next) { if (pfd->highfd < startfd) continue; - tmpfd = dup(pfd->highfd); - if (tmpfd < pfd->highfd) { - if (tmpfd == -1) { + fd = dup(pfd->highfd); + if (fd < pfd->highfd) { + if (fd == -1) { if (errno == EBADF) TAILQ_REMOVE(pfds, pfd, entries); continue; } - pfd->lowfd = tmpfd; - tmpfd = pfd->highfd; + pfd->lowfd = fd; + fd = pfd->highfd; + if (fd == debug_fd) + debug_fd = sudo_debug_fd_set(pfd->lowfd); sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, "dup %d -> %d", pfd->highfd, pfd->lowfd); } - (void) close(tmpfd); + (void) close(fd); + + if (pfd->lowfd > lastfd) + lastfd = pfd->lowfd; /* highest (relocated) preserved fd */ } if (TAILQ_EMPTY(pfds)) { @@ -146,27 +138,37 @@ debug_return; } - /* Close any fds [startfd,TAILQ_FIRST(pfds)->lowfd) */ - closefrom_range(startfd, TAILQ_FIRST(pfds)->lowfd - 1); + /* Create bitmap of preserved (relocated) fds. */ + fdsp = ecalloc(howmany(lastfd + 1, NFDBITS), sizeof(fd_mask)); + TAILQ_FOREACH(pfd, pfds, entries) { + FD_SET(pfd->lowfd, fdsp); + } - /* Close any unpreserved fds (TAILQ_LAST(pfds)->lowfd,startfd) */ - TAILQ_FOREACH_SAFE(pfd, pfds, entries, pfd_next) { - if (pfd->lowfd < startfd) - continue; - if (pfd_next != NULL && pfd->lowfd + 1 != pfd_next->lowfd) - closefrom_range(pfd->lowfd + 1, pfd_next->lowfd); + /* + * Close any unpreserved fds [startfd,lastfd] + * NOTE: this could relocate the debug fd, breaking the debug subsystem. + */ + for (fd = startfd; fd <= lastfd; fd++) { + if (!FD_ISSET(fd, fdsp)) { + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, + "closing fd %d", fd); +#ifdef __APPLE__ + /* Avoid potential libdispatch crash when we close its fds. */ + (void) fcntl(fd, F_SETFD, FD_CLOEXEC); +#else + (void) close(fd); +#endif + } } + free(fdsp); /* Let closefrom() do the rest for us. */ - pfd = TAILQ_LAST(pfds, preserved_fd_list); - if (pfd != NULL && pfd->lowfd + 1 > startfd) - startfd = pfd->lowfd + 1; sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, - "closefrom(%d)", startfd); - closefrom(startfd); + "closefrom(%d)", lastfd + 1); + closefrom(lastfd + 1); /* Restore preserved fds and set flags. */ - TAILQ_FOREACH(pfd, pfds, entries) { + TAILQ_FOREACH_REVERSE(pfd, pfds, preserved_fd_list, entries) { if (pfd->lowfd != pfd->highfd) { if (dup2(pfd->lowfd, pfd->highfd) == -1) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, @@ -184,6 +186,8 @@ sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, "fcntl(%d, F_SETFD, %d)", pfd->highfd, pfd->flags); } + if (pfd->lowfd == debug_fd) + debug_fd = sudo_debug_fd_set(pfd->highfd); (void) close(pfd->lowfd); } }