When using ptrace(2), push the point where we suspend into exec_cmnd().
This should reduce the amount of time the child has to wait for the parent to use PTRACE_SEIZE to seize control and then PTRACE_CONT to continue the child.
This commit is contained in:
37
src/exec.c
37
src/exec.c
@@ -48,6 +48,14 @@
|
|||||||
#include "sudo_plugin.h"
|
#include "sudo_plugin.h"
|
||||||
#include "sudo_plugin_int.h"
|
#include "sudo_plugin_int.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_PTRACE_INTERCEPT
|
||||||
|
static void
|
||||||
|
handler(int signo)
|
||||||
|
{
|
||||||
|
/* just return */
|
||||||
|
}
|
||||||
|
#endif /* HAVE_PTRACE_INTERCEPT */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
close_fds(struct command_details *details, int errfd, int intercept_fd)
|
close_fds(struct command_details *details, int errfd, int intercept_fd)
|
||||||
{
|
{
|
||||||
@@ -245,10 +253,35 @@ done:
|
|||||||
* If the exec fails, cstat is filled in with the value of errno.
|
* If the exec fails, cstat is filled in with the value of errno.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
exec_cmnd(struct command_details *details, int intercept_fd, int errfd)
|
exec_cmnd(struct command_details *details, sigset_t *mask,
|
||||||
|
int intercept_fd, int errfd)
|
||||||
{
|
{
|
||||||
debug_decl(exec_cmnd, SUDO_DEBUG_EXEC);
|
debug_decl(exec_cmnd, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
#ifdef HAVE_PTRACE_INTERCEPT
|
||||||
|
if (ISSET(details->flags, CD_USE_PTRACE)) {
|
||||||
|
struct sigaction sa;
|
||||||
|
sigset_t set;
|
||||||
|
|
||||||
|
/* Tracer will send us SIGUSR1 when it is time to proceed. */
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sa.sa_handler = handler;
|
||||||
|
if (sudo_sigaction(SIGUSR1, &sa, NULL) != 0) {
|
||||||
|
sudo_warn(U_("unable to set handler for signal %d"),
|
||||||
|
SIGUSR1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Suspend child until tracer seizes control and sends SIGUSR1. */
|
||||||
|
sigfillset(&set);
|
||||||
|
sigdelset(&set, SIGUSR1);
|
||||||
|
sigsuspend(&set);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_PTRACE_INTERCEPT */
|
||||||
|
|
||||||
|
if (mask != NULL)
|
||||||
|
sigprocmask(SIG_SETMASK, mask, NULL);
|
||||||
restore_signals();
|
restore_signals();
|
||||||
if (exec_setup(details, intercept_fd, errfd) == true) {
|
if (exec_setup(details, intercept_fd, errfd) == true) {
|
||||||
/* headed for execve() */
|
/* headed for execve() */
|
||||||
@@ -440,7 +473,7 @@ sudo_execute(struct command_details *details, struct command_status *cstat)
|
|||||||
*/
|
*/
|
||||||
if (direct_exec_allowed(details)) {
|
if (direct_exec_allowed(details)) {
|
||||||
if (!sudo_terminated(cstat)) {
|
if (!sudo_terminated(cstat)) {
|
||||||
exec_cmnd(details, -1, -1);
|
exec_cmnd(details, NULL, -1, -1);
|
||||||
cstat->type = CMD_ERRNO;
|
cstat->type = CMD_ERRNO;
|
||||||
cstat->val = errno;
|
cstat->val = errno;
|
||||||
}
|
}
|
||||||
|
@@ -386,8 +386,8 @@ mon_backchannel_cb(int fd, int what, void *v)
|
|||||||
* Returns only if execve() fails.
|
* Returns only if execve() fails.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
exec_cmnd_pty(struct command_details *details, bool foreground,
|
exec_cmnd_pty(struct command_details *details, sigset_t *mask,
|
||||||
int intercept_fd, int errfd)
|
bool foreground, int intercept_fd, int errfd)
|
||||||
{
|
{
|
||||||
volatile pid_t self = getpid();
|
volatile pid_t self = getpid();
|
||||||
debug_decl(exec_cmnd_pty, SUDO_DEBUG_EXEC);
|
debug_decl(exec_cmnd_pty, SUDO_DEBUG_EXEC);
|
||||||
@@ -430,7 +430,7 @@ exec_cmnd_pty(struct command_details *details, bool foreground,
|
|||||||
/* Execute command; only returns on error. */
|
/* Execute command; only returns on error. */
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "executing %s in the %s",
|
sudo_debug_printf(SUDO_DEBUG_INFO, "executing %s in the %s",
|
||||||
details->command, foreground ? "foreground" : "background");
|
details->command, foreground ? "foreground" : "background");
|
||||||
exec_cmnd(details, intercept_fd, errfd);
|
exec_cmnd(details, mask, intercept_fd, errfd);
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
@@ -536,14 +536,6 @@ fill_exec_closure_monitor(struct monitor_closure *mc,
|
|||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_PTRACE_INTERCEPT
|
|
||||||
static void
|
|
||||||
handler(int signo)
|
|
||||||
{
|
|
||||||
/* just return */
|
|
||||||
}
|
|
||||||
#endif /* HAVE_PTRACE_INTERCEPT */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Monitor process that creates a new session with the controlling tty,
|
* Monitor process that creates a new session with the controlling tty,
|
||||||
* resets signal handlers and forks a child to call exec_cmnd_pty().
|
* resets signal handlers and forks a child to call exec_cmnd_pty().
|
||||||
@@ -638,28 +630,8 @@ exec_monitor(struct command_details *details, sigset_t *oset,
|
|||||||
close(errpipe[0]);
|
close(errpipe[0]);
|
||||||
if (io_fds[SFD_USERTTY] != -1)
|
if (io_fds[SFD_USERTTY] != -1)
|
||||||
close(io_fds[SFD_USERTTY]);
|
close(io_fds[SFD_USERTTY]);
|
||||||
#ifdef HAVE_PTRACE_INTERCEPT
|
|
||||||
if (ISSET(details->flags, CD_USE_PTRACE)) {
|
|
||||||
sigset_t set;
|
|
||||||
|
|
||||||
/* Tracer will send us SIGUSR1 when it is time to proceed. */
|
|
||||||
sa.sa_handler = handler;
|
|
||||||
if (sudo_sigaction(SIGUSR1, &sa, NULL) != 0) {
|
|
||||||
sudo_warn(U_("unable to set handler for signal %d"),
|
|
||||||
SIGUSR1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Suspend child until tracer seizes control and sends SIGUSR1. */
|
|
||||||
sigfillset(&set);
|
|
||||||
sigdelset(&set, SIGUSR1);
|
|
||||||
sigsuspend(&set);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_PTRACE_INTERCEPT */
|
|
||||||
sigprocmask(SIG_SETMASK, oset, NULL);
|
|
||||||
restore_signals();
|
|
||||||
|
|
||||||
/* setup tty and exec command */
|
/* setup tty and exec command */
|
||||||
exec_cmnd_pty(details, foreground, intercept_fd, errpipe[1]);
|
exec_cmnd_pty(details, oset, foreground, intercept_fd, errpipe[1]);
|
||||||
if (write(errpipe[1], &errno, sizeof(int)) == -1)
|
if (write(errpipe[1], &errno, sizeof(int)) == -1)
|
||||||
sudo_warn(U_("unable to execute %s"), details->command);
|
sudo_warn(U_("unable to execute %s"), details->command);
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
|
@@ -348,14 +348,6 @@ free_exec_closure_nopty(struct exec_closure_nopty *ec)
|
|||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_PTRACE_INTERCEPT
|
|
||||||
static void
|
|
||||||
handler(int signo)
|
|
||||||
{
|
|
||||||
/* just return */
|
|
||||||
}
|
|
||||||
#endif /* HAVE_PTRACE_INTERCEPT */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute a command and wait for it to finish.
|
* Execute a command and wait for it to finish.
|
||||||
*/
|
*/
|
||||||
@@ -426,27 +418,7 @@ exec_nopty(struct command_details *details, struct command_status *cstat)
|
|||||||
close(errpipe[0]);
|
close(errpipe[0]);
|
||||||
if (intercept_sv[0] != -1)
|
if (intercept_sv[0] != -1)
|
||||||
close(intercept_sv[0]);
|
close(intercept_sv[0]);
|
||||||
#ifdef HAVE_PTRACE_INTERCEPT
|
exec_cmnd(details, &oset, intercept_sv[1], errpipe[1]);
|
||||||
if (ISSET(details->flags, CD_USE_PTRACE)) {
|
|
||||||
struct sigaction sa;
|
|
||||||
|
|
||||||
/* Tracer will send us SIGUSR1 when it is time to proceed. */
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = SA_RESTART;
|
|
||||||
sa.sa_handler = handler;
|
|
||||||
if (sudo_sigaction(SIGUSR1, &sa, NULL) != 0) {
|
|
||||||
sudo_warn(U_("unable to set handler for signal %d"),
|
|
||||||
SIGUSR1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Suspend child until tracer seizes control and sends SIGUSR1. */
|
|
||||||
sigdelset(&set, SIGUSR1);
|
|
||||||
sigsuspend(&set);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_PTRACE_INTERCEPT */
|
|
||||||
sigprocmask(SIG_SETMASK, &oset, NULL);
|
|
||||||
exec_cmnd(details, intercept_sv[1], errpipe[1]);
|
|
||||||
while (write(errpipe[1], &errno, sizeof(int)) == -1) {
|
while (write(errpipe[1], &errno, sizeof(int)) == -1) {
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
break;
|
break;
|
||||||
|
@@ -113,7 +113,7 @@ struct sudo_event_base;
|
|||||||
struct stat;
|
struct stat;
|
||||||
|
|
||||||
/* exec.c */
|
/* exec.c */
|
||||||
void exec_cmnd(struct command_details *details, int intercept_fd, int errfd);
|
void exec_cmnd(struct command_details *details, sigset_t *mask, int intercept_fd, int errfd);
|
||||||
void terminate_command(pid_t pid, bool use_pgrp);
|
void terminate_command(pid_t pid, bool use_pgrp);
|
||||||
bool sudo_terminated(struct command_status *cstat);
|
bool sudo_terminated(struct command_status *cstat);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user