Skip to content

Commit

Permalink
pidfd: block SIGCHLD during tmp process creation
Browse files Browse the repository at this point in the history
This patch blocks SIGCHLD during temporary process creation to prevent a
race condition between kill() and waitpid() where sigchld_handler()
causes `criu restore` to fail with an error.

Fixes: #2490

Signed-off-by: Bhavik Sachdev <[email protected]>
Signed-off-by: Radostin Stoyanov <[email protected]>
  • Loading branch information
bsach64 authored and rst0git committed Oct 20, 2024
1 parent 59afbf3 commit 66f165e
Showing 1 changed file with 20 additions and 0 deletions.
20 changes: 20 additions & 0 deletions criu/pidfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,20 @@ static int create_tmp_process(void)
static int free_dead_pidfd(struct dead_pidfd *dead)
{
int status;
sigset_t blockmask, oldmask;

/*
* Block SIGCHLD to prevent interfering from sigchld_handler()
* and to properly handle the tmp process termination without
* a race condition. A similar approach is used in cr_system().
*/
sigemptyset(&oldmask);
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &blockmask, &oldmask) == -1) {
pr_perror("Cannot set mask of blocked signals");
goto err;
}

if (kill(dead->pid, SIGKILL) < 0) {
pr_perror("Could not kill temporary process with pid: %d",
Expand All @@ -158,6 +172,12 @@ static int free_dead_pidfd(struct dead_pidfd *dead)
goto err;
}

/* Restore the original signal mask after tmp process has terminated */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) {
pr_perror("Cannot clear blocked signals");
goto err;
}

if (!WIFSIGNALED(status)) {
pr_err("Expected temporary process to be terminated by a signal\n");
goto err;
Expand Down

0 comments on commit 66f165e

Please sign in to comment.