Hello all! I'm about to write quite a long-ish email, but I
provide a small summary first for the "busy". :)
== Quick summary
The context is simple:
* the developer wants to write a C application (call it a
"controller") that spawns other child processes, which in their turn
spawn other processes and so on;
* some of these spawned processes might double fork (i.e. they daemonize);
* these child processes are not written by the developer in
question; (thus we can't "fix" them...)
* the controller will run with no special privileges (i.e.
non-root, no capabilities, etc.);
* (for purely practical reasons, thus let's not start a flame war)
we can assume a Linux-only environment, thus portability is not an
issue; (the developer is also not scared in applying patches to the
kernel...)
The problem I try to find a solution to is again quite simple, how
can the developer write the "controller" application such that the
following happens:
(A) any orphaned child of a sub-process (i.e. double forking ones,
ones whose parent has exited, etc.) are reparented to the controller;
(this is already solved in 3.4;)
(B) the controller should be able to kill all its subprocesses
(and their subprocesses, recursively);
(C) if the controller dies (segfault, killed, etc.) all its
subprocesses are terminated (and recursively so);
Thus, what "magic" :) should one invoke to obtain the above?
== Use cases
To better put the problem into a context, the previous features
would allow one to implement something like:
* "personal" service control systems (like `systemd`, `runit`,
`daemon-tools`, etc.);
* constrain badly written `sh` scripts that if terminated leak
processes; or build systems (like `make`), or SSH sessions, or cron
jobs, etc.;
* a building block in a PaaS underlaying;
But certainly NOT for "security" purposes...
== Existing primitives
I've really tried thinking about this for the last year or so, and
I've not managed to get a "good" enough solution... But I've found the
following partial solutions, but all of them have issues...
(1) `clone (CLONE_NEWPID)` -> solves all the problems, but has
major drawbacks:
* it requires special rights (root or capability);
* it creates an alternative process namespace thus will confuse
the hell out of scripts assuming PID equivalence...
(2) `prctl (PR_SET_CHILD_SUBREAPER)` -> solves the issue (A)
(reparenting), but that's it.
(3) `prctl (PR_SET_PDEATHSIG)` -> solves the issue (C) (forced
termination), but it has the following issues:
* it works only for the first level of sub-processes, as it must
be explicitly set after each `fork`;
* thus it is not "inheritable" by new children;
* it doesn't work for `setuid` processes (due to possible security issue);
(4) `killpg (group)` -> solves the issue (B), but:
* any child could choose to change its process group;
* if the controller uses its own group it kills itself;
Have I missed something?
== Brainstorming
It would have been nice if either of the following would happen
(in order of preference):
(a) maybe an additional `PR_SET_CHILD_SUBREAPER`-like flag that
would make the controller process really behave like a sub-init, that
is on its termination terminate all its children recursively;
(b) `PR_SET_PDEATHSIG` would be inheritable at least for non
`setuid` processes; (maybe even better if the signal is `SIGKILL` keep
it even for `setuid` processes as I don't see too much harm there...)
(c) have some way to send a signal to all a process children;
(d) (last resort solution we have today) iterate through
`/proc/$PID` and find all the controller children, SIGKILL them, and
continue until no process is found, then die; but it doesn't solve
(C)...
Something else?
Hope I find some solution to this... (If this is not the mailing
list to send it to, please point me in the right direction.)
Thanks in advance for feedback,
Ciprian.
_______________________________________________
Kernelnewbies mailing list
[email protected]
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies