DF-5527 / verdict.json
{ "finding_id": "DF-5527", "status": "reproduced", "reproduced": true, "impact": "dos", "confidence": "certain", "verdict": "gpio_cherryview_unmap_intr (gpio_cherryview.c:380-414) destroys the pin_intr_map and restores pad config but never clears the community interrupt MASK bit; GPIO_FREE_INTR without a preceding GPIO_TEARDOWN_INTR leaves the IRQ line armed with no mapping. Reproduced live on the DF-5518 planted-ACPI rig with the stock kernel: after ALLOC->SETUP->FREE (no teardown) the MASK bit for the unmapped line stays set (MASK=0x20, intrmaps[5].pin=-1), while the documented teardown->free order clears it; /dev/mem cross-check confirms. On real hardware a level-asserted pad then drives gpio_cherryview_intr into the is_level==0 edge-clear path in a tight re-asserting loop = interrupt storm / hard lockup (storm argued from ISR logic; QEMU cannot inject ISA IRQ 5 to fire it end-to-end). Latent today (only in-tree free path, gpio_acpi_unmap_aei, teardowns first) -> Info severity, defense-in-depth. fix.diff (mask+IS clear in unmap_intr) validated on a rebuilt kernel: same harness flips armed-with-no-mapping from 1 to 0.", "exploit_chain": "", "evidence": "run.log: gpiofree[A-free]: IS=00000020 MASK=00000020 (bit5=1) map5{pin=-1,intidx=-1} on stock kernel (line armed, mapping destroyed) vs run.fixed.log: gpiofree[A-free]: MASK=00000000 (bit5=0) map5{pin=-1} with fix.diff; SUMMARY lines line5 armed-with-no-mapping=1 (stock) vs =0 (patched); /dev/mem @0xD0380: 0x20 (stock) vs 0x0 (patched); fix_build.log full untrimmed kernel build RC=0", "kernel_refs": [ "sys/bus/gpio/gpio_intel/gpio_cherryview.c:380", "sys/bus/gpio/gpio_intel/gpio_cherryview.c:393", "sys/bus/gpio/gpio_intel/gpio_cherryview.c:395", "sys/bus/gpio/gpio_intel/gpio_cherryview.c:221", "sys/bus/gpio/gpio_intel/gpio_cherryview.c:425", "sys/bus/gpio/gpio_intel/gpio_cherryview.c:441", "sys/bus/gpio/gpio_intel/gpio_intel.c:250", "sys/bus/gpio/gpio_acpi/gpio_acpi.c:450" ], "poc_changes": "No seed PoC existed; harness written from scratch: gpiofree.c kmod drives the gpio_if methods directly on the live gpio_intel0 (A/B: free-without-teardown vs documented order), plants two pads (INTSEL lines 5/6) in the DF-5518 RAM register image, dumps IS/MASK/intrmaps from kernel space and cross-checks via /dev/mem.", "attempts": 2, "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 (baseline); fixed run #1: Tue Oct 6 23:06:02 UTC 2026", "runtime_sec": 1500, "guest_dirty": 0, "build_cmd": "sh build.sh (scp gpiofree.c+gpio_intel_var.h to guest; make in /tmp/gf5527 -> gpiofree.ko)", "run_cmd": "sh run.sh (boot DF-5518 rig chain; kldload /root/df5527/gpiofree.ko; dmesg | grep gpiofree; dd /dev/mem @0xD0380)", "code_hash": "8fd07fdbfd080bdc0845780285591c61fe003cdba2383f19e52eec90b9576a11", "notes": "QEMU cannot inject ISA IRQ 5, so the interrupt storm itself is argued from gpio_cherryview_intr:221-235 on top of the reproduced armed-line state. Latent in-tree (gpio_acpi_unmap_aei always teardowns first). Secondary hardening note folded here: unmap also zeroes intidx/is_level, so a stale cookie passed to enable/disable would hit 1U<<-1 UB guarded only by INVARIANTS-only KKASSERT (sys/sys/systm.h:80-119).", "recommended_fix": "In gpio_cherryview_unmap_intr, capture map->intidx before destroying the mapping and clear the CHV_GPIO_REG_MASK bit plus W1C the CHV_GPIO_REG_IS bit for that line (see fix.diff).", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applied to guest /usr/src (patch -p1, 2/2 hunks), kernel rebuilt with make -j6 nativekernel KERNCONF=X86_64_GENERIC (RC=0, fix_build.log), rig rebooted, identical harness re-run: A-free MASK bit5=0 with map5{pin=-1}, SUMMARY armed-with-no-mapping=0, /dev/mem @0xD0380=0x00000000. Baseline had 1/0x20. Only variable between runs = fix.diff.", "fix_evidence": "run.log vs run.fixed.log decisive lines: A-free: MASK=00000020 (bit5=1) -> A-free: MASK=00000000 (bit5=0); SUMMARY line5 armed-with-no-mapping=1 -> =0; fix_build.log tail: Kernel install for X86_64_GENERIC completed; kern.version #1: Tue Oct 6 23:06:02 UTC 2026" } |