RB_SCAN concurrency contract overstates the machinery: deleting a node that is another concurrent scan's in-flight element is an unguarded use-after-free
| Field | Value |
|---|---|
| ID | DF-2988 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H |
| CWE | CWE-667 / CWE-670 |
| File | sys/kern/subr_rbtree.c |
| Lines | engine sys/sys/tree.h:302-306, 591-594, 708-712, 777-786 (shims subr_rbtree.c:44-60) |
| Area | kern |
| Confidence | likely |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | memcorrupt |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
tree.h:708-712 documents that 'Any item may be deleted while the scan
is in progress', and subr_rbtree.c:44-50 states RB_SCAN is designed to
run under shared locks. The inprog machinery actually delivers only a
narrower guarantee: (a) the scanning thread may delete its OWN current
element (info.node precomputed before the callback runs), and (b) any
node any scan holds as its pending next element is advanced by the
RB_REMOVE fixup. It does NOT protect a scan's current element (best)
against deletion by a DIFFERENT concurrent scanner: RB_SCAN_INFO
records only node, not cur, so RB_REMOVE cannot fix it up, and the
parked scanner dereferences the freed element inside its callback and
again at scancmp(best)/RB_NEXT(best). A future consumer that takes the
header at its word — two threads in RB_SCAN on the same head under a
shared lock, one callback freeing a node the other is processing — gets
a kernel UAF. No in-tree consumer exhibits the pattern today (all
deleting consumers serialize exclusively: pmap pm_spin, vmobj_token,
teardown paths) — an API trap / latent hazard, not a live exploit.
Unpriv users reach consumers (pmap, vm_object, pf/ipfw state trees),
but exploitation requires a consumer that follows the documented
contract rather than the actual one; today that means future code.
Fix: amend the contract + optionally add cur to RB_SCAN_INFO with an
INVARIANTS KKASSERT in RB_REMOVE (row diff).
Timeline
- 2026-09-02 Discovered during pass-2 audit of subr_rbtree.c (GLM 5.3). Engine core (rotations, transplant, rebalance, NULL-sibling cases) proven FreeBSD-identical/correct.
No comments yet.