2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-30 22:05:46 +00:00

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.
This commit is contained in:
Todd C. Miller
2019-04-20 17:28:45 -06:00
parent 9048ee6c48
commit aa0146d68d

View File

@@ -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);
}