7

From this answer we have learned that you can implement reliable killing of entire process subtrees with Linux PID namespaces via unshare -p.

Here is problem with it that I don't understand:

  • It only works when I use the -f/--fork option to unshare.

    unshare -fp -- bash -c "watch /bin/sleep 10000 && echo hi"
    

    When I run this, and kill -9 the PID of that bash, then watch, sleep etc are all dead, as I desire.

  • But when I use it without -f:

    unshare -p -- bash -c "watch /bin/sleep 10000 && echo hi"
    

    and kill -9 the bash PID, then the watch gets reparented to PID 1 (on my Ubuntu that's systemd), so I don't have the desired effect of killing all children.

Questions:

  • Why is --fork necessary to get the desired effect? Why is unshare using exec() without fork not enough?
  • Is there a workaround for this? I would prefer if I could conveniently send kill -9 to the PID created by starting unshare to kill everything below it. But when I use --fork, killing the pid returned when I started unshare will, well, simply kill unshare and have bash reparented to PID 1, because unshare is not in my PID namespace.

Note, the && echo hi is needed because if you give only one command to bash -c, it will exec() it and thus the bash process is gone (replaced) and you can't kill its PID.

1
  • 1
    Hmm, this answer suggests that the effects of -n (unshare(CLONE_NEWPID)) only come into acction for the first child process forked. I think that would explain my first question, but the question about what the best workaround is still stands.
    – nh2
    Sep 19, 2017 at 15:19

1 Answer 1

7

As described in this helpful answer the effects of -n (unshare(CLONE_NEWPID)) only come into acction for the first child process forked.

In particular, man 2 unshare says says about CLONE_NEWPID:

Unshare the PID namespace, so that the calling process has a new PID namespace for its children which is not shared with any previously existing process.

The calling process is not moved into the new namespace.

The first child created by the calling process will have the process ID 1 and will assume the role of init(1) in the new namespace.


Patching unshare to make killing work reliably

Since asking my question, in the last couple hours I've written a patch to util-linux (pull request here) that adds a --kill-child flag to unshare.

Edit: This is now merged and released as part of util-linux v2.32.

You can use it like this:

unshare -fp --kill-child -- bash -c "watch /bin/sleep 10000 && echo hi"

and killing unshare will tear the entire process tree down as expeted.

Without root

You can even use it without root privileges if your kernel has user namespaces enabled (CONFIG_USER_NS=y) by passing the -U flag:

unshare -Ufp --kill-child -- bash -c "watch /bin/sleep 10000 && echo hi"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .