Unchecked AcpiEvaluateObject return causes NULL-pointer-dereference panic reachable from unprivileged user via CTLFLAG_ANYBODY sysctl
Summary
acpi_panasonic_sinf() and acpi_panasonic_hkey_event() call AcpiEvaluateObject() and immediately dereference result buffer pointer without checking ACPI status or testing pointer for NULL. When AcpiEvaluateObject fails (memory pressure AE_NO_MEMORY in ACPI_ALLOCATE_BUFFER kmalloc AML interpreter error missing/typed-wrong return object namespace teardown) ACPICA leaves ReturnBuffer->Pointer as caller-supplied NULL so res->Type dereferences NULL kernel panics. Four hotkey sysctls registered CTLFLAG_ANYBODY so any unprivileged local user can drive this path by reading hw.acpi.panasonic.lcd_brightness. Most realistic trigger: memory exhaustion via fork/allocation bomb forces AE_NO_MEMORY in ACPI buffer alloc. Impact: reliable full DoS system halt/reboot. [VERIFIED pass2: reproduced - unpriv maxx sysctl read with failing SINF evaluation panics at acpi_panasonic_sinf+0x5d on NULL res->Type test; fixed build returns -1, control read 128 unchanged]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2386 Β· 15 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.5 KB | β raw | |
| VERDICT.md | β | 5.2 KB | β raw | |
| run.sh | β | 240 B | view raw | |
| run.log | β | 409 B | view raw | |
| run_fixed.log | β | 523 B | view raw | |
| panic.txt | β | 2.3 KB | view raw | |
| serial.txt | β | 17.6 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 | β | 169 B | view raw | |
| build.log | β | 5.7 MB | β download | |
| fix.diff | β | 1.4 KB | view raw | |
| env.txt | β | 1.9 KB | view raw | |
| verdict.json | β | 5.3 KB | view raw |
DF-2386 β PoC evidence pack
Finding: Unchecked AcpiEvaluateObject return in acpi_panasonic_sinf()
(sys/dev/acpica/acpi_panasonic/acpi_panasonic.c:277-279) β NULL-pointer
dereference panic reachable from an unprivileged local user via the
CTLFLAG_ANYBODY sysctl hw.acpi.panasonic.lcd_brightness.
Rig
Verbatim-interposition kernel harness (same shape as the acpi_hp rig, DF-2383/DF-2384):
acpi_panasonic.ccompiled byte-identical into a custom INVARIANTS kernel (PANHARNESS=X86_64_GENERIC+device panasim; sha256-gated bybuild.sh:23e49741027f53dcedd05423f7c5eacd1be0dada1c46277dde0be6694b8d0912).pana_shim.c(build glue only)#define-renames the driver's ACPI externals topanasim_*; everything else β newbus probe/attach, the sysctl framework,ACPI_SERIAL_*locking,device_printfβ runs real.panasim.cfabricates the firmware side: the fakeacpi_panasonicchild is added to the REALacpi0, the real attach creates the realhw.acpi.panasonic.*sysctls, andpanasim_AcpiEvaluateObjectreplies for SINF/HINF/SSET with runtime-selectable behavior (including failure with the buffer left exactly as ACPICA leaves it βnsxfeval.c:536-600failure contract:Pointerstays NULL).
Build
sh build.sh # push rig + build/install PANHARNESS + reboot (baseline) sh build.sh fixed # additionally apply fix.diff to the driver, rebuild
Run
sh run.sh # baseline: expects panic in acpi_panasonic_sinf sh run.sh fixed # fixed: expects -1 returned, no panic
Baseline sequence: create fake device β unprivileged (maxx) sanity read
of hw.acpi.panasonic.lcd_brightness (sane SINF) β root arms
hw.panasim.sinf_mode=0 (SINF evaluation fails like
AE_NO_MEMORY) β maxx reads the sysctl again β kernel panic (fatal
trap, acpi_panasonic_sinf, fault va 0x0). panic.txt carries the
serial-console capture.
Expected result (baseline)
Fatal trap 12: page fault while in kernel mode at
acpi_panasonic_sinf+β¦ with fault virtual address = 0x0, triggered by
uid 1000's sysctl process. Fixed build: the same read returns -1,
guest stays up.
Note on reachability: the unprivileged sysctl read is real; the failure
of the SINF evaluation at that instant is the firmware/AML side β on
hardware it is caused by e.g. AE_NO_MEMORY under memory pressure or a
firmware anomaly. The rig deterministically produces exactly that
failure mode at the exact API boundary the driver consumes.
DF-2386 β PoC verdict
File: sys/dev/acpica/acpi_panasonic/acpi_panasonic.c (:277-279)
Verdict: REPRODUCED β deterministic kernel NULL-pointer-dereference
panic inside the verbatim acpi_panasonic_sinf(), triggered by an
unprivileged local user reading hw.acpi.panasonic.lcd_brightness,
when the SINF evaluation fails. The verified fix makes the panic
disappear and returns -1 instead (A/B validated).
Line-accurate confirmation
acpi_panasonic.c:275-276βbuf.Length = ACPI_ALLOCATE_BUFFER; buf.Pointer = NULL;β the caller initializes the pointer to NULL.acpi_panasonic.c:277βAcpiEvaluateObject(h, "SINF", NULL, &buf);β return status discarded.- ACPICA contract,
sys/contrib/dev/acpica/source/components/namespace/ nsxfeval.c:525-631: on EVERY failure path theReturnBufferis left as the caller initialized it β evaluation error βgoto CleanupReturnObjectwithReturnBufferuntouched (:530-566); no return object β onlyReturnBuffer->Length = 0is written,Pointerstays NULL (:541-545); buffer allocation failure insideAcpiUtInitializeBuffer(:580) also leavesPointerNULL. Sobuf.Pointer == NULLafter any failed SINF evaluation. acpi_panasonic.c:278-279βres = (ACPI_OBJECT *)buf.Pointer; if (res->Type == ACPI_TYPE_PACKAGE)β NULL deref.- Reach: the four hotkey sysctls are registered
CTLFLAG_ANYBODY(acpi_panasonic.c:171) under the realhw.acpitree β any local user reachesacpi_panasonic_sysctlβACPI_SERIAL_BEGINβhkey_lcd_brightnessβacpi_panasonic_sinfby a plainsysctl hw.acpi.panasonic.lcd_brightnessread.
Mechanical verification (verbatim-interposition rig)
Kernel PANHARNESS = stock INVARIANTS X86_64_GENERIC + device
panasim; the driver is compiled byte-identical
(sha256 23e49741...d0912, gated by build.sh) through pana_shim.c
build glue that renames only its ACPI externals to panasim_*
fakes; everything else (newbus, sysctl framework, ACPI_SERIAL locking)
runs real. The rig adds a real newbus child acpi_panasonic0 to the
real acpi0; the verbatim probe/attach run and create the real
hw.acpi.panasonic.* sysctls. panasim_AcpiEvaluateObject reproduces
the documented ACPICA failure contract exactly: returns AE_NO_MEMORY
leaving buf.Pointer NULL.
Baseline run (run.log, panic.txt):
- control: sane 9-element SINF β maxx (uid 1001) reads
hw.acpi.panasonic.lcd_brightness=128, RC=0 β unprivileged read works; - armed:
hw.panasim.sinf_mode=0(SINF evaluation fails); - trigger: maxx reads the sysctl again β kernel panic, full trap block captured:
Fatal user address access from kernel mode from sysctl at ffffffff80a8013d Fatal trap 12: page fault while in kernel mode fault virtual address = 0x0 fault code = supervisor read data, page not present current process = 1027 kernel: type 12 trap, code=0 Stopped at acpi_panasonic_sinf+0x5d: cmpl $0x4,(%rdi)
cmpl $0x4,(%rdi) is literally res->Type == ACPI_TYPE_PACKAGE
(ACPI_TYPE_PACKAGE == 4) with %rdi = res = NULL; the kernel itself
attributes the fault to the unprivileged sysctl process.
Reachability / privesc assessment (honest)
- Hardware precondition: the driver only attaches on Panasonic
MAT0019firmware (Let's note laptops); the unprivileged sysctl read is real but the fault additionally requires the SINF evaluation to fail at that moment β realisticallyAE_NO_MEMORYunder kernel memory pressure (the finding's fork/allocation-bomb scenario) or a firmware anomaly. The rig injects exactly that failure mode at the exact API boundary; the driver-side unchecked deref is proven 1/1 deterministic. - Impact: NULL-deref panic / reliable local DoS. No write primitive, no controllable corruption β nothing to pivot to uid=0; not a privesc. Severity Medium upheld (C:N/I:N/A:H from an unprivileged read surface on matching hardware).
Fix validation (A/B)
fix.diff (status check + res != NULL + index < Count guard +
guarded free + HINF/shutdown hunks shared with DF-2387/2590/2591):
- first iteration of the fix was itself caught by the rig: on the
failure path it reached
AcpiOsFree(NULL)β INVARIANTSpanic: trying to free NULL pointer(sys/kern/kern_slaballoc.c: 1407β even the realAcpiOsFree(NULL)would panic on INVARIANTS DragonFly). Amended withif (buf.Pointer != NULL)(the same idiom the driver itself uses at :420-421) β this is precisely why fix validation matters. - fixed kernel (#6): identical trigger sequence β maxx read returns
-1(UINT64 -1truncation), RC=0, guest stays up (run_fixed.log), repeated 2Γ.
Artifacts
run.log/run_fixed.log (script outputs), panic.txt (full trap
block + DDB stop), serial.txt (fixed-run serial), panasim.c /
panasim.h / pana_shim.c (rig), build.sh / run.sh,
build.log (nativekernel, full), 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_testableConfirmed kernel references
- 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
Detail
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 (decisive lines)
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
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.
Verified 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
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.
No comments yet.