DF-2386 / verdict.json
{ "finding_id": "DF-2386", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Confirmed deterministically on the verbatim driver compiled byte-identical into a custom INVARIANTS kernel: acpi_panasonic_sinf discards the AcpiEvaluateObject status (acpi_panasonic.c:277) and dereferences res = buf.Pointer (set NULL by the driver itself at :276 and left NULL by every ACPICA failure path, nsxfeval.c:525-631) at :279 -- an unprivileged local user reading the CTLFLAG_ANYBODY sysctl hw.acpi.panasonic.lcd_brightness while the SINF evaluation fails panics the kernel: full trap block captured (fatal trap 12, fault va 0x0, Stopped at acpi_panasonic_sinf+0x5d cmpl 0x4,(%rdi) -- the ACPI_TYPE_PACKAGE comparison on NULL, attributed by the kernel to the sysctl process). Reach requires Panasonic MAT0019 firmware plus an SINF evaluation failure at read time (AE_NO_MEMORY under memory pressure or a firmware anomaly) -- the rig injects exactly that failure at the exact ACPICA boundary the driver consumes. Impact is a reliable NULL-deref panic / local DoS from an unprivileged read; no write primitive, not a privesc. fix.diff (status check + NULL/type/Count guards + guarded free) A/B validated: same trigger returns -1 with no panic. The first fix iteration was itself caught by the rig (it reached AcpiOsFree(NULL) and panicked via kern_slaballoc.c:1407 on INVARIANTS) and was amended to guard the free -- the idiom the driver itself uses at :420-421.", "exploit_chain": "uid 1001 maxx -> sysctl read of hw.acpi.panasonic.lcd_brightness (CTLFLAG_ANYBODY, acpi_panasonic.c:171) -> acpi_panasonic_sysctl -> ACPI_SERIAL_BEGIN -> hkey_lcd_brightness(HKEY_GET) -> acpi_panasonic_sinf(reg 0x04) -> AcpiEvaluateObject fails AE_NO_MEMORY leaving buf.Pointer NULL -> res->Type load from NULL -> fatal trap 12, kernel panic, system halt. Chain ceiling is DoS: the faulting access is a 4-byte read at address 0x0 with no attacker-controlled write, so no uid0 escalation exists for this class.", "evidence": "panic.txt (full trap block: fatal trap 12, fault virtual address 0x0, current process = the unprivileged sysctl, Stopped at acpi_panasonic_sinf+0x5d cmpl 0x4,(%rdi)); run.log (control read = 128 by maxx, then armed trigger); run_fixed.log (trigger returns -1, RC=0, guest alive); serial.txt; panasim.c/panasim.h/pana_shim.c (rig); build.log (nativekernel build); env.txt", "kernel_refs": [ "sys/dev/acpica/acpi_panasonic/acpi_panasonic.c:275-276", "sys/dev/acpica/acpi_panasonic/acpi_panasonic.c:277", "sys/dev/acpica/acpi_panasonic/acpi_panasonic.c:278-280", "sys/dev/acpica/acpi_panasonic/acpi_panasonic.c:171", "sys/dev/acpica/acpi_panasonic/acpi_panasonic.c:248-254", "sys/contrib/dev/acpica/source/components/namespace/nsxfeval.c:530-566", "sys/contrib/dev/acpica/source/components/namespace/nsxfeval.c:541-545", "sys/contrib/dev/acpica/source/components/namespace/nsxfeval.c:580", "sys/kern/kern_slaballoc.c:1407" ], "poc_changes": "No seed PoC existed. Built the verbatim-interposition kernel harness from scratch (same protocol as the acpi_hp rig DF-2383): pana_shim.c build glue renames the driver ACPI externals at the preprocessor level and includes the sha256-gated verbatim source; panasim.c fabricates the firmware world (SINF/HINF/SSET replies honoring the ACPICA failure contract, notify-handler capture, fake newbus child on the real acpi0 so the real sysctls appear under hw.acpi.panasonic). Iterations: (1) missing panasim.h prototypes tripped -Werror; (2) blanket-matching fake ACPI_ID_PROBE let the driver hijack an unrelated unit-0 ACPI child at boot -- fixed to match only the rig-created device; (3) first fix.diff iteration panicked in AcpiOsFree(NULL) on INVARIANTS -- amended with a NULL guard before the free.", "attempts": 4, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #4: Mon Oct 19 09:05:52 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/PANHARNESS x86_64", "runtime_sec": 8400, "guest_dirty": 0, "build_cmd": "sh build.sh # sha256-gated verbatim acpi_panasonic.c + rig -> make -j6 nativekernel KERNCONF=PANHARNESS -> installkernel -> reboot; sh build.sh fixed # applies fix.diff to the guest tree copy and rebuilds", "run_cmd": "sh run.sh baseline # create device, maxx control read (sane SINF), arm hw.panasim.sinf_mode=0 (evaluation fails), maxx re-reads -> panic; sh run.sh fixed # same sequence -> -1, no panic", "code_hash": "a70387113f982a4e39cc0daf840d67df623a06cdbcd64a5b48c1ab3aafd39ac7", "notes": "Guest has no Panasonic hardware; the rig supplies the firmware side at the exact API boundary the findings describe -- that boundary (what AcpiEvaluateObject returns on failure) is the trust boundary under test and was verified against the ACPICA source contract. DF-2589 duplicates the sinf half of this finding and DF-2590 is the same class in the notify path (per the pass-2 negative-evidence note for this file). Console note: output from the injected-notify kthread is dropped by the console layer (both kprintf and the trap block); the DF-2386 sysctl-context panic prints fully.", "recommended_fix": "acpi_panasonic_sinf: check AcpiEvaluateObject status, verify res != NULL and res->Type == ACPI_TYPE_PACKAGE and index < res->Package.Count before reading Elements[index], and free buf.Pointer only when non-NULL" } |