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

Use-after-free in detach: deferred ACPI notify callback runs on freed softc (AcpiOsWaitEventsComplete is a no-op in DragonFly)

Summary

acpi_fujitsu_notify_handler queues acpi_fujitsu_notify_status_changed(sc) via AcpiOsExecute to deferred LWKT helper thread (acpi_task_td). acpi_fujitsu_detach calls AcpiRemoveNotifyHandler which internally invokes AcpiOsWaitEventsComplete() to drain pending deferred work - but in DragonFlyBSD this function is empty no-op macro (acdragonfly.h:219-220 XXX TBI). After AcpiRemoveNotifyHandler returns queued LWKT message holding raw pointer to sc still pending. Detach frees sysctl context returns bus layer frees softc. When acpi_task_thread dequeues message calls acpi_fujitsu_notify_status_changed(sc) accessing sc->gsif sc->gvol sc->dev sc->handle all on freed memory. Additionally detach never takes ACPI_SERIAL_BEGIN(fujitsu) so serial lock does not synchronize. Systemic: affects every DragonFly ACPI driver using AcpiOsExecute + AcpiRemoveNotifyHandler (also DF-2307 gpio_acpi DF-2376 acpi_cmbat). [VERIFIED pass2: reproduced - deferred notify on freed plus sprayed 208-byte softc Fatal trap 12 at device_get_parent via canaried dev pointer; real no-drain UAF same family as DF-2376; OSL drain fix compile-validated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2381 Β· 8 files
FileTypeDescriptionSize
README.md β€” 1.1 KB ↓ raw
VERDICT.md β€” 1.6 KB ↓ raw
env.txt β€” 145 B view raw
fix.diff β€” 1.7 KB view raw
panic.txt β€” 343 B view raw
run.log β€” 530 B view raw
run.sh β€” 121 B view raw
verdict.json β€” 2.2 KB view raw

DF-2381 - fujitsu deferred notify on freed softc: KERNEL PANIC

Rig (ACHARNESS + ssdt_acsim FJS0, op=run_fufreed)

  1. blocker queued on the real acpi_task thread (30s tsleep)
  2. eval _SB.NFJ -> Notify(FJS0, 0x80); ACPICA queues notify-dispatch behind the blocker
  3. softc freed exactly as device_set_driver() at detach: kfree(0xfffff8008bb47d10 [208 bytes], M_BUS) + softc=NULL + 0x41 spray
  4. blocker times out -> dispatch -> acpi_fujitsu_notify_handler queues acpi_fujitsu_notify_status_changed(sc) -> acpi_fujitsu_update -> acpi_device_get_parent_softc(sc->dev) with sc->dev = 0x4141...

Result (panic.txt)

Fatal trap 12: page fault, fault virtual address = 0x28 Stopped at device_get_parent: movq 0x28(%rdi),%rax current process = Idle

Fix (fix.diff = real AcpiOsWaitEventsComplete drain in OsdSchedule.c)

AcpiRemoveNotifyHandler (acpi_fujitsu_detach) now drains queued tasks before the softc is freed. Compile-validated in the fixed ACHARNESS build; the rig choreography frees the softc directly (bypassing the AcpiRemoveNotifyHandler call site) so the rig cannot itself demonstrate the fix - the production detach path is what the fix protects.

VERDICT.md
↓ download raw

DF-2381 VERDICT

Status: reproduced (reproduced) Impact: panic Confidence: certain Attempts: 3

Deferred acpi_fujitsu_notify_status_changed ran on the freed+canary-sprayed softc and dereferenced sc->dev = 0x4141414141414141 - Fatal trap 12 at device_get_parent+0x0 (movq 0x28(%rdi),%rax, fault 0x28), current process Idle (acpi_task helper). Choreography (console-narrated): blocker on acpi_task; Notify(FJS0, 0x80) queues the dispatch behind it; softc freed (kfree M_BUS 208-byte zone) + 0x41-sprayed exactly as detach does; blocker timeout -> dispatch -> handler queues acpi_fujitsu_notify_status_changed(sc) -> acpi_fujitsu_update -> acpi_device_get_parent_softc(sc->dev) faults. Confirms AcpiOsWaitEventsComplete is a no-op (acdragonfly.h:219-220) and detach drains nothing.

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-2381

Confirmed kernel references

Detail

Exploit chain

firmware notify 0x80 + detach without drain -> deferred callback on freed softc -> wild pointer deref; with heap grooming the freed 208-byte chunk can carry attacker-chosen sc->dev/sc->handle consumed by device/AcpiEvaluateObject paths - memory-corruption primitive beyond the panic

Evidence (decisive lines)

panic.txt (Fatal trap 12, fault virtual address 0x28, Stopped at device_get_parent: movq 0x28(%rdi),%rax); run.log console narration (softc 0xfffff8008bb47d10 size 208 freed+canaried; blocker out at 30s)

PoC changes

blocker choreography op run_fufreed written for this batch

Verified recommended fix

see fix.diff

Verdict

Deferred acpi_fujitsu_notify_status_changed ran on the freed+canary-sprayed softc and dereferenced sc->dev = 0x4141414141414141 - Fatal trap 12 at device_get_parent+0x0 (movq 0x28(%rdi),%rax, fault 0x28), current process Idle (acpi_task helper). Choreography (console-narrated): blocker on acpi_task; Notify(FJS0, 0x80) queues the dispatch behind it; softc freed (kfree M_BUS 208-byte zone) + 0x41-sprayed exactly as detach does; blocker timeout -> dispatch -> handler queues acpi_fujitsu_notify_status_changed(sc) -> acpi_fujitsu_update -> acpi_device_get_parent_softc(sc->dev) faults. Confirms AcpiOsWaitEventsComplete is a no-op (acdragonfly.h:219-220) and detach drains nothing.