shmfork() bcopy's transient shmmap_s reservation state: fork landing in shmat's blocked window permanently burns a SHMSEG slot in the child (and gives it an un-accounted, un-shmdt-able mapping)
| Field | Value |
|---|---|
| ID | DF-2858 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-362 (resource leak) |
| File | sys/kern/sysv_shm.c |
| Lines | 646-663 (reservation site :306-318) |
| Area | kern |
| Confidence | likely |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:kern |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
sys_shmat marks a shmmap_s slot reserved=1 for the duration of its blocking vm_map_find window; shmfork bcopy's the ENTIRE array including that transient state. The child's copy of reserved=1/shmid=β1 can never be cleared (only the parent's in-flight shmat clears its own array), permanently shrinking the child's usable shmseg slots by one per hit; if the fork lands after vm_map_find inserted the entry, the child's copied vm_map holds the mapping while its vm_shm entry stays shmid=β1 β shmdt/exit skip it (refcounting still balances via the map teardown, so a leak, not corruption). Unpriv fork-vs-shmat racing; per-process slot exhaustion + loss of SysV accounting. Fix: un-reserve inherited slots when copying in shmfork.
Timeline
- 2026-09-02 Discovered during pass-2 audit of sysv_shm.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2858 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| shmfork_race2.c | β | 3.0 KB | view raw | |
| shmfork_race.c (v1, detector artifact - kept for the record) | β | 2.9 KB | β download | |
| run.log | β | 1.1 KB | view raw | |
| v1_detector_artifact.log | β | 385 B | view raw | |
| fix.diff | β | 793 B | view raw |
Fix verification
not_testableFix (clear inherited reserved flags in shmfork) compile- and boot-validated; with the corrected detector the patched kernel shows the same zero-burn behavior as the stock kernel (the race itself was not reproducible, so no differential A/B exists).
df2858_final.log: 0 burns on patched kernel (3000 forks)
Confirmed kernel references
Detail
Exploit chain
(intended) fork inside sys_shmat reservation window -> child inherits reserved=1/shmid=-1 -> permanently unusable slot - NOT OBSERVED in 10,000 forks with corrected detector
Evidence (decisive lines)
shmfork_race2.c (corrected detector); df2858_final.log: 0 burns stock (3000 + 4000 under pressure), 0 burns patched (3000)
PoC changes
v1 detector miscounted normal single-attachment inheritance as slot loss; v2 adds fixed-address attach + mincore inheritance probe
Verified recommended fix
--- sys/kern/sysv_shm.c 2026-06-29 12:51:19.000000000 +0000
Verdict
DOWNGRADED to not_reproduced after the PoCs own detector was proven wrong - an important negative result. The code gap is real and line-accurate: sys_shmat marks a shmmap_s slot reserved=1 across its blocking window (sys/kern/sysv_shm.c:312-322), shmfork bcopys the entire array including that transient state (:656), and nothing ever clears the childs copy; the original PoC appeared to reproduce at a 90% rate (3622/4000 children at reduced capacity) but that detector counted capacity < shmseg as slot loss while the parents attacher thread legitimately holds one attachment at fork time. A corrected detector (parent attaches at a FIXED address; child counts capacity AND probes whether the fixed address is mapped; burn = reduced capacity with NO inherited mapping) produced ZERO burns in 10,000 forks on the stock kernel, with and without memory pressure (which would widen the vm_map_find window). The shm_token serialization evidently keeps forks out of the reservation window under tested conditions. The fix (clear inherited reserved flags in shmfork) is correct, compile- and boot-validated, and the patched kernel shows the same zero-burn behavior with no regression.
No comments yet.