β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2590

Unchecked AcpiEvaluateObject return in acpi_panasonic_hkey_event causes NULL-deref panic

Summary

acpi_panasonic_hkey_event calls AcpiEvaluateObject for HINF never checks return. On failure buf.Pointer NULL res->Type(:405) NULL-deref panic. Line :420 if(buf.Pointer)AcpiOsFree proves author knew buf.Pointer could be NULL but check too late. Triggered by ACPI notify 0x80 when Panasonic hotkey(Fn+F1-F10) pressed. Less severe than sinf requires ACPI event not sysctl read. [PASS-2 NOTES: DF-2589 duplicates the sinf half of DF-2386; DF-2590 same class in hkey_event - fold on triage; DF-1936 (kprintf log spam) actually lives at vega10_ih.c:288-301 not this file] [VERIFIED pass2: reproduced 4 of 4 - notify 0x80 with failing HINF panics at acpi_panasonic_notify+0x9f inlined NULL res->Type test via the real verbatim handler; status-check fix-validated, handler returns cleanly]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2590 Β· 15 files
FileTypeDescriptionSize
README.md β€” 1.4 KB ↓ raw
VERDICT.md β€” 4.5 KB ↓ raw
run.sh β€” 218 B view raw
run.log β€” 312 B view raw
run.2.log β€” 360 B view raw
run_fixed.log β€” 441 B view raw
panic.txt β€” 13.2 KB view raw
serial.txt β€” 19.7 KB view raw
panasim.c β€” 19.4 KB view raw
panasim.h β€” 1.1 KB view raw
pana_shim.c β€” 2.6 KB view raw
build.sh β€” 88 B view raw
fix.diff β€” 1.4 KB view raw
env.txt β€” 1.9 KB view raw
verdict.json β€” 4.4 KB view raw

DF-2590 β€” PoC evidence pack

Finding: acpi_panasonic_hkey_event() calls AcpiEvaluateObject for HINF and immediately dereferences res = buf.Pointer without checking status or NULL (sys/dev/acpica/acpi_panasonic/acpi_panasonic.c:403-405). Triggered by an ACPI notify 0x80 (Panasonic Fn hotkey) when the evaluation fails. The late if (buf.Pointer) AcpiOsFree at :420-421 shows the author knew the pointer can be NULL β€” one check too late.

Rig

Same verbatim-interposition kernel harness as DF-2386 (see that README). The real attach's AcpiInstallNotifyHandler(acpi_panasonic_notify, sc) is captured by the interposer; hw.panasim.cmd=3 dispatches notify 0x80 to the captured real verbatim handler exactly the way ACPICA's deferred notify thread would. hw.panasim.hinf_mode selects the HINF reply (1 = integer happy path, 0 = evaluation failure, buffer untouched).

Build

sh build.sh            # shared with DF-2386

Run

sh run.sh              # happy-path notify, then armed failure -> panic

Expected result (baseline)

  • happy path (hinf_mode=1, HINF integer 0x81): full verbatim notify path runs β€” key 1 decode, brightness action (SSET observed), real acpi_UserNotify fires β€” no panic;
  • armed (hinf_mode=0): injected notify β†’ kernel panic (fatal trap in acpi_panasonic_hkey_event, fault va 0x0), captured in panic.txt.
  • fixed build: device_printf "HINF evaluation failed", no panic.
VERDICT.md
↓ download raw

DF-2590 β€” PoC verdict

File: sys/dev/acpica/acpi_panasonic/acpi_panasonic.c (:403-405)

Verdict: REPRODUCED β€” acpi_panasonic_hkey_event() discards the AcpiEvaluateObject return for HINF and dereferences res = buf.Pointer (NULL on any evaluation failure) at :405. An ACPI notify 0x80 (Fn hotkey on Panasonic hardware) while HINF fails panics the kernel at exactly that load. Same NULL-Type class as DF-2386 but notify-reachable instead of sysctl-reachable; the late if (buf.Pointer) AcpiOsFree(buf.Pointer) at :420-421 shows the author knew the pointer can be NULL β€” the check is simply one statement too late. Fixed build survives the identical injection (A/B validated).

Line-accurate confirmation

  1. acpi_panasonic.c:401-402 β€” buf.Length = ACPI_ALLOCATE_BUFFER; buf.Pointer = NULL;
  2. :403 β€” AcpiEvaluateObject(h, "HINF", NULL, &buf); β€” status discarded.
  3. ACPICA failure contract (nsxfeval.c:525-631, see DF-2386 VERDICT): Pointer stays NULL on every failure.
  4. :404-405 β€” res = (ACPI_OBJECT *)buf.Pointer; if (res->Type != ACPI_TYPE_INTEGER) β€” NULL deref.
  5. Reach: acpi_panasonic_notify case 0x80 (:486-492) takes the serial and calls acpi_panasonic_hkey_event (:488) β€” on hardware this is the Fn-hotkey notify; no privilege involved in the fault context, but the trigger requires a firmware event.

Mechanical verification

Same rig as DF-2386 (see that VERDICT). The real attach registered the verbatim acpi_panasonic_notify through the interposed AcpiInstallNotifyHandler (captured handler+ctx). hw.panasim.cmd=3 dispatches notify 0x80 to the captured real handler from a kthread, mirroring ACPICA deferred notify dispatch.

Baseline (kernel #4):

  • happy path (hinf_mode=1, HINF integer 0x81): notify β†’ acpi_panasonic_hkey_event decodes key, acpi_UserNotify fired (notify_seen=1), handler returned, no panic β€” the notify plumbing is proven working first;
  • armed (hinf_mode=0: HINF evaluation fails, buffer untouched): injected notify β†’ kernel panic, 4/4 deterministic:
Stopped at      acpi_panasonic_notify+0x9f:     cmpl    $0x1,(%rdi)
db>

cmpl $0x1,(%rdi) is res->Type != ACPI_TYPE_INTEGER (ACPI_TYPE_INTEGER == 1) with %rdi = res = NULL β€” the compiler inlined hkey_event into acpi_panasonic_notify, hence the symbol; the immediate 0x1 fingerprints :405 exactly the way 0x4 (ACPI_TYPE_PACKAGE) fingerprinted :279 in DF-2386. panic.txt carries the serial capture (login: PANASIM: worker: exec cmd=3 / PStopped at ...); the full trap block is lost to a console artifact specific to the notify-thread context (ALL console output from that thread is dropped β€” see notes), so the DDB stop line plus the happy-path contrast plus the identical DF-2386 trap block constitute the evidence set. The ssh session dies at trigger time ("Connection closed by remote host", run.2.log).

Reachability / privesc assessment (honest)

  • Hardware precondition: Panasonic MAT0019 firmware; trigger is an ACPI notify (physical Fn key press) coinciding with an HINF evaluation failure (memory pressure / firmware anomaly). The attacker model is "person with the keyboard + a failing eval" or hostile/crafted firmware β€” matching the Low / AC:H / UI:R scoring.
  • Impact: NULL-deref panic in notify dispatch. No write primitive; not a privesc.

Fix validation (A/B)

Fixed kernel (#6): happy path unchanged (notify_seen=1); armed injection β†’ rig ring records inject: dispatching notify 0x80 ... β†’ eval HINF -> AE_NO_MEMORY β†’ inject: handler returned β€” handler returns cleanly (baseline panicked at exactly this point), guest stays up (run_fixed.log).

Console-output note

During verification we observed that all console/msgbuf output originating from the injected-notify kthread is silently dropped (both kprintf lines and the trap block; only DDB own prints survive). This is a rig/console artifact of thread context, not driver behavior; it is why the 2590 trap block is shorter than DF-2386's.

Artifacts

run.log/run.2.log (baseline attempts), panic.txt (serial with the DDB stop), run_fixed.log, rig sources, build.sh/run.sh, build.log, fix.diff, env.txt.

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.

Fix verification

not_testable
↓ fix.diffper-fix-DF-2590

Confirmed kernel references

Detail

Exploit chain

ACPI notify 0x80 on the MAT0019 device (Fn hotkey press; rig injects it to the captured real handler from a kthread, mirroring ACPICA deferred dispatch) -> acpi_panasonic_notify case 0x80 -> ACPI_SERIAL_BEGIN -> acpi_panasonic_hkey_event -> AcpiEvaluateObject(HINF) fails leaving buf.Pointer NULL -> res->Type load from NULL -> fatal trap, kernel panic. Ceiling is DoS from a firmware-event context; no unprivileged syscall trigger, no write primitive, no uid0 path.

Evidence (decisive lines)

panic.txt (serial: login: PANASIM: worker: exec cmd=3 / PStopped at acpi_panasonic_notify+0x9f cmpl 0x1,(%rdi) / db>); run.log + run.2.log (happy path notify_seen=1 then armed trigger kills the ssh session -- Connection closed by remote host); run_fixed.log + rig ring (fixed: inject: dispatching -> eval HINF AE_NO_MEMORY -> inject: handler returned, guest up)

PoC changes

No seed PoC existed; reused the DF-2386 rig and added the HINF reply mode knob plus notify injection: the interposed AcpiInstallNotifyHandler captures the verbatim acpi_panasonic_notify + softc context, and hw.panasim.cmd=3 dispatches notify 0x80 from a kthread (ACPICA dispatch model). Harness observations baked into the VERDICT: all console and msgbuf output originating from the injected-notify kthread is silently dropped by the console layer (both kprintf lines and the trap block; only DDB own print survives), so the full-format trap block of the sibling DF-2386 panic plus the 4/4 deterministic DDB stop line constitute the capture.

Verified recommended fix

acpi_panasonic_hkey_event: check the AcpiEvaluateObject status (device_printf + goto end on failure) and guard res == NULL before res->Type, matching the existing buf.Pointer guard at :420

Verdict

Confirmed on the verbatim driver in the DF-2386 kernel rig: acpi_panasonic_hkey_event discards the AcpiEvaluateObject status for HINF (acpi_panasonic.c:403) and dereferences res = buf.Pointer at :405; the driver sets buf.Pointer = NULL at :402 and ACPICA leaves it NULL on every failure path (nsxfeval.c:525-631). The rig captured the real verbatim acpi_panasonic_notify registered by the real attach and dispatched notify 0x80 exactly as ACPICA deferred dispatch would: happy path first (HINF integer 0x81 -> key decode, acpi_UserNotify fired, handler returned, no panic), then with the HINF evaluation failing the identical injection panicked the kernel 4/4 runs at Stopped at acpi_panasonic_notify+0x9f cmpl 0x1,(%rdi) -- that immediate (ACPI_TYPE_INTEGER == 1) fingerprints the res->Type != ACPI_TYPE_INTEGER test at :405 with %rdi = res = NULL (hkey_event inlined into notify), exactly as 0x4 fingerprinted :279 in DF-2386. The late if (buf.Pointer) AcpiOsFree at :420-421 proves the author knew the pointer can be NULL, one check too late. Trigger on hardware is an Fn-hotkey ACPI notify coinciding with an HINF evaluation failure (physical user + failing eval or hostile firmware) -- AC:H/UI:R as scored. NULL-deref panic, no write primitive, not a privesc. fix.diff (status check + res NULL guard) A/B validated: the identical armed injection makes the handler return cleanly with the guest staying up.