Page MenuHomeFreeBSD

proc: Copy the p_reapsubtree field explicitly during fork
ClosedPublic

Authored by markj on Jul 27 2026, 6:29 PM.
Tags
None
Referenced Files
Unknown Object (File)
Fri, Sep 4, 2:34 AM
Unknown Object (File)
Tue, Sep 1, 11:32 AM
Unknown Object (File)
Sat, Aug 29, 9:08 PM
Unknown Object (File)
Sat, Aug 29, 9:04 PM
Unknown Object (File)
Fri, Aug 28, 5:30 AM
Unknown Object (File)
Thu, Aug 27, 11:25 PM
Unknown Object (File)
Thu, Aug 27, 8:56 AM
Unknown Object (File)
Mon, Aug 17, 10:46 PM
Subscribers

Details

Summary

p_reapsubtree lives in the p_startcopy/p_endcopy block of struct proc,
which is copied during fork without any synchronization. However, the
field is not stable except when the proctree lock is held, and indeed
may change if p1's reaper exits or explicitly releases its reaper
status. This state change can race with fork() and leave the child with
an incorrect p_reapsubtree field.

Close the race: explicitly copy the field under the proctree lock during
fork.

Reported by: syzkaller

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 75174
Build 72057: arc lint + arc unit

Event Timeline

markj requested review of this revision.Jul 27 2026, 6:29 PM

I am curious what was the panic (?).

This revision is now accepted and ready to land.Jul 27 2026, 6:41 PM
In D58482#1341859, @kib wrote:

I am curious what was the panic (?).

They all have this form:

panic: bit 1868 not set in 3

cpuid = 1
time = 13
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0xc6/frame 0xfffffe0056e88470
kdb_backtrace() at kdb_backtrace+0xd0/frame 0xfffffe0056e885d0
vpanic() at vpanic+0x257/frame 0xfffffe0056e88790
panic() at panic+0xb5/frame 0xfffffe0056e88850
proc_id_clear() at proc_id_clear+0x113/frame 0xfffffe0056e88890
proc_reap() at proc_reap+0x597/frame 0xfffffe0056e888f0
proc_to_reap() at proc_to_reap+0x675/frame 0xfffffe0056e88950
kern_wait6() at kern_wait6+0x35e/frame 0xfffffe0056e88a10
sys_wait4() at sys_wait4+0x1c4/frame 0xfffffe0056e88d10
amd64_syscall() at amd64_syscall+0x4e2/frame 0xfffffe0056e88f30
fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe0056e88f30
--- syscall (7, FreeBSD ELF64, wait4), rip = 0x10610aefb6ea, rsp = 0x1061058e8c88, rbp = 0x1061058e8cf0 ---

It took a long time for it to find a reproducer. The reproducer is a program which runs the following three syscalls in parallel, from different threads:

procctl$PROC_REAP_ACQUIRE(0x0, 0x0, 0x2, 0x0) (async)
procctl$PROC_REAP_KILL(0x0, 0x0, 0x6, 0x0)
pdfork(0x0, 0x2) (async, rerun: 32)

I can send you the C reproducer if you like.

sys/kern/kern_fork.c
708

Really, p_reapsubtree does not belong in the startcopy/endcopy block, but I prefer to commit this change first to make MFCs easier.

I can send you the C reproducer if you like.

I think Peter would take it for stress2.