Cook: security things in Linux v5.1
Cook: security things in Linux v5.1
Posted May 29, 2019 21:51 UTC (Wed) by rweikusat2 (subscriber, #117920)In reply to: Cook: security things in Linux v5.1 by Cyberax
Parent article: Cook: security things in Linux v5.1
Putting this in another way, processes with the given name which are started after listProcess returned and before the loop terminates will only be killed if they happen to reuse a pid which hasn't already been used in the loop.
Posted May 29, 2019 21:54 UTC (Wed)
by Cyberax (✭ supporter ✭, #52523)
[Link] (11 responses)
My code does exactly what the contract of pkill is: killing processes by name.
> Putting this in another way, processes with the given name which are started after listProcess returned and before the loop terminates will only be killed if they happen to reuse a pid which hasn't already been used in the loop.
Yet my code guarantees that any matching processes that existed before the pkill launch will be killed.
Posted May 29, 2019 23:50 UTC (Wed)
by ms-tg (subscriber, #89231)
[Link] (9 responses)
My understanding of the race condition being asked about:
2. a process with name: “foo” and pid: 42 is filtered by the lambda from that list
3. This process exits. A new process named “dont_kill_me” is started and received recycled pid 42
4. The pid fd for 42 is opened. It refers to dont_kill_me
5. This new process is killed
I’d be super interested in learning more about:
(a) does the pseudocode as presented actually avoid suffering from this race, and how?
(b) is there something offensive about asking about this?
Thanks!
Posted May 29, 2019 23:57 UTC (Wed)
by ms-tg (subscriber, #89231)
[Link] (1 responses)
Is that context correct? At least that’s the inference I made about the relevance of a parent process.
Posted May 30, 2019 12:55 UTC (Thu)
by rweikusat2 (subscriber, #117920)
[Link]
[verbal redundancies due to LWN blocking 'yes' as an answer ...]
Posted May 30, 2019 0:05 UTC (Thu)
by Cyberax (✭ supporter ✭, #52523)
[Link] (6 responses)
> (a) does the pseudocode as presented actually avoid suffering from this race, and how?
In this case the pid_open() call will return the handle to that incorrect process. However, this is fine because the next check for checkProcess() will fail and nothing is going to be killed.
If this check does succeed then there are two options:
> (b) is there something offensive about asking about this?
Posted May 30, 2019 9:36 UTC (Thu)
by moltonel (guest, #45207)
[Link]
Might as well not do the initial matching then ? Just go through the unfiltered process list, open /proc/<pid>, match using content of /proc/<pid>/, and kill if it matches ? I imagine performance cost of opening /proc/<pid> is dwarfed by the general cost of process matching ?
The commit message doesn't say clearly whether "the entire procfs directory remains visible or just one entry" when /proc/<pid> is opened (it says "same as happens right now" but I don't know what that is). I'm tempted to understand that the whole directory remains visible (otherwise the patch only barely reduces the RC window), but at the same time the message says that opening /proc/<pid> doesn't reserve the pid, so I wonder.
Posted May 30, 2019 12:07 UTC (Thu)
by rweikusat2 (subscriber, #117920)
[Link] (4 responses)
It's probably possible to prevent this somehow but at least, this wasn't mentioned so far.
Posted May 30, 2019 16:12 UTC (Thu)
by FLHerne (guest, #105373)
[Link] (3 responses)
Posted May 30, 2019 17:21 UTC (Thu)
by rweikusat2 (subscriber, #117920)
[Link] (2 responses)
Posted May 30, 2019 22:57 UTC (Thu)
by cyphar (subscriber, #110703)
[Link] (1 responses)
Also, pkill is a toy example. The real users of this syscall are more complicated systems which are sure that the pidfd is correct, and need to store it somewhere so they can detect the process dying properly (and send it signals if its not dead). Container runtimes and init systems are obvious contenders.
Posted May 31, 2019 17:28 UTC (Fri)
by rweikusat2 (subscriber, #117920)
[Link]
I also didn't come up with the pkill example, I made a general statement about pidfd open calls in absence of some guarantee that the process the pid originally referred to didn't terminate in the meantime. pkill was presentend as an example where one can claim that the race wouldn't matter in practice for more or less good reasons.
[*] Both the "process terminates and pid gets reused" and the "process starts to execute a different program" races could be avoided without any new system calls by sending a SIGSTOP to a process before checking its attributes, BTW.
Posted May 30, 2019 0:38 UTC (Thu)
by rweikusat2 (subscriber, #117920)
[Link]
Cook: security things in Linux v5.1
Because you're stupidly wrong?
This is true with ANY variant of pkill. A matching process can be started at the moment pkill exits and it'll be missed.
Cook: security things in Linux v5.1
1. listProcesses is called. Imagine it atomically returns a set of (name, pid) tuples alive at the time of the call
Cook: security things in Linux v5.1
Cook: security things in Linux v5.1
Cook: security things in Linux v5.1
Because rweikusat2 seems obsessed with insisting that the old Unix API is the only source of truth.
Yes. Imagine that one of the initially matched processes dies and is replaced by another process.
1) The new process also matches the target name and so it's OK to kill it (according to pkill's contract).
2) The new process has actually died in the time between the pid_open and checkProcess, and it's been replaced by a new process that matches the target. In this case the further pidfd_kill() call will be a no-op (since its target is dead), but this is still fine within the pkill's contract.
No.
Cook: security things in Linux v5.1
>
> In this case the pid_open() call will return the handle to that incorrect process. However, this is fine because the next check for checkProcess() will fail and nothing is going to be killed.
>
> If this check does succeed then there are two options:
> 1) The new process also matches the target name and so it's OK to kill it (according to pkill's contract).
> 2) The new process has actually died in the time between the pid_open and checkProcess, and it's been replaced by a new process that matches the target. In this case the further pidfd_kill() call will be a no-op (since its target is dead), but this is still fine within the pkill's contract.
Cook: security things in Linux v5.1
Cook: security things in Linux v5.1
Cook: security things in Linux v5.1
Cook: security things in Linux v5.1
Cook: security things in Linux v5.1
Cook: security things in Linux v5.1