# DF-5074 — acpi_acad has no device_detach: ACPI notify handler, ioctl hook and hw.acpi.acline sysctl OID are never removed (resource pinning; DF-5006-family latent UAF)

## What

`acpi_acad.c` installs three persistent kernel-side registrations at attach
and provides **no `device_detach` method at all** (methods table:
`sys/dev/acpica/acpi_acad.c:76-82` — probe/attach only):

1. an `ACPI_ALL_NOTIFY` handler with `context = dev` for the life of the
   namespace (`acpi_acad.c:193-194`), never removed;
2. a global ioctl hook `ACPIIO_ACAD_GET_STATUS` with `arg = dev`
   (`acpi_acad.c:172`), never deregistered;
3. for unit 0, an `hw.acpi.acline` sysctl OID added to the *acpi bus* sysctl
   context whose `oid_arg1 = &sc->status` pins the acad softc
   (`acpi_acad.c:178-184`), never removed;

plus deferred `AcpiOsExecute(OSL_NOTIFY_HANDLER, ...)` callbacks
(`acpi_acad.c:140`, `:195`) that hold `dev` with no drain on any teardown
(the DF-2381 family problem: `AcpiOsWaitEventsComplete` is not implemented in
DragonFly's OSL).

## Why it is NOT a live UAF (unlike DF-5006) — verified mechanics

- A driver without `device_detach` fails `device_detach()` with ENXIO
  (`sys/kern/subr_bus.c:2139` `DEVICE_DETACH(dev)` dispatches to
  `kobj_error_method`, `sys/kern/subr_kobj.c:69-75`).
- `devclass_delete_driver()` — the only newbus path that frees driver-owned
  devices on module unload — **aborts on the first detach failure**
  (`sys/kern/subr_bus.c:901-902`).
- Therefore the acad softc can never be freed: every teardown path
  (`devctl delete`, `kldunload acpi.ko` on a modular build) fails before
  newbus frees anything. The dangling references never dangle in practice.

Contrast with DF-5006 (acpi_cpu): there `device_detach` *was* implemented as
`bus_generic_detach`, which returns 0, so newbus freed the softc while the
notify handler / sysctl OIDs / sensordev still referenced it → real UAF. In
acpi_acad the defect is the mirror image:

- modular `acpi.ko` **cannot be unloaded** on any machine that has an AC
  adapter (the acad device's detach failure aborts `devclass_delete_driver`);
- the notify handler, ioctl hook and sysctl OID are pinned forever (resource
  leak across hypothetical ACPI namespace teardowns);
- the driver is one trivial "add a bare detach returning 0" patch away from
  becoming the DF-5006-class UAF — the teardown bug is latent, not absent.

## Threat model

Root-only or boot-time-firmware configurations (kldunload by root, devctl by
root). No unprivileged trigger exists. Severity: Low / hardening.

## Fix

`fix.diff` adds a real `acpi_acad_detach`: removes the notify handler (ACPICA
drains notify work inside `AcpiRemoveNotifyHandler` — evxface.c:1276), then
deregisters the ioctl hook and removes the sysctl OID (stored in the softc).

## Files

* `README.md`, `VERDICT.md`, `run.log` (guest gate documentation), `env.txt`,
  `fix.diff`, `manifest.json`, `verdict.json`
