Date: Tue, 30 Sep 2025 14:01:48 +0000 From: bugzilla-noreply@freebsd.org To: bugs@FreeBSD.org Subject: [Bug 289917] PID leak in proc_id_reapmap Message-ID: <bug-289917-227@https.bugs.freebsd.org/bugzilla/>
index | next in thread | raw e-mail
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: bugs@FreeBSD.org Reporter: avg@FreeBSD.org 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.home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-289917-227>
