# DF-5074 — VERDICT

**Status: untested (by design) / impact: none / confidence: certain (code
structure verified in source and against newbus/kobj mechanics).**

## Why untested

The defect cannot be exercised on the audit guest — or on any stock
DragonFly system:

1. **Stock guest**: QEMU's DSDT contains no ACPI0003 device, so acpi_acad
   never attaches (`sysctl hw.acpi.acline` → `unknown oid`; see run.log).
   (That acad is bootable on this guest at all was proven for DF-5073 via an
   injected SSDT — but the teardown gap needs a *detach*, not an attach.)
2. **No teardown path exists.** The defect's harm requires the acad softc to
   be freed while the notify handler / ioctl hook / sysctl OID still
   reference it. Verified in source:
   - `acpi_acad.c:76-82` — methods table has NO `device_detach`;
   - `sys/kern/subr_bus.c:2139` + `sys/kern/subr_kobj.c:69-75` — missing
     method ⇒ `DEVICE_DETACH` returns ENXIO ⇒ `device_detach()` fails;
   - `sys/kern/subr_bus.c:901-902` — `devclass_delete_driver()` aborts on the
     first detach failure, so a modular `kldunload acpi` never reaches the
     softc free either;
   - guest confirms `acpi` is compiled into the kernel (`kldunload acpi` →
     "can't find file acpi", run.log), and no `devctl` utility exists on the
     guest anyway.
   Even with DF-5073's SSDT-injected AC adapter, `device_detach(acpi_acad0)`
   would simply return ENXIO and free nothing.

## What the defect actually is (pass-2 depth)

Same family as DF-5006 (acpi_cpu) but the mirror image:

- DF-5006: detach *succeeds* (bare `bus_generic_detach`) ⇒ softc freed ⇒
  handler/OIDs/sensordev dangle ⇒ UAF on `kldunload acpi` (modular builds).
- DF-5074 (this): detach *cannot succeed* ⇒ softc never freed ⇒ nothing
  dangles; instead the three global registrations
  (`acpi_acad.c:172,180-183,193-194`) are pinned forever and, on any machine
  with a real AC adapter, `kldunload acpi.ko` is permanently blocked by the
  acad device's ENXIO. Any future one-line "fix" that adds a bare
  `device_detach` returning 0 — the tempting minimal change — instantly
  converts this into the DF-5006-class UAF (AML `Notify(PWRS, 0x80)` →
  `acpi_acad_notify_handler` on freed `dev` → `device_get_softc` of freed
  memory → `AcpiOsExecute` over freed text after unload; sysctl reader →
  handler on freed softc via `oid_arg1 = &sc->status`).

Also noted (info-level, folded here): `AcpiInstallNotifyHandler`'s return
value is ignored at `acpi_acad.c:193`, and deferred
`AcpiOsExecute(OSL_NOTIFY_HANDLER, ...)` work (`acpi_acad.c:140,195`) has no
drain — moot while no teardown exists, relevant once `fix.diff` is applied
(`AcpiRemoveNotifyHandler` performs ACPICA-internal draining).

## Recommended fix

`fix.diff` — add `acpi_acad_detach` that removes the `ACPI_ALL_NOTIFY`
handler, deregisters `ACPIIO_ACAD_GET_STATUS`, and removes the unit-0
sysctl OID (now tracked in the softc). Not applied to `sys/`; not built
(untested — no triggerable path exists to validate against; the diff follows
the exact registration order reversed).

## Kernel references

- sys/dev/acpica/acpi_acad.c:76-82 (no device_detach in methods table)
- sys/dev/acpica/acpi_acad.c:172 (ioctl hook registered, never deregistered)
- sys/dev/acpica/acpi_acad.c:180-183 (sysctl OID pins &sc->status, never removed)
- sys/dev/acpica/acpi_acad.c:193-194 (notify handler context=dev, never removed)
- sys/dev/acpica/acpi_acad.c:140,195 (deferred AcpiOsExecute, no drain)
- sys/kern/subr_bus.c:2129-2153 (device_detach; fails on ENXIO)
- sys/kern/subr_bus.c:853-912 (devclass_delete_driver aborts on detach failure)
- sys/kern/subr_kobj.c:69-75 (kobj_error_method → ENXIO)

## 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.
