https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289917
Bug ID: 289917
Summary: PID leak in proc_id_reapmap
Product: Base System
Version: CURRENT
Hardware: Any
OS: Any
Status: New
Severity: Affects Many People
Priority: ---
Component: kern
Assignee: [email protected]
Reporter: [email protected]
I have an easy way to reproduce a PID leak in proc_id_reapmap using timeout(1)
command.
It does not require any elevated privileges, that is, it can be done as a
regular user.
The leak is readily reproducible using these versions of FreeBSD: 14.3,
stable/13, 13.5.
The leak is a bit harder to reproduce on main, stable/15, upcoming 15.0,
stable/14.
What I mean by a bit harder is that the leak is not reproducible in a default
installation, but if I take a copy of timeout(1) command from an affected
version (e.g., 14.3), then I can reproduce the leak using the command.
I conclude that the kernel allows for a resource leak via procctl(2).
In the affected versions, timeout(1) has some bug(s) which trigger the resource
leak.
In newer versions, timeout(1) is much better behaved but procctl(2) can still
be "exploited".
By filling proc_id_reapmap it's possible to create a situation where no new PID
could be allocated.
An attempt to do so would get stuck in an infinite loop in fork_findpid.
Subsequent attempts would be blocked on procid lock.
To reproduce the issue I use a small script that kills itself like this:
#!/bin/sh
sleep 0.0001 ; kill $$
Then I run the script under timeout(1) like this:
timeout 0.01 ./timeout-test.sh
Or in a loop for a more pronounced effect:
while true ; do timeout 0.01 ./timeout-test.sh ; done
proc_id_reapmap can be checked using a custom gdb function like:
define bitset_count
set $bitset = $arg0
set $bitcount = $arg1
set $c = 0
set $i = 0
while ($i < $bitcount)
set $n = $i / 64
set $b = $i % 64
if (($bitset[$n] & (1ul << $b)) != 0)
set $c = $c + 1
end
set $i = $i + 1
end
print $c
end
Example from a test on 14.3 (running the command just moments apart):
(kgdb) bitset_count proc_id_reapmap 100000
$1 = 23
(kgdb) bitset_count proc_id_reapmap 100000
$2 = 1485
According to my brief research the userland misbehavior of timeoout(1) was
fixed by the commit series to bin/timeout done on April 16 (2025) by bapt, with
most of those changes authored by Aaron LI.
--
You are receiving this mail because:
You are the assignee for the bug.