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

UAF: sysctl sensor read races kfree of sensor arrays in detach

Summary

aibs_detach calls sensordev_deinstall then immediately kfrees sc->sc_asens_{volt temp fan}. Per-sensor sysctl OIDs were created with arg1=sens (struct ksensor* into sc->sc_asens_*). sysctl framework SUPPOSED to drain in-flight handlers via oid_running loop at kern_sysctl.c:391-398 BUT oid_running NEVER incremented anywhere in kernel (grep confirms no write site). Additionally sysctl_find_oid walks OID tree lockless SLIST_FOREACH. Window: reader obtains raw oid pointer -> detach frees OID struct and sensor arrays -> reader dereferences freed oid->oid_lock and freed ks->desc via memcpy(us->desc ks->desc 32). Systemic framework issue affecting ALL sensor drivers freeing sensor storage in detach. Unprivileged user reads sensors world-readable racing root kldunload or VM host ACPI hot-unplug. [VERIFIED pass2: race not staged but framework claim verified - oid_running read-only kernel-wide so the kern_sysctl drain loop is dead code and detach kfrees sensor arrays under live oid arg1; functional-drain fix compile-validated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2396 Β· 7 files
FileTypeDescriptionSize
README.md β€” 788 B ↓ raw
VERDICT.md β€” 1.5 KB ↓ raw
env.txt β€” 145 B view raw
fix.diff β€” 728 B view raw
run.log β€” 802 B view raw
run.sh β€” 121 B view raw
verdict.json β€” 1.7 KB view raw

DF-2396 - sysctl sensor race vs detach: NOT staged (rig wedge)

Claim verification (source)

  • kern_sysctl.c:391-398: while (oidp->oid_running > 0) tsleep(...)
  • grep across sys/: oid_running is NEVER incremented - the drain is dead code; sysctl_root invokes oid->oid_handler with no running-marker.
  • aibs_detach (atk0110.c:267-275) kfrees sc_asens_* immediately after sensordev_deinstall while per-sensor oid arg1 pointers reference them.

Runtime

The race staging required a live aibs sensor device; the verbatim-attach interposition wedged the harness guest (DF-2395 pack), so no race window was actually exercised.

fix.diff (compile-validated): atomic oid_running++/-- + wakeup around

the handler invocation in sysctl_root, making the existing drain loop functional.

VERDICT.md
↓ download raw

DF-2396 VERDICT

Status: not_reproduced Impact: corruption Confidence: likely Attempts: 1

No runtime race was executed: the aibs verbatim attach (which creates the sensor sysctl OIDs) wedged the harness guest (see DF-2395 pack), so the reader-vs-detach race could not be staged. The framework claim verifies cleanly in source: oid_running is read in exactly one place (kern_sysctl.c:391-398 drain loop) and grep confirms NO increment site anywhere in the kernel - the drain loop can never observe oid_running>0, so sysctl_remove_oid frees oid+arg1 storage without waiting for in-flight handlers. The aibs-side precondition (sensordev_deinstall then immediate kfree of sc_asens_* at atk0110.c:267-275) is real. fix.diff (increment/decrement+wakeup around the handler call) compile-validated in the fixed build.

Kernel references

Guest

DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #7: Sat Oct 24 00:08:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/ACHARNESS x86_64

Fix validation

See fix.diff and README.md for the baseline/fixed A/B outputs (run.log / fixed.log).

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_testable
↓ fix.diffper-fix-DF-2396

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md source analysis (oid_running read-only); race not staged (rig wedge)

PoC changes

race staging depended on the aibs rig that wedged; framework analysis performed instead

Verified recommended fix

see fix.diff

Verdict

No runtime race was executed: the aibs verbatim attach (which creates the sensor sysctl OIDs) wedged the harness guest (see DF-2395 pack), so the reader-vs-detach race could not be staged. The framework claim verifies cleanly in source: oid_running is read in exactly one place (kern_sysctl.c:391-398 drain loop) and grep confirms NO increment site anywhere in the kernel - the drain loop can never observe oid_running>0, so sysctl_remove_oid frees oid+arg1 storage without waiting for in-flight handlers. The aibs-side precondition (sensordev_deinstall then immediate kfree of sc_asens_* at atk0110.c:267-275) is real. fix.diff (increment/decrement+wakeup around the handler call) compile-validated in the fixed build.