cam_periph_invalidate()'s underflow guard is dead code: `u_int32_t refcount < 0` never fires, so periph refcount underflows (DF-5273/DF-5327 classes) are silent
Summary
The CAM core's ONLY periph-refcount underflow detector compares unsigned < 0 - can never fire. Guest-verified: the DF-5273 burn drove a live cd periph to -5, invalidate ran on it, zero 'refcount < 0' warnings in dmesg - the underflowed periph silently became a permanent zombie. This dead guard is why the whole DF-5273/5327 corruption class shipped unnoticed. Signed-compare + release-underflow-trap fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5329 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.7 KB | β raw | |
| VERDICT.md | β | 1.8 KB | β raw | |
| poc_guard.c | β | 2.1 KB | view raw | |
| poc_ref.c | β | 2.6 KB | view raw | |
| poc_ref.out | β | 284 B | view raw | |
| fix.diff | β | 861 B | view raw | |
| verdict.json | β | 2.2 KB | view raw |
DF-5329 evidence pack β cam_periph_invalidate() underflow guard is dead code (u_int32_t refcount < 0 is always false)
Finding (one line)
cam_periph_invalidate() (sys/bus/cam/cam_periph.c:576-577) is the only
place the CAM core notices a periph refcount underflow, and its check
else if (periph->refcount < 0) can never be true because
struct cam_periph.refcount is u_int32_t (sys/bus/cam/cam_periph.h:123).
Every underflow of the class proven by DF-5273 / DF-5327 therefore sails
through silently as 0xFFFFFFxx: no warning, no assert β and the periph
becomes permanently unfreeable (zombie) or freeable at a wrapped-wrong
moment.
Reproduce (guest, root; evilcd2 kld loaded)
cd /root/df5327 cc -O -o poc_ref poc_ref.c # DF-5273 burn PoC (shared rig) timeout 45 usched :1 ./poc_ref /dev/cd1 sysctl -n debug.evilcd.refcnt # observe negative refcount sysctl -n debug.evilcd.invalidate=1 # run cam_periph_invalidate() on it dmesg | grep -c "refcount < 0" # expect 0 (guard never fires)
Expected (vulnerable kernel)
[poc] round 0 burn 0: ioctl rc=-1 errno=4(Interrupted system call) refcount=-1 [poc] round 0 burn 1: ioctl rc=-1 errno=4(Interrupted system call) refcount=-2 [poc] round 0 burn 2: ioctl rc=-1 errno=4(Interrupted system call) refcount=-3 ... sysctl refcnt -> -5 dmesg grep "refcount < 0" -> 0 <-- guard dead while rc < 0
Observed on guest (see poc_ref.out): refcount driven to -5 across runs,
cam_periph_invalidate() invoked (debug.evilcd.invalidate) with the count
negative, zero occurrences of the "cam_invalidate_periph: refcount < 0!!"
message. The only observability hook for this corruption class provably
never fires on the running kernel.
DF-5329 VERDICT
Status: REPRODUCED (the guard provably never fires)
What was reproduced
cam_periph_invalidate() (sys/bus/cam/cam_periph.c:576-577) contains
the CAM core's ONLY underflow detector:
else if (periph->refcount < 0)
kprintf("cam_invalidate_periph: refcount < 0!!\n");
refcount is u_int32_t (sys/bus/cam/cam_periph.h:123), so the
comparison is always false and the message can never print.
Guest proof (evilcd2 rig, cd periph; DF-5273's burn PoC drives the refcount negative):
[poc] round 0 burn 0: ... refcount=-1 [poc] round 0 burn 1: ... refcount=-2 [poc] round 0 burn 2: ... refcount=-3 sysctl debug.evilcd.refcnt -> -5 sysctl debug.evilcd.invalidate=1 # runs cam_periph_invalidate() dmesg | grep -c "refcount < 0" -> 0
With the count at 0xFFFFFFFB, cam_periph_invalidate() ran and printed
nothing; the periph became a silent zombie (not freed at 0, not
reported negative, permanently stuck until reboot). Repeated across two
guest sessions.
Impact
Observability/containment gap only (the underlying underflows are DF-5273/DF-5327's bugs). It converts a detect-and-warn condition into a silent integrity failure and removes the only diagnostic that would have surfaced this bug class in the field. Info severity.
Fix
fix.diff: signed comparison in the guard plus an underflow check (and
loud report, no release) in cam_periph_release()'s fast path so a
wrapped count cannot keep sinking. Validated by inspection only (Info
finding; no kernel rebuild spent).
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff authored (guard cast + release-side underflow trap); not kernel-validated -- Info severity, validation budget spent on DF-5327
fix.diff; code inspection
Confirmed kernel references
Detail
Evidence (decisive lines)
poc_ref.out (refcount -1 -> -3 lines), sysctl refcnt=-5, `dmesg | grep -c "refcount < 0" -> 0` after invalidate; README.md reproduce block
PoC changes
reused DF-5273's poc_ref burn unchanged; added poc_guard.c wrapper that also invokes invalidate and greps dmesg
Verified recommended fix
signed comparison in the guard plus an underflow check + loud report in cam_periph_release()'s fast path (fix.diff)
Verdict
cam_periph_invalidate()'s `else if (periph->refcount < 0)' is dead code (u_int32_t). Guest proof: DF-5273 burn drove the cd periph refcount to -5 (0xFFFFFFFB), cam_periph_invalidate() was invoked on it, and zero occurrences of the warning appeared in dmesg. The guard this audit relied on for detection never fires on a stock kernel.
No comments yet.