Kernel heap address leak via incomplete pointer fix-up in ACPIIO_DO_MCALL Package results
Summary
acpi_call_fixup_pointers() only rewrites top-level String.Pointer/Buffer.Pointer when translating ACPICA result buffer for copyout. Does not handle ACPI_TYPE_PACKAGE nor recurse into nested Package elements. When ACPI method invoked via ACPIIO_DO_MCALL returns a Package (_BIF _BIX _PSL _PSS _CST _PCT) entire result buffer copyout()d with every internal pointer (Package.Elements nested Package.Elements nested String.Pointer nested Buffer.Pointer) left as raw kernel virtual addresses defeating KASLR/leaking kernel heap layout. ACPICA allocates single buffer whose internal pointers reference locations within same buffer. For Package with N elements user receives N+1 raw kernel heap addresses. Requires FWRITE on /dev/acpi (root) + debug.acpi.allow_method_calls=1 (boot-only loader tunable default 0). [VERIFIED pass2: reproduced on STOCK kernel via ACPIIO_DO_MCALL - Package method copyouts 7 plus raw kernel heap pointers per run 3 of 3; root plus FWRITE plus tunable gated so no unpriv reach; recursive pointer-scrub fix compile-validated]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2373 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 912 B | β raw | |
| VERDICT.md | β | 1.3 KB | β raw | |
| env.txt | β | 145 B | view raw | |
| fix.diff | β | 686 B | view raw | |
| reach.log | β | 564 B | view raw | |
| run.sh | β | 121 B | view raw | |
| verdict.json | β | 1.7 KB | view raw |
DF-2373 - ACPIIO_DO_MCALL leaks kernel heap pointers for Package results
acpi_call_fixup_pointers (acpi.c:3391-3401) only rewrites top-level String.Pointer/Buffer.Pointer. A Package result (e.g. _SB.PCI0._PRT from the stock QEMU DSDT) is copyout()d with Package.Elements and every nested sub-package Elements left as raw kernel virtual addresses.
Reproduce (STOCK kernel)
- echo "debug.acpi.allow_method_calls=1" >> /boot/loader.conf ; reboot
- cc -O -o mcall_leak mcall_leak.c -I/usr/src/sys/contrib/dev/acpica/source/include \ -I/usr/src/sys/contrib/dev/acpica/source/include/platform -I/usr/src/sys
- ./mcall_leak '_SB.PCI0._PRT' (root)
Expected (3/3 runs, see run.log): LEAKED-KERNEL-POINTERS: 7, e.g. Package.Elements = 0xfffff80118684018.
Reachability: /dev/acpi is 0644, but ACPIIO_DO_MCALL is a core ioctl behind the FWRITE gate - an unprivileged O_RDONLY fd gets EPERM (reach.log).
DF-2373 VERDICT
Status: reproduced (reproduced) Impact: leak Confidence: certain Attempts: 3
Stock X86_64_GENERIC kernel with debug.acpi.allow_method_calls=1: ACPIIO_DO_MCALL on a Package-returning method hands the caller the full ACPICA result buffer with every internal pointer unfixed - top-level Package.Elements plus each nested sub-package Elements remain raw kernel virtual addresses. 3/3 runs leaked 7+ KVA pointers each (0xfffff801... heap layout). Gated: root FWRITE on /dev/acpi plus the boot-time loader tunable (unprivileged O_RDONLY ioctl returns EPERM - verified).
Kernel references
sys/dev/acpica/acpi.c:3391sys/dev/acpica/acpi.c:3398sys/dev/acpica/acpi.c:3380sys/dev/acpica/acpi.c:3458
Guest
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
Fix validation
See fix.diff and README.md for the baseline/fixed A/B outputs (run.log / fixed.log).
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
Detail
Exploit chain
root-gated kernel heap address disclosure (KASLR defeat primitive); no direct memory corruption
Evidence (decisive lines)
run.log runs 1-3 (Package.Elements = 0xfffff80118684018, elem[0..5] nested Elements all raw KVA); reach.log (unpriv ioctl EPERM)
PoC changes
seed mcall_leak.c from the pack was already runnable; re-ran on a fresh stock boot with the loader tunable, added the unprivileged-reachability probe
Verified recommended fix
see fix.diff
Verdict
Stock X86_64_GENERIC kernel with debug.acpi.allow_method_calls=1: ACPIIO_DO_MCALL on a Package-returning method hands the caller the full ACPICA result buffer with every internal pointer unfixed - top-level Package.Elements plus each nested sub-package Elements remain raw kernel virtual addresses. 3/3 runs leaked 7+ KVA pointers each (0xfffff801... heap layout). Gated: root FWRITE on /dev/acpi plus the boot-time loader tunable (unprivileged O_RDONLY ioctl returns EPERM - verified).
No comments yet.