# DF-5669 — VERDICT

**status: reproduced** (privileged local; impact ceiling: dos) —
**confidence: certain** for everything demonstrated below.

## What reproduced (guest-live, 4/4 deterministic runs)

Guest: DragonFly 6.5-DEVELOPMENT #0 (X86_64_GENERIC), QEMU i440FX,
`hw.acpi.supported_sleep_state: S3 S4 S5` (see env.txt).

1. **Unprivileged boundary holds** — `open("/dev/acpi", O_RDWR)` as uid 1001 →
   `Permission denied` (`run.unpriv.log`). Device is root:wheel 0644
   (`acpi.c:730`), FWRITE checked at `acpi.c:3424-3429`.
2. **The supported entry point is gated** — `ACPIIO_REQSLPSTATE` S3 as root →
   `errno 45 (Operation not supported)` (`run.reqstate.log`), exactly the
   platform gate at `sys/dev/acpica/acpi.c:2417-2420`.
3. **The deprecated ioctl bypasses the gate and lies.** `ACPIIO_SETSLPSTATE`
   S3/S4 as root → `ioctl() = 0, errno = 0` while `dmesg` gains
   `acpi0: warning: acpi_SetSleepState() deprecated...` +
   `acpi0: device_suspend failed` for **every** call (4 lines after 4 calls —
   run.log, dmesg.txt). So the kernel walked the whole device tree suspend
   path (with `bus_generic_suspend`'s inline partial RESUME of already-
   suspended siblings, `sys/kern/subr_bus.c:2894-2908`) and then returned
   **success** for an operation that (a) is not supported on this platform and
   (b) failed.

Root cause of the false success: in `acpi_EnterSleepState()`
(`sys/dev/acpica/acpi.c:2557`), `status` is set to `AE_OK` by
`AcpiGetSleepTypeData()` (`acpi.c:2597-2605`); the `DEVICE_SUSPEND != 0`
branch only prints and `break`s (`acpi.c:2624-2627`) without setting an
error, so `return_ACPI_STATUS(status)` (`acpi.c:2698`) yields AE_OK →
`error = 0` at `acpi.c:3455-3456`.

## What the deeper path would do (code-cited; blocked on this guest)

On this guest a driver deterministically vetoes `DEVICE_SUSPEND` (silent
error; identity not attributed), so the flow stops at stage 2 of 5
(`ACPI_SS_GPE_SET`). On suspend-clean hardware the same ioctl continues:

- `AcpiEnterSleepStatePrep(state)` — `_PTS` + SLP_TYP written to PM1 control
  (`acpi.c:2630-2636`);
- `acpi_sleep_machdep(sc, state)` — **no-op stub** on pc64
  (`sys/platform/pc64/acpica/acpi_wakeup.c:51-54`); its return value is
  ignored. On real FreeBSD this function *is* the actual sleep transition
  (wake APs, save CPU state, `AcpiEnterSleepState` from the trampoline);
  here nothing sleeps;
- `slp_state = ACPI_SS_SLEPT` unconditionally (`acpi.c:2653`);
- backout: `AcpiLeaveSleepState(state)` (PM1-control writes, WAKE_STATUS
  clears, `_WAK` — `sys/contrib/dev/acpica/source/components/hardware/
  hwsleep.c:408-479`) and `DEVICE_RESUME(root_bus)` (`acpi.c:2669-2673`) on a
  machine that never slept;
- ICU/ELCR/LAPIC state is never resynced after the phantom cycle:
  `icu_reinit()` (`sys/platform/pc64/icu/icu.c:128`) and `elcr_resume()`
  (`sys/platform/pc64/icu/elcr.c:121`) have **zero callers** (the latter is
  already tracked as DF-5654 — not re-reported here).

This is a full device-tree teardown/rebuild driven through an entry point the
platform explicitly declares unsupported — unvalidated on pc64 by design of
the stubs.

## Why not uid0 / not a panic

Not memory corruption — a control-flow/logic defect with a privileged-only
entry. No unprivileged route exists (proven). On this guest the driver veto
prevents the phantom stages, so no wedge/panic was observable; the impact
ceiling on capable hardware is a wedged/half-resumed system (privileged DoS).

## Fix

Route the deprecated ioctl through the same gate as the modern one
(fix.diff): `acpi_ReqSleepState(sc, state)` already implements the platform
policy (S5 allowed → poweroff; S1–S4 → EOPNOTSUPP; range → EINVAL). Also
worth a follow-up in `acpi_EnterSleepState()`: set `status = AE_ERROR` on the
`device_suspend failed` break so failures are never masked.

Fix validation: **not tested** — this is a Low-severity logic finding, not a
reproduced memory-corruption bug, so the single-fix kernel rebuild cycle was
not warranted per the audit contract. The diff is trivially reviewable
against `acpi.c:3451-3456`.

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