DF-3793 / verdict.json
{ "finding_id": "DF-3793", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "acpi_GetInteger() reads an uninitialized stack ACPI_OBJECT whenever an AML object evaluates successfully but returns no value: ACPICA leaves the caller buffer untouched (Length=0) and returns AE_OK, after which acpi.c:2177-2182 reads param.Type/param.Integer.Value from stale stack. Proven on the guest by evaluating a no-Return method of the live DSDT (\\_SB.PCI0.PRES._INI and \\_SB.CPUS.CTFY) with a poisoned caller buffer under debug.acpi.interpreter_slack=0: AE_OK with the poison intact, and acpi_GetIntegers outcome (AE_TYPE vs AE_OK+garbage) varying with stack history. Impact ceiling is limited: stale kernel stack data influences device-present/lid/thermal decisions and values exposed via sysctls (limited disclosure); no corruption, no unprivileged trigger on a stock system (firmware-driven).", "exploit_chain": "", "evidence": "run.log lines BUFFER UNTOUCHED, AE_OK (AE_OK + Length 0 + poison intact for both no-Return methods); acpi_GetInteger returning AE_TYPE (garbage Type) with slack off vs AE_OK/0 with slack on \u2014 same input, stack-history-dependent outcome. Source: sys/dev/acpica/acpi.c:2161-2204; ACPICA nsxfeval.c (!Info->ReturnObject -> ReturnBuffer->Length = 0, buffer untouched).", "kernel_refs": [ "sys/dev/acpica/acpi.c:2162", "sys/dev/acpica/acpi.c:2175", "sys/dev/acpica/acpi.c:2177", "sys/dev/acpica/acpi.c:2179", "sys/contrib/dev/acpica/source/components/namespace/nsxfeval.c:217" ], "poc_changes": "kmod written from scratch (no seed): probes live-DSDT no-Return methods with a poisoned caller buffer, plus stack-spray + real acpi_GetInteger call; needed opt_acpi.h/opt_global.h copied from /usr/obj kernel dir and the acpica Makefile.inc include paths.", "attempts": 4, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 900, "guest_dirty": 1, "build_cmd": "make (kmod; see build.sh)", "run_cmd": "kldload ./df3793.ko; dmesg | grep DF3793 (see run.sh)", "code_hash": "a37295b2727952b7abb28335eaab8810c22360985cf11c7af056b6cc1c039e8d", "notes": "Reached after discovering interpreter-slack implicit-return masks most no-Return methods with the default tunable; slack-off (supported config) makes every no-Return method a trigger. Patched-kernel validation: acpi_GetInteger then returns AE_AML_NO_RETURN_VALUE deterministically (run_patched.log).", "recommended_fix": "Zero-initialize param and map the AE_OK-with-no-object case to AE_AML_NO_RETURN_VALUE instead of reading the untouched buffer.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Patched kernel (fix.diff applied in guest /usr/src, nativekernel rebuild, reboot) turns the undefined outcome into a defined AE_AML_NO_RETURN_VALUE; no uninit-dependent behavior remains.", "fix_evidence": "run_patched.log: acpi_GetInteger -> AE_AML_NO_RETURN_VALUE for both no-Return paths on the patched kernel." } |