From: Earl Chew Date: Sat, 1 Jan 2022 22:44:47 +0000 (-0800) Subject: unshare: Fix PDEATHSIG race for --kill-child X-Git-Tag: v2.38-rc1~63^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=764bb68af8e6d1b6c10a154c1dace64c450100c0;p=thirdparty%2Futil-linux.git unshare: Fix PDEATHSIG race for --kill-child Kill the child explicitly should the parent terminate just before the child invokes prctl(PR_SET_PDEATHSIG). The underlying issue can be reproduced as follows: #!/bin/bash rm -f /tmp/unshare.log.* strace -ff -tt -o /tmp/unshare.log /usr/bin/unshare --kill-child --fork true head -1 /tmp/unshare.log.* while : ; do PARENT=$( /usr/bin/unshare --kill-child --fork bash -c 'echo $PPID' & sleep 0 # sleep 0.00$RANDOM kill -9 $! 2>/dev/null ) [ "$PARENT" != 1 ] || { echo "$PARENT" ; break ; } done Signed-off-by: Earl Chew --- diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 58a5e180c8..2dbab9161a 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -763,7 +763,7 @@ int main(int argc, char *argv[]) const char *newroot = NULL; const char *newdir = NULL; pid_t pid_bind = 0, pid_idmap = 0; - pid_t pid = 0; + pid_t pid = 0, pid_parent = 0; int fd_idmap, fd_bind = -1; int status; unsigned long propagation = UNSHARE_PROPAGATION_DEFAULT; @@ -952,6 +952,7 @@ int main(int argc, char *argv[]) /* force child forking before mountspace binding * so pid_for_children is populated */ + pid_parent = getpid(); pid = fork(); switch(pid) { @@ -989,8 +990,17 @@ int main(int argc, char *argv[]) err(EXIT_FAILURE, _("child exit failed")); } - if (kill_child_signo != 0 && prctl(PR_SET_PDEATHSIG, kill_child_signo) < 0) - err(EXIT_FAILURE, "prctl failed"); + if (kill_child_signo != 0) { + if (prctl(PR_SET_PDEATHSIG, kill_child_signo) < 0) + err(EXIT_FAILURE, "prctl failed"); + + if (getppid() != pid_parent) { + if (kill(getpid(), kill_child_signo) != 0) + err(EXIT_FAILURE, _("child kill failed")); + /* The selected kill_child_signo be blocked, or + * might not cause termination. */ + } + } if (mapuser != (uid_t) -1 && !usermap) map_id(_PATH_PROC_UIDMAP, mapuser, real_euid);