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/preload.c
|
||||||
src/selinux.c
|
src/selinux.c
|
||||||
src/sesh.c
|
src/sesh.c
|
||||||
|
src/signal.c
|
||||||
src/solaris.c
|
src/solaris.c
|
||||||
src/sudo.c
|
src/sudo.c
|
||||||
src/sudo.h
|
src/sudo.h
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
/* API version major/minor */
|
/* API version major/minor */
|
||||||
#define SUDO_API_VERSION_MAJOR 1
|
#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_MKVERSION(x, y) ((x << 16) | y)
|
||||||
#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR)
|
#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR)
|
||||||
|
|
||||||
|
@@ -85,8 +85,8 @@ SHELL = @SHELL@
|
|||||||
PROGS = @PROGS@
|
PROGS = @PROGS@
|
||||||
|
|
||||||
OBJS = conversation.o env_hooks.o exec.o exec_common.o exec_pty.o get_pty.o \
|
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 \
|
hooks.o net_ifs.o load_plugins.o parse_args.o signal.o sudo.o \
|
||||||
tgetpass.o ttyname.o utmp.o @SUDO_OBJS@
|
sudo_edit.o tgetpass.o ttyname.o utmp.o @SUDO_OBJS@
|
||||||
|
|
||||||
SESH_OBJS = sesh.o locale_stub.o exec_common.o
|
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)/list.h $(incdir)/sudo_debug.h $(srcdir)/sudo_exec.h \
|
||||||
$(incdir)/sudo_plugin.h
|
$(incdir)/sudo_plugin.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/sesh.c
|
$(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 \
|
solaris.o: $(srcdir)/solaris.c $(top_builddir)/config.h $(srcdir)/sudo.h \
|
||||||
$(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \
|
$(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \
|
||||||
$(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.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
|
* XXX - currently we send SIGCONT upon resume in some cases where
|
||||||
* we don't need to (e.g. command pgrp == parent pgrp).
|
* 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);
|
sigfillset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
|
sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
|
||||||
#ifdef SA_SIGINFO
|
#ifdef SA_SIGINFO
|
||||||
@@ -113,11 +113,11 @@ static int fork_cmnd(struct command_details *details, int sv[2])
|
|||||||
#else
|
#else
|
||||||
sa.sa_handler = handler;
|
sa.sa_handler = handler;
|
||||||
#endif
|
#endif
|
||||||
sigaction(SIGCONT, &sa, NULL);
|
sudo_sigaction(SIGCONT, &sa, NULL, false);
|
||||||
#ifdef SA_SIGINFO
|
#ifdef SA_SIGINFO
|
||||||
sa.sa_sigaction = handler_user_only;
|
sa.sa_sigaction = handler_user_only;
|
||||||
#endif
|
#endif
|
||||||
sigaction(SIGTSTP, &sa, NULL);
|
sudo_sigaction(SIGTSTP, &sa, NULL, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The policy plugin's session init must be run before we fork
|
* 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);
|
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.
|
* 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
|
* 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.
|
* We block all other signals while running the signal handler.
|
||||||
* Note: HP-UX select() will not be interrupted if SA_RESTART set.
|
* 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);
|
sigfillset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
|
sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
|
||||||
#ifdef SA_SIGINFO
|
#ifdef SA_SIGINFO
|
||||||
@@ -297,12 +247,12 @@ sudo_execute(struct command_details *details, struct command_status *cstat)
|
|||||||
#else
|
#else
|
||||||
sa.sa_handler = handler;
|
sa.sa_handler = handler;
|
||||||
#endif
|
#endif
|
||||||
sigaction(SIGALRM, &sa, NULL);
|
sudo_sigaction(SIGTERM, &sa, NULL, true);
|
||||||
sigaction(SIGCHLD, &sa, NULL);
|
sudo_sigaction(SIGALRM, &sa, NULL, false); /* XXX - only if there is a timeout */
|
||||||
sigaction(SIGPIPE, &sa, NULL);
|
sudo_sigaction(SIGCHLD, &sa, NULL, false);
|
||||||
sigaction(SIGTERM, &sa, NULL);
|
sudo_sigaction(SIGPIPE, &sa, NULL, false);
|
||||||
sigaction(SIGUSR1, &sa, NULL);
|
sudo_sigaction(SIGUSR1, &sa, NULL, true);
|
||||||
sigaction(SIGUSR2, &sa, NULL);
|
sudo_sigaction(SIGUSR2, &sa, NULL, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When not running the command in a pty, we do not want to
|
* 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;
|
sa.sa_sigaction = handler_user_only;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sigaction(SIGHUP, &sa, NULL);
|
sudo_sigaction(SIGHUP, &sa, NULL, true);
|
||||||
sigaction(SIGINT, &sa, NULL);
|
sudo_sigaction(SIGINT, &sa, NULL, true);
|
||||||
sigaction(SIGQUIT, &sa, NULL);
|
sudo_sigaction(SIGQUIT, &sa, NULL, true);
|
||||||
|
|
||||||
/* Max fd we will be selecting on. */
|
/* Max fd we will be selecting on. */
|
||||||
maxfd = MAX(sv[0], signal_pipe[0]);
|
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;
|
saved_pgrp = -1;
|
||||||
}
|
}
|
||||||
if (signo == SIGTSTP) {
|
if (signo == SIGTSTP) {
|
||||||
zero_bytes(&sa, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = SIG_DFL;
|
sa.sa_handler = SIG_DFL;
|
||||||
sigaction(SIGTSTP, &sa, &osa);
|
sudo_sigaction(SIGTSTP, &sa, &osa, false);
|
||||||
}
|
}
|
||||||
if (kill(getpid(), signo) != 0)
|
if (kill(getpid(), signo) != 0)
|
||||||
warning("kill(%d, SIG%s)", (int)getpid(), signame);
|
warning("kill(%d, SIG%s)", (int)getpid(), signame);
|
||||||
if (signo == SIGTSTP)
|
if (signo == SIGTSTP)
|
||||||
sigaction(SIGTSTP, &osa, NULL);
|
sudo_sigaction(SIGTSTP, &osa, NULL, false);
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
/*
|
/*
|
||||||
* Restore command's process group if different.
|
* 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
|
* Handles the case where the signal was sent to us before
|
||||||
* we have executed the command.
|
* we have executed the command.
|
||||||
* Returns 1 if we should terminate, else 0.
|
* 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. */
|
/* Only stop if we haven't already been terminated. */
|
||||||
if (signo == SIGTSTP)
|
if (signo == SIGTSTP)
|
||||||
{
|
{
|
||||||
zero_bytes(&sa, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = SIG_DFL;
|
sa.sa_handler = SIG_DFL;
|
||||||
sigaction(SIGTSTP, &sa, NULL);
|
sudo_sigaction(SIGTSTP, &sa, NULL, false);
|
||||||
if (kill(getpid(), SIGTSTP) != 0)
|
if (kill(getpid(), SIGTSTP) != 0)
|
||||||
warning("kill(%d, SIGTSTP)", (int)getpid());
|
warning("kill(%d, SIGTSTP)", (int)getpid());
|
||||||
/* No need to reinstall SIGTSTP handler. */
|
/* No need to reinstall SIGTSTP handler. */
|
||||||
|
@@ -376,11 +376,11 @@ suspend_parent(int signo)
|
|||||||
|
|
||||||
/* Suspend self and continue command when we resume. */
|
/* Suspend self and continue command when we resume. */
|
||||||
if (signo != SIGSTOP) {
|
if (signo != SIGSTOP) {
|
||||||
zero_bytes(&sa, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = SIG_DFL;
|
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);
|
sudo_debug_printf(SUDO_DEBUG_INFO, "kill parent SIG%s", signame);
|
||||||
if (killpg(ppgrp, signo) != 0)
|
if (killpg(ppgrp, signo) != 0)
|
||||||
@@ -413,7 +413,7 @@ suspend_parent(int signo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (signo != SIGSTOP)
|
if (signo != SIGSTOP)
|
||||||
sigaction(signo, &osa, NULL);
|
sudo_sigaction(signo, &osa, NULL, false);
|
||||||
rval = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG;
|
rval = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG;
|
||||||
break;
|
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 */
|
ppgrp = getpgrp(); /* parent's pgrp, so child can signal us */
|
||||||
|
|
||||||
zero_bytes(&sa, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
|
|
||||||
if (io_fds[SFD_USERTTY] != -1) {
|
if (io_fds[SFD_USERTTY] != -1) {
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = sigwinch;
|
sa.sa_handler = sigwinch;
|
||||||
sigaction(SIGWINCH, &sa, NULL);
|
sudo_sigaction(SIGWINCH, &sa, NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* So we can block tty-generated signals */
|
/* 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. */
|
/* We don't want to receive SIGTTIN/SIGTTOU, getting EIO is preferable. */
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGTTIN, &sa, NULL);
|
sudo_sigaction(SIGTTIN, &sa, NULL, true);
|
||||||
sigaction(SIGTTOU, &sa, NULL);
|
sudo_sigaction(SIGTTOU, &sa, NULL, true);
|
||||||
|
|
||||||
/* Job control signals to relay from parent to child. */
|
/* Job control signals to relay from parent to child. */
|
||||||
sigfillset(&sa.sa_mask);
|
sigfillset(&sa.sa_mask);
|
||||||
@@ -656,7 +656,7 @@ fork_pty(struct command_details *details, int sv[], int *maxfd, sigset_t *omask)
|
|||||||
#else
|
#else
|
||||||
sa.sa_handler = handler;
|
sa.sa_handler = handler;
|
||||||
#endif
|
#endif
|
||||||
sigaction(SIGTSTP, &sa, NULL);
|
sudo_sigaction(SIGTSTP, &sa, NULL, true);
|
||||||
|
|
||||||
if (foreground) {
|
if (foreground) {
|
||||||
/* Copy terminal attrs from user tty -> pty slave. */
|
/* 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"));
|
error(1, _("unable to create pipe"));
|
||||||
|
|
||||||
/* Reset SIGWINCH and SIGALRM. */
|
/* Reset SIGWINCH and SIGALRM. */
|
||||||
zero_bytes(&sa, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = SIG_DFL;
|
sa.sa_handler = SIG_DFL;
|
||||||
sigaction(SIGWINCH, &sa, NULL);
|
sudo_sigaction(SIGWINCH, &sa, NULL, false);
|
||||||
sigaction(SIGALRM, &sa, NULL);
|
sudo_sigaction(SIGALRM, &sa, NULL, false); /* XXX - saved value */
|
||||||
|
|
||||||
/* Ignore any SIGTTIN or SIGTTOU we get. */
|
/* Ignore any SIGTTIN or SIGTTOU we get. */
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGTTIN, &sa, NULL);
|
sudo_sigaction(SIGTTIN, &sa, NULL, true);
|
||||||
sigaction(SIGTTOU, &sa, NULL);
|
sudo_sigaction(SIGTTOU, &sa, NULL, true);
|
||||||
|
|
||||||
/* Block all signals in mon_handler(). */
|
/* Block all signals in mon_handler(). */
|
||||||
sigfillset(&sa.sa_mask);
|
sigfillset(&sa.sa_mask);
|
||||||
@@ -1010,7 +1010,7 @@ exec_monitor(struct command_details *details, int backchannel)
|
|||||||
#else
|
#else
|
||||||
sa.sa_handler = mon_handler;
|
sa.sa_handler = mon_handler;
|
||||||
#endif
|
#endif
|
||||||
sigaction(SIGCHLD, &sa, NULL);
|
sudo_sigaction(SIGCHLD, &sa, NULL, false);
|
||||||
|
|
||||||
/* Catch common signals so we can cleanup properly. */
|
/* Catch common signals so we can cleanup properly. */
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
@@ -1020,13 +1020,13 @@ exec_monitor(struct command_details *details, int backchannel)
|
|||||||
#else
|
#else
|
||||||
sa.sa_handler = mon_handler;
|
sa.sa_handler = mon_handler;
|
||||||
#endif
|
#endif
|
||||||
sigaction(SIGHUP, &sa, NULL);
|
sudo_sigaction(SIGHUP, &sa, NULL, true);
|
||||||
sigaction(SIGINT, &sa, NULL);
|
sudo_sigaction(SIGINT, &sa, NULL, true);
|
||||||
sigaction(SIGQUIT, &sa, NULL);
|
sudo_sigaction(SIGQUIT, &sa, NULL, true);
|
||||||
sigaction(SIGTERM, &sa, NULL);
|
sudo_sigaction(SIGTERM, &sa, NULL, true);
|
||||||
sigaction(SIGTSTP, &sa, NULL);
|
sudo_sigaction(SIGTSTP, &sa, NULL, true);
|
||||||
sigaction(SIGUSR1, &sa, NULL);
|
sudo_sigaction(SIGUSR1, &sa, NULL, true);
|
||||||
sigaction(SIGUSR2, &sa, NULL);
|
sudo_sigaction(SIGUSR2, &sa, NULL, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start a new session with the parent as the session leader
|
* 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 plugin_container_list io_plugins;
|
||||||
struct user_details user_details;
|
struct user_details user_details;
|
||||||
const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */
|
const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */
|
||||||
int signal_pipe[2];
|
|
||||||
static int sudo_mode;
|
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 char **get_user_info(struct user_details *);
|
||||||
static void command_info_to_details(char * const info[],
|
static void command_info_to_details(char * const info[],
|
||||||
struct command_details *details);
|
struct command_details *details);
|
||||||
static void setup_signals(void);
|
|
||||||
|
|
||||||
/* Policy plugin convenience functions. */
|
/* Policy plugin convenience functions. */
|
||||||
static int policy_open(struct plugin_container *plugin, char * const settings[],
|
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"));
|
errorx(1, _("unable to initialize policy plugin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_signals();
|
init_signals();
|
||||||
|
|
||||||
switch (sudo_mode & MODE_MASK) {
|
switch (sudo_mode & MODE_MASK) {
|
||||||
case MODE_VERSION:
|
case MODE_VERSION:
|
||||||
@@ -1249,43 +1247,3 @@ iolog_unlink(struct plugin_container *plugin)
|
|||||||
|
|
||||||
debug_return;
|
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 */
|
/* exec.c */
|
||||||
int pipe_nonblock(int fds[2]);
|
int pipe_nonblock(int fds[2]);
|
||||||
int sudo_execute(struct command_details *details, struct command_status *cstat);
|
int sudo_execute(struct command_details *details, struct command_status *cstat);
|
||||||
void restore_signals(void);
|
|
||||||
void save_signals(void);
|
|
||||||
|
|
||||||
/* term.c */
|
/* term.c */
|
||||||
int term_cbreak(int);
|
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[]);
|
int os_init_common(int argc, char *argv[], char *envp[]);
|
||||||
extern const char *list_user, *runas_user, *runas_group;
|
extern const char *list_user, *runas_user, *runas_group;
|
||||||
extern struct user_details user_details;
|
extern struct user_details user_details;
|
||||||
extern int signal_pipe[2];
|
|
||||||
|
|
||||||
/* sudo_edit.c */
|
/* sudo_edit.c */
|
||||||
int sudo_edit(struct command_details *details);
|
int sudo_edit(struct command_details *details);
|
||||||
@@ -267,4 +264,12 @@ int sudo_setgroups(int ngids, const GETGROUPS_T *gids);
|
|||||||
/* ttyname.c */
|
/* ttyname.c */
|
||||||
char *get_process_ttyname(void);
|
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 */
|
#endif /* _SUDO_SUDO_H */
|
||||||
|
Reference in New Issue
Block a user