Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion bubblewrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ static bool opt_unshare_cgroup_try = FALSE;
static bool opt_needs_devpts = FALSE;
static bool opt_new_session = FALSE;
static bool opt_die_with_parent = FALSE;
static bool opt_forward_signals = FALSE;
static uid_t opt_sandbox_uid = -1;
static gid_t opt_sandbox_gid = -1;
static int opt_sync_fd = -1;
Expand Down Expand Up @@ -367,6 +368,7 @@ usage (int ecode, FILE *out)
" --perms OCTAL Set permissions of next argument (--bind-data, --file, etc.)\n"
" --size BYTES Set size of next argument (only for --tmpfs)\n"
" --chmod OCTAL PATH Change permissions of PATH (must already exist)\n"
" --forward-signals Forward SIGNALs to the child process.\n"
);
exit (ecode);
}
Expand All @@ -381,6 +383,32 @@ handle_die_with_parent (void)
die_with_error ("prctl");
}

static int forwarded_signals[] =
{
SIGINT,
SIGTERM,
SIGCONT,
SIGHUP,
SIGQUIT,
SIGUSR1,
SIGUSR2,
SIGWINCH,
};

static void
block_forwarded_signals (sigset_t *prevmask)
{
sigset_t mask;
size_t i;

sigemptyset (&mask);

for (i = 0; i < N_ELEMENTS (forwarded_signals); i++)
{
sigaddset (&mask, forwarded_signals[i]);
}
}

static void
block_sigchild (void)
{
Expand Down Expand Up @@ -502,6 +530,7 @@ monitor_child (int event_fd, pid_t child_pid, int setup_finished_fd)
int exitc;
pid_t died_pid;
int died_status;
size_t i;

/* Close all extra fds in the monitoring process.
Any passed in fds have been passed on to the child anyway. */
Expand All @@ -517,6 +546,11 @@ monitor_child (int event_fd, pid_t child_pid, int setup_finished_fd)
sigemptyset (&mask);
sigaddset (&mask, SIGCHLD);

for (i = 0; i < N_ELEMENTS(forwarded_signals); i++)
{
sigaddset(&mask, forwarded_signals[i]);
}

signal_fd = signalfd (-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
if (signal_fd == -1)
die_with_error ("Can't create signalfd");
Expand Down Expand Up @@ -555,12 +589,17 @@ monitor_child (int event_fd, pid_t child_pid, int setup_finished_fd)
}

/* We need to read the signal_fd, or it will keep polling as read,
* however we ignore the details as we get them from waitpid
* however we ignore the details for SIGCHLD as we get them from waitpid
* below anyway */
s = read (signal_fd, &fdsi, sizeof (struct signalfd_siginfo));
if (s == -1 && errno != EINTR && errno != EAGAIN)
die_with_error ("read signalfd");

/* Propagate signal to child so that it will take the correct
* action. This avoids the parent terminating, leaving an orphan. */
if (fdsi.ssi_signo != SIGCHLD && kill (child_pid, fdsi.ssi_signo))
die_with_error ("kill child");

/* We may actually get several sigchld compressed into one
SIGCHLD, so we have to handle all of them. */
while ((died_pid = waitpid (-1, &died_status, WNOHANG)) > 0)
Expand Down Expand Up @@ -2527,6 +2566,10 @@ parse_args_recurse (int *argcp,
argc -= 1;
break;
}
else if (strcmp (arg, "--forward-signals") == 0)
{
opt_forward_signals = TRUE;
}
else if (*arg == '-')
{
die ("Unknown option %s", arg);
Expand Down Expand Up @@ -2666,6 +2709,8 @@ main (int argc,
cleanup_free char *args_data UNUSED = NULL;
int intermediate_pids_sockets[2] = {-1, -1};
const char *exec_path = NULL;
sigset_t sigmask_before_forwarding;
sigemptyset (&sigmask_before_forwarding);

/* Handle --version early on before we try to acquire/drop
* any capabilities so it works in a build environment;
Expand Down Expand Up @@ -2839,6 +2884,10 @@ main (int argc,
/* We block sigchild here so that we can use signalfd in the monitor. */
block_sigchild ();

/* We block other signals here to avoid leaving an orphan. */
if (opt_forward_signals)
block_forwarded_signals (&sigmask_before_forwarding);

clone_flags = SIGCHLD | CLONE_NEWNS;
if (opt_unshare_user)
clone_flags |= CLONE_NEWUSER;
Expand Down Expand Up @@ -2989,6 +3038,13 @@ main (int argc,
return monitor_child (event_fd, pid, setup_finished_pipe[0]);
}

/* Restore the state of sigmask from before the blocking. */
if (opt_forward_signals)
{
if (sigprocmask (SIG_SETMASK, &sigmask_before_forwarding, NULL) != 0)
die_with_error ("sigprocmask");
}

if (opt_pidns_fd > 0)
{
if (setns (opt_pidns_fd, CLONE_NEWPID) != 0)
Expand Down