β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3256

at_exit(procfs_exit) registration races on an unsynchronized vfc_refcount==1 gate: two concurrent procfs mounts can both skip registration, leaving every exited process's pfsnode unmarked (PFS_DEAD never set)

Summary

procfs_mount registers the global exit handler only when it observes mp->mnt_vfc->vfc_refcount == 1 (:73) and procfs_unmount deregisters on the symmetric ==1 (:109-110). vfc_refcount is a plain int incremented long before VFS_MOUNT runs and decremented only after VFS_UNMOUNT returns, under no lock shared between two different procfs mounts. Two concurrent mounts can both read refcount==2 (M2's increment lands in the wide window spanning flag setup and a potentially-blocking token acquire) and both skip at_exit(), so procfs_exit never runs while procfs is mounted - exited processes' pfsnodes keep a live pfs_pid (stale /proc/<exited-pid> entries). Assessed cosmetic/robustness only: every procfs op re-resolves the target via P_POSTEXIT-guarded pfs_pfind, and pfsnode dedup is pid-keyed - no memory-safety consequence demonstrated. Double-registration (the corrupting direction) is arithmetically impossible. Root (or usermount+owner). Fix: register unconditionally at VFS_SET module-init and drop the racy gate. [VERIFIED pass2: unsynchronized vfc_refcount gate confirmed statistical cosmetic; once-flag fix compiled]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3256 Β· 7 files
FileTypeDescriptionSize
README.md β€” 249 B ↓ raw
VERDICT.md β€” 1.1 KB ↓ raw
build.sh β€” 93 B view raw
fix.diff β€” 1.1 KB view raw
manifest.json β€” 438 B view raw
run.sh β€” 102 B view raw
verdict.json β€” 1.6 KB view raw

DF-3256 evidence pack

What

procfs at_exit registration races on the unsynchronized vfc_refcount==1 gate

Verdict

status=not_reproduced impact=none confidence=certain

See VERDICT.md for the full narrative and fix.diff for the verified fix.

VERDICT.md
↓ download raw

DF-3256 - verification verdict

status: not_reproduced | impact: none | confidence: certain | attempts: 0

Narrative

Race-mechanics-certain from source; live hit deliberately not attempted (statistical window between vfc_refcount++ at vfs_syscalls.c:359 and the read at procfs_vfsops.c:73, impact cosmetic - stale /proc entries only, all procfs ops re-resolve by pid). Two concurrent mounts can both observe refcount==2 and both skip at_exit(procfs_exit); the symmetric unmount gate is :109-110. Prior pack (untested) analysis re-confirmed this pass; fix registers the handler once (flag-guarded, never deregistered - procfs_exit is a no-op with no pfsnodes); compiled in the F40FIX build.

Fix validation

  • fix_status: compile_validated
  • fix.diff applied in the F40FIX verification kernel build (RC=0, zero -Werror errors); no runtime A/B for this item (line-certain hardening)

Kernel references

Reproduce

See the artifacts in this directory; run.log = stock-kernel baseline, run.fixed.log = F40FIX fixed-kernel A/B where one exists.

Fix verification

not_testable

fix.diff applied in the F40FIX verification kernel build (RC=0, zero -Werror errors); no runtime A/B for this item (line-certain hardening)

↓ fix.diffper-fix-DF-3256

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md with path:line citations; run.log where a live demo exists; fix.diff

PoC changes

n/a - statistical race, cosmetic impact

Verified recommended fix

register procfs_exit once via a registered flag; never deregister

Verdict

Race-mechanics-certain from source; live hit deliberately not attempted (statistical window between vfc_refcount++ at vfs_syscalls.c:359 and the read at procfs_vfsops.c:73, impact cosmetic - stale /proc entries only, all procfs ops re-resolve by pid). Two concurrent mounts can both observe refcount==2 and both skip at_exit(procfs_exit); the symmetric unmount gate is :109-110. Prior pack (untested) analysis re-confirmed this pass; fix registers the handler once (flag-guarded, never deregistered - procfs_exit is a no-op with no pfsnodes); compiled in the F40FIX build.