{
  "finding_id": "DF-5518",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "gpio_acpi_detach (gpio_acpi.c:486-497) performs no quiesce of in-flight gpio_acpi_space_handler dispatches: ACPICA runs non-default address-space handlers with the AML interpreter exited (evregion.c:392-401) and AcpiRemoveAddressSpaceHandler (evxfregn.c:290-418) unlinks the region, runs _REG and frees the HandlerObj (incl. its ContextMutex) without waiting for running handlers; device_detach then frees both softcs and the device_t objects (subr_bus.c:2150 -> :1943-1947) and the parent gpio_intel_detach releases the MMIO/IRQ resources and lockuninits the provider lock. A dispatched handler therefore keeps executing against freed state. Reproduced on the stock QEMU guest with a full planted-ACPI-table harness that brings the unmodified gpio_intel/gpio_acpi drivers up on a fake INT33FF controller (register image in the 0xD0000 option-ROM window) and drives ~19k GeneralPurposeIo field dispatches/s from TZ0._TMP. Deterministic trigger (gpo_race2.ko): hold the provider sc->lk so the next dispatch blocks mid-handler, detach (everything freed), release -> Fatal trap 12, Stopped at gpio_cherryview_read_pin+0x4c: cmpq $0,0x48(%rcx) (panic.txt). Lottery variant with a freely running hammer (8 attempts) did not hit naturally: the natural window is interpreter-handoff-bound and freed-but-unreused slab memory keeps working, the classic first-touch UAF lottery. Root-triggered (devctl-style detach / kldunload), race-dependent -> Low, same trigger profile as the known AEI-half findings DF-1094/DF-2307; this is the complementary OpRegion-handler half of the same missing-drain defect.",
  "exploit_chain": "planted RSDP/DSDT chain (kenv hint.acpi.0.rsdp=0x40000000 + QEMU loader blob, stock kernel) -> \\_SB.GPO0 (INT33FF, _UID 2, _CRS mem 0xD0000 irq 5) -> gpio_intel0+gpio_acpi0 attach -> OpRegion(GOPR, GeneralPurposeIo) + Connection(GpioIo, 59 pins) + FLD0,59 -> TZ0._TMP hammers field reads once gpoke.ko plants the register image (magic-gated; DBG0=0x55555555 proves exact pin values flow through the whole stack) -> gpo_race2.ko holds gpio_intel0 sc->lk so the next dispatch blocks inside gpioio_alloc_pins -> device_detach frees HandlerObj/softcs/device_t/resources -> LK_RELEASE resumes the blocked handler -> page fault in gpio_cherryview_read_pin on freed provider state -> DDB, guest dead.",
  "evidence": "panic.txt / run.race2.1.log: gpo_race2: detach returned 0; freeing lock followed by Fatal trap 12 ... fault virtual address = 0x48 ... Stopped at gpio_cherryview_read_pin+0x4c: cmpq $0,0x48(%rcx) -> db>, vm.sh status down. run.fixed.log + fix.diff: same rig on the fixed kernel with the hammer live (PRE-RACE delta=9543 dispatches/s, ARMED) -> no trap, guest up, detach-completion marker 0x600d0000 at 0xD6008 after the drain. VERDICT.md has the full narrative incl. the harness bring-up (why the register window must live at 0xD0000: ram0 reserves all SMAP RAM into nexus mem_rman and acpi_sysres_alloc never populates acpi_rman_mem).",
  "kernel_refs": [
    "sys/bus/gpio/gpio_acpi/gpio_acpi.c:486",
    "sys/bus/gpio/gpio_acpi/gpio_acpi.c:494",
    "sys/bus/gpio/gpio_acpi/gpio_acpi.c:217",
    "sys/contrib/dev/acpica/source/components/events/evregion.c:392",
    "sys/contrib/dev/acpica/source/components/events/evregion.c:449",
    "sys/contrib/dev/acpica/source/components/events/evregion.c:555",
    "sys/contrib/dev/acpica/source/components/events/evxfregn.c:290",
    "sys/kern/subr_bus.c:2150",
    "sys/kern/subr_bus.c:1943",
    "sys/bus/gpio/gpio_intel/gpio_intel.c:170"
  ],
  "poc_changes": "Built the whole firmware-ABI harness from scratch (no prior gpio-family rig existed: DF-1094 was source-confirmed only): iasl DSDT with GPO0/TZ0/_REG, RSDP-chain generator adapted from DF-5483, gpoke.ko register-image planter via PHYS_TO_DMAP, three race-trigger kmods (lottery/deterministic/fix-validation), AML debug window (DBG0/1/2) for dispatch-level observability. Key empirical discoveries: register window must be at 0xD0000 (not RAM: ram0/nexus reservation, nexus.c:663-680; not via PNP0C02: acpi_sysres_alloc early-returns), IRQ 5 not 10 (SCI), GPIOCFG=0 passes both RX and TX checks, and the hammer must be raced in its ~13s first _TMP window (afterwards the acpi_tz thread silences errors for hours).",
  "attempts": 12,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (stock) / #1: Tue Oct  6 19:53:21 UTC 2026 (fix-validation build)",
  "runtime_sec": 16200,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh (iasl on guest; python3 gen_gpio.py chain on host; gpoke/gpo_detach/gpo_race2/gpo_race3 kmods via bsd.kmod.mk on guest)",
  "run_cmd": "vm.sh down; QEMU_EXTRA=-device loader,file=gpio_chain.bin,addr=0x40000000,force-raw=on vm.sh up; kldload gpoke.ko; sleep until armed; kldload gpo_race2.ko (stock: panic) / gpo_race3.ko (fixed: clean)",
  "code_hash": "b375f69b73232918172d82c6af109dc9c27b71f3ce07c6055aaff4dee405c13e",
  "notes": "Natural-window lottery (freely running hammer + detach + poison spray) did not hit in 8 attempts: interpreter handoffs bound the last dispatch ahead of the removal critical section and DFs slab leaves freed chunks readable until reuse; the deterministic trigger (provider lock held across detach, handler blocked mid-dispatch) mirrors real contention (slow provider / preempted CPU) and panics reliably. Residual hazard noted for upstream: even with driver-side draining, AcpiRemoveAddressSpaceHandler frees the HandlerObj ContextMutex while a dispatch can hold it - a full fix needs ACPICA-side dispatch refcounting; ordering the drain BEFORE the remove (as in the final fix.diff) avoids it. Also observed: ksnprintf(_E%02X) truncation for pin>255 is safe (gpio_acpi.c:319-323 guards with pin<=255); /dev/mem at 0xD0000 was used only as an observability channel. 5 additional fix-validation boots on the patched kernel.",
  "recommended_fix": "Quiesce GPIO address-space dispatches in gpio_acpi_detach: refuse new dispatches via a detaching flag, drain in-flight ones (busy count + wakeup) BEFORE removing the address-space handler and before any teardown (fix.diff).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff applied to the guests /usr/src copy, kernel rebuilt (X86_64_GENERIC, RC=0) and installed. Baseline stock kernel + live hammer (9543 dispatches/s at trigger) + blocked in-flight handler -> Fatal trap 12 in gpio_cherryview_read_pin (panic.txt). Patched kernel, identical rig and trigger (gpo_race3.ko, fired while armed): no trap, guest stays up, detach completes only after the drain (completion marker 0x600d0000 written after device_detach returns 0). The previously-observed panic is gone.",
  "fix_evidence": "fix.diff; fix_build.log (kernel install RC=0); run.fixed.log (no Fatal trap, MARK=0x600d0000); panic.txt (baseline)"
}