Comment 33 for bug 2011806

Revision history for this message
In , Idarktemplar (idarktemplar) wrote :

SUMMARY
Since cgroup is created in kio after process startup, there is a race condition present if started process forks and starts some children before cgroup creation is processed.

Currently, situation sometimes, depending on various circumstances, may be following:
1. kio starts new process via KProcessRunner class.
2. Started process runs and forks, creating one or more children.
3. kio creates new cgroup and puts started process to this new cgroup. All children created by started process stay in current cgroup.

STEPS TO REPRODUCE
1. Try starting via KProcessRunner class applications which fork soon after launch.
Modern firefox, for example.
If application forks and parent exits, it's even better.

OBSERVED RESULT
Sometimes created cgroup would contain only parent process without any it's children. If parent process quits, it may result even into an empty cgroup. Children of launched process would be left in the cgroup of parent of launched process. Should not be reliably reproducible.

EXPECTED RESULT
Cgroup should contain both started process and all it's children reliably.

ADDITIONAL INFORMATION
I did not try reproducing it.

Currently, cgroup created when process is already running, and if this process creates some children fast, it may lead to described issue. Here's the link to code:

https://invent.kde.org/frameworks/kio/-/blob/8d6b306f585920230acecd19903325f6f0387b8e/src/gui/kprocessrunner.cpp#L226

Function 'registerCGroup()' is called in 'KProcessRunner::slotProcessStarted()' slot, which is invoked after process started, within some undetermined timeframe.

In my opinion, proper way to start process in new cgroup in order to fix this issue looks like following:
1. KProcessRunner forks.
2. Fork sets up cgroup, puts itself into it, waits until it's confirmed that OS finished moving it into new cgroup. Optionally between forking and setting up cgroup, it may exec into some helper which would setup cgroup.
3. Fork (or helper used to setup cgroup, if one is used) execs into the new process. Since it's already running in new cgroup before exec, when new process is started it's already contained in new cgroup, and even if first thing it does is fork() call, all children would be contained in that new cgroup as well, without any race conditions.

AFAIK, systemd-run actually setups cgroup and reliably puts requested process and all it's children into newly created cgroup, but I might be wrong. Not sure which interfaces are available from systemd via dbus or some library for starting process similarly to systemd-run.