From: Todd C. Miller Date: Sat, 20 Apr 2019 23:28:45 +0000 (-0600) Subject: Keep debug fds open in send_mail() to aid in debugging. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aa0146d68d01571287529900310961ab8a9993f2;p=sudo Keep debug fds open in send_mail() to aid in debugging. Adds closefrom_nodebug() which acts like closefrom(3) but doesn't close debug fds for use by send_mail(). Also moves the code to exec the mailer to its own function. --- diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c index 11f4c3437..c200698e6 100644 --- a/plugins/sudoers/logging.c +++ b/plugins/sudoers/logging.c @@ -650,9 +650,112 @@ gai_log_warning(int flags, int errnum, const char *fmt, ...) debug_return_bool(ret); } +static void +closefrom_nodebug(int lowfd) +{ + unsigned char *debug_fds; + int fd, startfd; + debug_decl(closefrom_nodebug, SUDOERS_DEBUG_LOGGING) + + startfd = sudo_debug_get_fds(&debug_fds) + 1; + if (lowfd > startfd) + startfd = lowfd; + + /* Close fds higher than the debug fds. */ + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, + "closing fds >= %d", startfd); + closefrom(startfd); + + /* Close fds [lowfd, startfd) that are not in debug_fds. */ + for (fd = lowfd; fd < startfd; fd++) { + if (sudo_isset(debug_fds, fd)) + continue; + 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 + } + debug_return; +} #define MAX_MAILFLAGS 63 +static void __attribute__((__noreturn__)) +exec_mailer(int *pfd) +{ + char *last, *p, *argv[MAX_MAILFLAGS + 1]; + char *mflags, *mpath = def_mailerpath; + int i; +#ifdef NO_ROOT_MAILER + int perm = PERM_FULL_USER; +#else + int perm = PERM_ROOT; + static char *envp[] = { + "HOME=/", + "PATH=/usr/bin:/bin:/usr/sbin:/sbin", + "LOGNAME=root", + "USER=root", +# ifdef _AIX + "LOGIN=root", +# endif + NULL + }; +#endif /* NO_ROOT_MAILER */ + debug_decl(exec_mailer, SUDOERS_DEBUG_LOGGING) + + /* Set stdin to output side of the pipe */ + if (pfd[0] != STDIN_FILENO) { + if (dup2(pfd[0], STDIN_FILENO) == -1) { + mysyslog(LOG_ERR, _("unable to dup stdin: %m")); + sudo_debug_printf(SUDO_DEBUG_ERROR, + "unable to dup stdin: %s", strerror(errno)); + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); + _exit(127); + } + (void) close(pfd[0]); + } + (void) close(pfd[1]); + + /* Build up an argv based on the mailer path and flags */ + if ((mflags = strdup(def_mailerflags)) == NULL) { + mysyslog(LOG_ERR, _("unable to allocate memory")); + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); + _exit(127); + } + if ((argv[0] = strrchr(mpath, '/'))) + argv[0]++; + else + argv[0] = mpath; + + i = 1; + if ((p = strtok_r(mflags, " \t", &last))) { + do { + argv[i] = p; + } while (++i < MAX_MAILFLAGS && (p = strtok_r(NULL, " \t", &last))); + } + argv[i] = NULL; + + /* + * Depending on the config, either run the mailer as root + * (so user cannot kill it) or as the user (for the paranoid). + */ + (void) set_perms(perm); + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); +#ifdef NO_ROOT_MAILER + execv(mpath, argv); +#else + execve(mpath, argv, envp); +#endif + mysyslog(LOG_ERR, _("unable to execute %s: %m"), mpath); + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to execute %s: %s", + mpath, strerror(errno)); + _exit(127); +} + /* * Send a message to MAILTO user */ @@ -666,18 +769,6 @@ send_mail(const char *fmt, ...) pid_t pid, rv; struct stat sb; va_list ap; -#ifndef NO_ROOT_MAILER - static char *root_envp[] = { - "HOME=/", - "PATH=/usr/bin:/bin:/usr/sbin:/sbin", - "LOGNAME=root", - "USER=root", -# ifdef _AIX - "LOGIN=root", -# endif - NULL - }; -#endif /* NO_ROOT_MAILER */ debug_decl(send_mail, SUDOERS_DEBUG_LOGGING) /* If mailer is disabled just return. */ @@ -703,9 +794,11 @@ send_mail(const char *fmt, ...) mysyslog(LOG_ERR, _("unable to fork: %m")); sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to fork: %s", strerror(errno)); + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); _exit(1); case 0: /* Grandchild continues below. */ + sudo_debug_enter(__func__, __FILE__, __LINE__, sudo_debug_subsys); break; default: /* Parent will wait for us. */ @@ -721,7 +814,9 @@ send_mail(const char *fmt, ...) if (rv != -1 && !WIFSTOPPED(status)) break; } - return true; /* not debug */ + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "child (%d) exit value %d", (int)rv, status); + debug_return_bool(true); } /* Daemonize - disassociate from session/tty. */ @@ -738,8 +833,8 @@ send_mail(const char *fmt, ...) sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, NULL); - /* Close fds so we don't leak anything. */ - closefrom(STDERR_FILENO + 1); + /* Close non-debug fds so we don't leak anything. */ + closefrom_nodebug(STDERR_FILENO + 1); if (pipe(pfd) == -1) { mysyslog(LOG_ERR, _("unable to open pipe: %m")); @@ -759,58 +854,9 @@ send_mail(const char *fmt, ...) _exit(1); break; case 0: - { - char *last, *argv[MAX_MAILFLAGS + 1]; - char *mflags, *mpath = def_mailerpath; - int i; - - /* Child, set stdin to output side of the pipe */ - if (pfd[0] != STDIN_FILENO) { - if (dup2(pfd[0], STDIN_FILENO) == -1) { - mysyslog(LOG_ERR, _("unable to dup stdin: %m")); - sudo_debug_printf(SUDO_DEBUG_ERROR, - "unable to dup stdin: %s", strerror(errno)); - _exit(127); - } - (void) close(pfd[0]); - } - (void) close(pfd[1]); - - /* Build up an argv based on the mailer path and flags */ - if ((mflags = strdup(def_mailerflags)) == NULL) { - mysyslog(LOG_ERR, _("unable to allocate memory")); - _exit(127); - } - if ((argv[0] = strrchr(mpath, '/'))) - argv[0]++; - else - argv[0] = mpath; - - i = 1; - if ((p = strtok_r(mflags, " \t", &last))) { - do { - argv[i] = p; - } while (++i < MAX_MAILFLAGS && (p = strtok_r(NULL, " \t", &last))); - } - argv[i] = NULL; - - /* - * Depending on the config, either run the mailer as root - * (so user cannot kill it) or as the user (for the paranoid). - */ -#ifndef NO_ROOT_MAILER - (void) set_perms(PERM_ROOT); - execve(mpath, argv, root_envp); -#else - (void) set_perms(PERM_FULL_USER); - execv(mpath, argv); -#endif /* NO_ROOT_MAILER */ - mysyslog(LOG_ERR, _("unable to execute %s: %m"), mpath); - sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to execute %s: %s", - mpath, strerror(errno)); - _exit(127); - } - break; + /* Child. */ + exec_mailer(pfd); + /* NOTREACHED */ } (void) close(pfd[0]); @@ -858,6 +904,8 @@ send_mail(const char *fmt, ...) if (rv != -1 && !WIFSTOPPED(status)) break; } + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "child (%d) exit value %d", (int)rv, status); sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); _exit(0); }