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 <b.sachdev1904@gmail.com>
Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
  • Loading branch information
bsach64 authored and rst0git committed Oct 14, 2024
1 parent 56bc739 commit 2f5e4f5
Showing 1 changed file with 19 additions and 0 deletions.
19 changes: 19 additions & 0 deletions criu/pidfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ 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 +171,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 2f5e4f5

Please sign in to comment.