Move signal code into its own source file and add sudo_sigaction()
wrapper that has an extra flag to check the saved_signals list to only install the handler if the signal is not already ignored. Bump plugin API version for the new front-end signal behavior.
This commit is contained in:
1
MANIFEST
1
MANIFEST
@@ -347,6 +347,7 @@ src/po/zh_CN.po
|
||||
src/preload.c
|
||||
src/selinux.c
|
||||
src/sesh.c
|
||||
src/signal.c
|
||||
src/solaris.c
|
||||
src/sudo.c
|
||||
src/sudo.h
|
||||
|
@@ -19,7 +19,7 @@
|
||||
|
||||
/* API version major/minor */
|
||||
#define SUDO_API_VERSION_MAJOR 1
|
||||
#define SUDO_API_VERSION_MINOR 2
|
||||
#define SUDO_API_VERSION_MINOR 3
|
||||
#define SUDO_API_MKVERSION(x, y) ((x << 16) | y)
|
||||
#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR)
|
||||
|
||||
|
@@ -85,8 +85,8 @@ SHELL = @SHELL@
|
||||
PROGS = @PROGS@
|
||||
|
||||
OBJS = conversation.o env_hooks.o exec.o exec_common.o exec_pty.o get_pty.o \
|
||||
hooks.o net_ifs.o load_plugins.o parse_args.o sudo.o sudo_edit.o \
|
||||
tgetpass.o ttyname.o utmp.o @SUDO_OBJS@
|
||||
hooks.o net_ifs.o load_plugins.o parse_args.o signal.o sudo.o \
|
||||
sudo_edit.o tgetpass.o ttyname.o utmp.o @SUDO_OBJS@
|
||||
|
||||
SESH_OBJS = sesh.o locale_stub.o exec_common.o
|
||||
|
||||
@@ -261,6 +261,12 @@ sesh.o: $(srcdir)/sesh.c $(top_builddir)/config.h \
|
||||
$(incdir)/list.h $(incdir)/sudo_debug.h $(srcdir)/sudo_exec.h \
|
||||
$(incdir)/sudo_plugin.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/sesh.c
|
||||
signal.o: $(srcdir)/signal.c $(top_builddir)/config.h $(srcdir)/sudo.h \
|
||||
$(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \
|
||||
$(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \
|
||||
$(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/signal.c
|
||||
solaris.o: $(srcdir)/solaris.c $(top_builddir)/config.h $(srcdir)/sudo.h \
|
||||
$(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \
|
||||
$(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \
|
||||
|
90
src/exec.c
90
src/exec.c
@@ -104,7 +104,7 @@ static int fork_cmnd(struct command_details *details, int sv[2])
|
||||
* XXX - currently we send SIGCONT upon resume in some cases where
|
||||
* we don't need to (e.g. command pgrp == parent pgrp).
|
||||
*/
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
|
||||
#ifdef SA_SIGINFO
|
||||
@@ -113,11 +113,11 @@ static int fork_cmnd(struct command_details *details, int sv[2])
|
||||
#else
|
||||
sa.sa_handler = handler;
|
||||
#endif
|
||||
sigaction(SIGCONT, &sa, NULL);
|
||||
sudo_sigaction(SIGCONT, &sa, NULL, false);
|
||||
#ifdef SA_SIGINFO
|
||||
sa.sa_sigaction = handler_user_only;
|
||||
#endif
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
sudo_sigaction(SIGTSTP, &sa, NULL, true);
|
||||
|
||||
/*
|
||||
* The policy plugin's session init must be run before we fork
|
||||
@@ -175,56 +175,6 @@ static int fork_cmnd(struct command_details *details, int sv[2])
|
||||
debug_return_int(cmnd_pid);
|
||||
}
|
||||
|
||||
static struct signal_state {
|
||||
int signo;
|
||||
sigaction_t sa;
|
||||
} saved_signals[] = {
|
||||
{ SIGALRM }, /* SAVED_SIGALRM */
|
||||
{ SIGCHLD }, /* SAVED_SIGCHLD */
|
||||
{ SIGCONT }, /* SAVED_SIGCONT */
|
||||
{ SIGHUP }, /* SAVED_SIGHUP */
|
||||
{ SIGINT }, /* SAVED_SIGINT */
|
||||
{ SIGPIPE }, /* SAVED_SIGPIPE */
|
||||
{ SIGQUIT }, /* SAVED_SIGQUIT */
|
||||
{ SIGTERM }, /* SAVED_SIGTERM */
|
||||
{ SIGTSTP }, /* SAVED_SIGTSTP */
|
||||
{ SIGTTIN }, /* SAVED_SIGTTIN */
|
||||
{ SIGTTOU }, /* SAVED_SIGTTOU */
|
||||
{ SIGUSR1 }, /* SAVED_SIGUSR1 */
|
||||
{ SIGUSR2 }, /* SAVED_SIGUSR2 */
|
||||
{ -1 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Save signal handler state so it can be restored before exec.
|
||||
*/
|
||||
void
|
||||
save_signals(void)
|
||||
{
|
||||
struct signal_state *ss;
|
||||
debug_decl(save_signals, SUDO_DEBUG_EXEC)
|
||||
|
||||
for (ss = saved_signals; ss->signo != -1; ss++)
|
||||
sigaction(ss->signo, NULL, &ss->sa);
|
||||
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore signal handlers to initial state.
|
||||
*/
|
||||
void
|
||||
restore_signals(void)
|
||||
{
|
||||
struct signal_state *ss;
|
||||
debug_decl(restore_signals, SUDO_DEBUG_EXEC)
|
||||
|
||||
for (ss = saved_signals; ss->signo != -1; ss++)
|
||||
sigaction(ss->signo, &ss->sa, NULL);
|
||||
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute a command, potentially in a pty with I/O loggging.
|
||||
* This is a little bit tricky due to how POSIX job control works and
|
||||
@@ -288,7 +238,7 @@ sudo_execute(struct command_details *details, struct command_status *cstat)
|
||||
* We block all other signals while running the signal handler.
|
||||
* Note: HP-UX select() will not be interrupted if SA_RESTART set.
|
||||
*/
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
|
||||
#ifdef SA_SIGINFO
|
||||
@@ -297,12 +247,12 @@ sudo_execute(struct command_details *details, struct command_status *cstat)
|
||||
#else
|
||||
sa.sa_handler = handler;
|
||||
#endif
|
||||
sigaction(SIGALRM, &sa, NULL);
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
sigaction(SIGUSR2, &sa, NULL);
|
||||
sudo_sigaction(SIGTERM, &sa, NULL, true);
|
||||
sudo_sigaction(SIGALRM, &sa, NULL, false); /* XXX - only if there is a timeout */
|
||||
sudo_sigaction(SIGCHLD, &sa, NULL, false);
|
||||
sudo_sigaction(SIGPIPE, &sa, NULL, false);
|
||||
sudo_sigaction(SIGUSR1, &sa, NULL, true);
|
||||
sudo_sigaction(SIGUSR2, &sa, NULL, true);
|
||||
|
||||
/*
|
||||
* When not running the command in a pty, we do not want to
|
||||
@@ -317,9 +267,9 @@ sudo_execute(struct command_details *details, struct command_status *cstat)
|
||||
sa.sa_sigaction = handler_user_only;
|
||||
}
|
||||
#endif
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
sudo_sigaction(SIGHUP, &sa, NULL, true);
|
||||
sudo_sigaction(SIGINT, &sa, NULL, true);
|
||||
sudo_sigaction(SIGQUIT, &sa, NULL, true);
|
||||
|
||||
/* Max fd we will be selecting on. */
|
||||
maxfd = MAX(sv[0], signal_pipe[0]);
|
||||
@@ -560,15 +510,16 @@ dispatch_signals(int sv[2], pid_t child, int log_io, struct command_status *csta
|
||||
saved_pgrp = -1;
|
||||
}
|
||||
if (signo == SIGTSTP) {
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(SIGTSTP, &sa, &osa);
|
||||
sudo_sigaction(SIGTSTP, &sa, &osa, false);
|
||||
}
|
||||
if (kill(getpid(), signo) != 0)
|
||||
warning("kill(%d, SIG%s)", (int)getpid(), signame);
|
||||
if (signo == SIGTSTP)
|
||||
sigaction(SIGTSTP, &osa, NULL);
|
||||
sudo_sigaction(SIGTSTP, &osa, NULL, false);
|
||||
if (fd != -1) {
|
||||
/*
|
||||
* Restore command's process group if different.
|
||||
@@ -603,7 +554,7 @@ dispatch_signals(int sv[2], pid_t child, int log_io, struct command_status *csta
|
||||
}
|
||||
|
||||
/*
|
||||
* Read pending signals on signale_pipe written by sudo_handler().
|
||||
* Drain pending signals from signale_pipe written by sudo_handler().
|
||||
* Handles the case where the signal was sent to us before
|
||||
* we have executed the command.
|
||||
* Returns 1 if we should terminate, else 0.
|
||||
@@ -647,10 +598,11 @@ dispatch_pending_signals(struct command_status *cstat)
|
||||
/* Only stop if we haven't already been terminated. */
|
||||
if (signo == SIGTSTP)
|
||||
{
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
sudo_sigaction(SIGTSTP, &sa, NULL, false);
|
||||
if (kill(getpid(), SIGTSTP) != 0)
|
||||
warning("kill(%d, SIGTSTP)", (int)getpid());
|
||||
/* No need to reinstall SIGTSTP handler. */
|
||||
|
@@ -376,11 +376,11 @@ suspend_parent(int signo)
|
||||
|
||||
/* Suspend self and continue command when we resume. */
|
||||
if (signo != SIGSTOP) {
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(signo, &sa, &osa);
|
||||
sudo_sigaction(signo, &sa, &osa, false);
|
||||
}
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "kill parent SIG%s", signame);
|
||||
if (killpg(ppgrp, signo) != 0)
|
||||
@@ -413,7 +413,7 @@ suspend_parent(int signo)
|
||||
}
|
||||
|
||||
if (signo != SIGSTOP)
|
||||
sigaction(signo, &osa, NULL);
|
||||
sudo_sigaction(signo, &osa, NULL, false);
|
||||
rval = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG;
|
||||
break;
|
||||
}
|
||||
@@ -569,13 +569,13 @@ fork_pty(struct command_details *details, int sv[], int *maxfd, sigset_t *omask)
|
||||
|
||||
ppgrp = getpgrp(); /* parent's pgrp, so child can signal us */
|
||||
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
if (io_fds[SFD_USERTTY] != -1) {
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = sigwinch;
|
||||
sigaction(SIGWINCH, &sa, NULL);
|
||||
sudo_sigaction(SIGWINCH, &sa, NULL, false);
|
||||
}
|
||||
|
||||
/* So we can block tty-generated signals */
|
||||
@@ -644,8 +644,8 @@ fork_pty(struct command_details *details, int sv[], int *maxfd, sigset_t *omask)
|
||||
|
||||
/* We don't want to receive SIGTTIN/SIGTTOU, getting EIO is preferable. */
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGTTIN, &sa, NULL);
|
||||
sigaction(SIGTTOU, &sa, NULL);
|
||||
sudo_sigaction(SIGTTIN, &sa, NULL, true);
|
||||
sudo_sigaction(SIGTTOU, &sa, NULL, true);
|
||||
|
||||
/* Job control signals to relay from parent to child. */
|
||||
sigfillset(&sa.sa_mask);
|
||||
@@ -656,7 +656,7 @@ fork_pty(struct command_details *details, int sv[], int *maxfd, sigset_t *omask)
|
||||
#else
|
||||
sa.sa_handler = handler;
|
||||
#endif
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
sudo_sigaction(SIGTSTP, &sa, NULL, true);
|
||||
|
||||
if (foreground) {
|
||||
/* Copy terminal attrs from user tty -> pty slave. */
|
||||
@@ -987,17 +987,17 @@ exec_monitor(struct command_details *details, int backchannel)
|
||||
error(1, _("unable to create pipe"));
|
||||
|
||||
/* Reset SIGWINCH and SIGALRM. */
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(SIGWINCH, &sa, NULL);
|
||||
sigaction(SIGALRM, &sa, NULL);
|
||||
sudo_sigaction(SIGWINCH, &sa, NULL, false);
|
||||
sudo_sigaction(SIGALRM, &sa, NULL, false); /* XXX - saved value */
|
||||
|
||||
/* Ignore any SIGTTIN or SIGTTOU we get. */
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGTTIN, &sa, NULL);
|
||||
sigaction(SIGTTOU, &sa, NULL);
|
||||
sudo_sigaction(SIGTTIN, &sa, NULL, true);
|
||||
sudo_sigaction(SIGTTOU, &sa, NULL, true);
|
||||
|
||||
/* Block all signals in mon_handler(). */
|
||||
sigfillset(&sa.sa_mask);
|
||||
@@ -1010,7 +1010,7 @@ exec_monitor(struct command_details *details, int backchannel)
|
||||
#else
|
||||
sa.sa_handler = mon_handler;
|
||||
#endif
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
sudo_sigaction(SIGCHLD, &sa, NULL, false);
|
||||
|
||||
/* Catch common signals so we can cleanup properly. */
|
||||
sa.sa_flags = SA_RESTART;
|
||||
@@ -1020,13 +1020,13 @@ exec_monitor(struct command_details *details, int backchannel)
|
||||
#else
|
||||
sa.sa_handler = mon_handler;
|
||||
#endif
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
sigaction(SIGUSR2, &sa, NULL);
|
||||
sudo_sigaction(SIGHUP, &sa, NULL, true);
|
||||
sudo_sigaction(SIGINT, &sa, NULL, true);
|
||||
sudo_sigaction(SIGQUIT, &sa, NULL, true);
|
||||
sudo_sigaction(SIGTERM, &sa, NULL, true);
|
||||
sudo_sigaction(SIGTSTP, &sa, NULL, true);
|
||||
sudo_sigaction(SIGUSR1, &sa, NULL, true);
|
||||
sudo_sigaction(SIGUSR2, &sa, NULL, true);
|
||||
|
||||
/*
|
||||
* Start a new session with the parent as the session leader
|
||||
|
167
src/signal.c
Normal file
167
src/signal.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
int signal_pipe[2];
|
||||
|
||||
static struct signal_state {
|
||||
int signo;
|
||||
sigaction_t sa;
|
||||
} saved_signals[] = {
|
||||
{ SIGALRM }, /* SAVED_SIGALRM */
|
||||
{ SIGCHLD }, /* SAVED_SIGCHLD */
|
||||
{ SIGCONT }, /* SAVED_SIGCONT */
|
||||
{ SIGHUP }, /* SAVED_SIGHUP */
|
||||
{ SIGINT }, /* SAVED_SIGINT */
|
||||
{ SIGPIPE }, /* SAVED_SIGPIPE */
|
||||
{ SIGQUIT }, /* SAVED_SIGQUIT */
|
||||
{ SIGTERM }, /* SAVED_SIGTERM */
|
||||
{ SIGTSTP }, /* SAVED_SIGTSTP */
|
||||
{ SIGTTIN }, /* SAVED_SIGTTIN */
|
||||
{ SIGTTOU }, /* SAVED_SIGTTOU */
|
||||
{ SIGUSR1 }, /* SAVED_SIGUSR1 */
|
||||
{ SIGUSR2 }, /* SAVED_SIGUSR2 */
|
||||
{ -1 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Save signal handler state so it can be restored before exec.
|
||||
*/
|
||||
void
|
||||
save_signals(void)
|
||||
{
|
||||
struct signal_state *ss;
|
||||
debug_decl(save_signals, SUDO_DEBUG_MAIN)
|
||||
|
||||
for (ss = saved_signals; ss->signo != -1; ss++)
|
||||
sigaction(ss->signo, NULL, &ss->sa);
|
||||
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore signal handlers to initial state for exec.
|
||||
*/
|
||||
void
|
||||
restore_signals(void)
|
||||
{
|
||||
struct signal_state *ss;
|
||||
debug_decl(restore_signals, SUDO_DEBUG_MAIN)
|
||||
|
||||
for (ss = saved_signals; ss->signo != -1; ss++)
|
||||
sigaction(ss->signo, &ss->sa, NULL);
|
||||
|
||||
debug_return;
|
||||
}
|
||||
|
||||
static void
|
||||
sudo_handler(int signo)
|
||||
{
|
||||
/*
|
||||
* The pipe is non-blocking, if we overflow the kernel's pipe
|
||||
* buffer we drop the signal. This is not a problem in practice.
|
||||
*/
|
||||
ignore_result(write(signal_pipe[1], &signo, sizeof(signo)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Trap tty-generated (and other) signals so we can't be killed before
|
||||
* calling the policy close function. The signal pipe will be drained
|
||||
* in sudo_execute() before running the command and new handlers will
|
||||
* be installed in the parent.
|
||||
*/
|
||||
void
|
||||
init_signals(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
struct signal_state *ss;
|
||||
debug_decl(init_signals, SUDO_DEBUG_MAIN)
|
||||
|
||||
/*
|
||||
* We use a pipe to atomically handle signal notification within
|
||||
* the select() loop without races (we may not have pselect()).
|
||||
*/
|
||||
if (pipe_nonblock(signal_pipe) != 0)
|
||||
error(1, _("unable to create pipe"));
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = sudo_handler;
|
||||
|
||||
for (ss = saved_signals; ss->signo > 0; ss++) {
|
||||
switch (ss->signo) {
|
||||
case SIGCHLD:
|
||||
case SIGCONT:
|
||||
case SIGPIPE:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
/* Don't install these until exec time. */
|
||||
break;
|
||||
default:
|
||||
if (ss->sa.sa_handler != SIG_IGN)
|
||||
sigaction(ss->signo, &sa, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like sigaction() but includes an udpate_only flag.
|
||||
* In update-only mode, don't override SIG_IGN.
|
||||
*/
|
||||
int
|
||||
sudo_sigaction(int signo, struct sigaction *sa, struct sigaction *osa, bool update_only)
|
||||
{
|
||||
/* Don't override SIG_IGN if the update_only flag is set. */
|
||||
if (update_only) {
|
||||
struct signal_state *ss;
|
||||
for (ss = saved_signals; ss->signo > 0; ss++) {
|
||||
if (ss->signo == signo) {
|
||||
if (ss->sa.sa_handler == SIG_IGN)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sigaction(signo, sa, osa);
|
||||
}
|
44
src/sudo.c
44
src/sudo.c
@@ -95,7 +95,6 @@ struct plugin_container policy_plugin;
|
||||
struct plugin_container_list io_plugins;
|
||||
struct user_details user_details;
|
||||
const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */
|
||||
int signal_pipe[2];
|
||||
static int sudo_mode;
|
||||
|
||||
/*
|
||||
@@ -107,7 +106,6 @@ static void sudo_check_suid(const char *path);
|
||||
static char **get_user_info(struct user_details *);
|
||||
static void command_info_to_details(char * const info[],
|
||||
struct command_details *details);
|
||||
static void setup_signals(void);
|
||||
|
||||
/* Policy plugin convenience functions. */
|
||||
static int policy_open(struct plugin_container *plugin, char * const settings[],
|
||||
@@ -209,7 +207,7 @@ main(int argc, char *argv[], char *envp[])
|
||||
errorx(1, _("unable to initialize policy plugin"));
|
||||
}
|
||||
|
||||
setup_signals();
|
||||
init_signals();
|
||||
|
||||
switch (sudo_mode & MODE_MASK) {
|
||||
case MODE_VERSION:
|
||||
@@ -1249,43 +1247,3 @@ iolog_unlink(struct plugin_container *plugin)
|
||||
|
||||
debug_return;
|
||||
}
|
||||
|
||||
static void
|
||||
sudo_handler(int signo)
|
||||
{
|
||||
/*
|
||||
* The pipe is non-blocking, if we overflow the kernel's pipe
|
||||
* buffer we drop the signal. This is not a problem in practice.
|
||||
*/
|
||||
ignore_result(write(signal_pipe[1], &signo, sizeof(signo)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Trap tty-generated signals so we can't be killed before calling
|
||||
* the policy close function. The signal pipe will be checked
|
||||
* in sudo_execute().
|
||||
*/
|
||||
static void
|
||||
setup_signals(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
debug_decl(setup_signals, SUDO_DEBUG_MAIN)
|
||||
|
||||
/*
|
||||
* We use a pipe to atomically handle signal notification within
|
||||
* the select() loop without races (we may not have pselect()).
|
||||
*/
|
||||
if (pipe_nonblock(signal_pipe) != 0)
|
||||
error(1, _("unable to create pipe"));
|
||||
|
||||
/* XXX - should not install handler if ignored by default. */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = sudo_handler;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
|
||||
debug_return;
|
||||
}
|
||||
|
11
src/sudo.h
11
src/sudo.h
@@ -184,8 +184,6 @@ void zero_bytes(volatile void *, size_t);
|
||||
/* exec.c */
|
||||
int pipe_nonblock(int fds[2]);
|
||||
int sudo_execute(struct command_details *details, struct command_status *cstat);
|
||||
void restore_signals(void);
|
||||
void save_signals(void);
|
||||
|
||||
/* term.c */
|
||||
int term_cbreak(int);
|
||||
@@ -218,7 +216,6 @@ int run_command(struct command_details *details);
|
||||
int os_init_common(int argc, char *argv[], char *envp[]);
|
||||
extern const char *list_user, *runas_user, *runas_group;
|
||||
extern struct user_details user_details;
|
||||
extern int signal_pipe[2];
|
||||
|
||||
/* sudo_edit.c */
|
||||
int sudo_edit(struct command_details *details);
|
||||
@@ -267,4 +264,12 @@ int sudo_setgroups(int ngids, const GETGROUPS_T *gids);
|
||||
/* ttyname.c */
|
||||
char *get_process_ttyname(void);
|
||||
|
||||
/* signal.c */
|
||||
struct sigaction;
|
||||
extern int signal_pipe[2];
|
||||
int sudo_sigaction(int signo, struct sigaction *sa, struct sigaction *osa, bool update_only);
|
||||
void init_signals(void);
|
||||
void restore_signals(void);
|
||||
void save_signals(void);
|
||||
|
||||
#endif /* _SUDO_SUDO_H */
|
||||
|
Reference in New Issue
Block a user