Heap OOB read in aibs_attach_sif when ACPI ?SIF returns a zero-element package
- File:
sys/dev/acpica/aibs/atk0110.c - Lines: 169β177 (BP deref at 170-177 without Count guard)
- Severity: Low
- CVSS 3.1:
CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U:C:L/I:N/A:H - CWE: CWE-125 Out-of-bounds Read
- Confidence: likely
- Status: new
Summary
After AcpiEvaluateObjectTyped succeeds for an ACPI_TYPE_PACKAGE return, the
code immediately dereferences bp->Package.Elements[0] without checking that
bp->Package.Count >= 1.
For a malicious or buggy ACPI ?SIF method returning Package(){} (zero
elements), ACPICA sizes the return buffer to exactly sizeof(ACPI_OBJECT)
(~24 bytes) and sets Elements to point past the buffer end, so the
o[0].Type read at line 171 and the o[0].Integer.Value read at line 177
are heap out-of-bounds reads of up to 12 bytes.
Root cause
In aibs_attach_sif (atk0110.c:169-177):
bp = b.Pointer;
o = bp->Package.Elements; /* line 170 */
if (o[0].Type != ACPI_TYPE_INTEGER) { /* line 171 -- OOB if Count==0 */
...
}
n = o[0].Integer.Value; /* line 177 -- further OOB if Type matched */
There is no bp->Package.Count >= 1 guard before the first dereference.
ACPICA behavior for Count==0 packages
Tracing ACPICA:
AcpiEvaluateObjectTyped(nsxfeval.c:193-299) callsAcpiEvaluateObjectwhich builds the external buffer viaAcpiUtCopyIpackageToEpackage(utcopy.c:457-504).- For
Count==0:Info.Length = ROUND_UP(sizeof(ACPI_OBJECT)) * 1 = ~24 bytes(utcopy.c:479,494-497); the buffer is allocated at exactly that size. ExternalObject->Package.Elementsis set toBuffer + sizeof(ACPI_OBJECT)(utcopy.c:487-488), which is past the end of the 24-byte allocation.AcpiEvaluateObjectTyped's only guard isReturnBuffer->Length == 0(nsxfeval.c:255), but for aCount==0package the length is ~24 (nonzero), and the Type check passes (ACPI_TYPE_PACKAGE==4matches).
So the zero-element package reaches aibs_attach_sif and o[0] is
dereferenced past the heap allocation.
If the 4 bytes of adjacent heap data at o[0].Type happen to equal 0x01
(ACPI_TYPE_INTEGER), the code additionally reads 8 bytes of
o[0].Integer.Value at Buffer+32 (12 bytes past end).
Subsequent checks (Count-1 < n with Count==0 producing UINT32_MAX, then
n < 1) prevent any further memory access or corruption, so the blast radius
is limited to the initial ~12-byte OOB read.
Threat model
Attacker must supply malicious ACPI AML bytecode that makes the ATK0110
device's TSIF/FSIF/VSIF method return Package(){} with zero elements.
This is reachable in VM/firmware-load scenarios:
- an attacker who controls the guest's ACPI tables (e.g., custom QEMU DSDT/SSDT), or
- who can reflash firmware on physical hardware,
β¦can trigger this during device attach at boot.
Impact:
- Bounded heap out-of-bounds read of up to 12 bytes of adjacent kernel heap memory.
- The read data influences only the control-flow comparison against
ACPI_TYPE_INTEGERand does not propagate to userspace (no info leak via sysctl ordmesg). - On KASAN-enabled kernels this triggers a panic (A:DoS);
- On standard kernels it silently reads adjacent slab data.
No write primitive, no code execution path identified.
Proof of concept
This requires a malicious ACPI SSDT override. Steps to reproduce on a DragonFlyBSD QEMU/KVM guest:
- Compile a malicious SSDT that defines an ATK0110 device with a zero-element
TSIFpackage:
DefinitionBlock ("evil.aml", "SSDT", 2, "ATK", "TEST", 0x1) {
Device (ATK0) {
Name (_HID, "ATK0110")
Method (TSIF) { Return (Package() {}) } // zero elements
Method (VSIF) { Return (Package() {}) }
Method (FSIF) { Return (Package() {}) }
}
}
- Load it at boot:
acpi_load=YESin/boot/loader.confwithevil.amlin/boot/, or use QEMU's-acpitable file=evil.aml. - Boot the guest. During
aibs_attach,AcpiEvaluateObjectTyped("TSIF")succeeds with a 0-element package. aibs_attach_sifdereferenceso[0]past the buffer β heap OOB read. On KASAN kernels this panics; on standard kernels it silently reads adjacent heap bytes and returns "invalid type" or "no members", printing the error todmesg.
Success criteria: KASAN panic with "heap-buffer-overflow" or (without
KASAN) confirmation via dmesg that TSIF was evaluated with Count==0 and
the driver took an error path rather than validating the count first.
Note: because all three ?SIF methods return empty packages, sensors_count==0
and aibs_attach returns ENXIO (atk0110.c:126-129), so no sysctl nodes are
created. The OOB read is the only security-relevant effect.
Recommended fix
Add a Package.Count validation before dereferencing o[0]. Insert after line
169 (bp = b.Pointer;) and before line 170:
--- a/sys/dev/acpica/aibs/atk0110.c
+++ b/sys/dev/acpica/aibs/atk0110.c
@@ -166,6 +166,13 @@ aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st)
return;
}
+ bp = b.Pointer;
+ if (bp->Package.Count < 1) {
+ device_printf(sc->sc_dev, "%s: empty package (count=0)\n", name);
+ AcpiOsFree(b.Pointer);
+ return;
+ }
+
- bp = b.Pointer;
o = bp->Package.Elements;
if (o[0].Type != ACPI_TYPE_INTEGER) {
device_printf(sc->sc_dev, "%s[0]: invalid type\n", name);
This ensures at least one element exists before Elements[0] is accessed,
preventing the heap OOB read for any zero-element package returned by ACPI.
References
sys/dev/acpica/aibs/atk0110.c:169-177β unguardedo[0]deref afterAcpiEvaluateObjectTypedsys/dev/acpica/.../nsxfeval.c:193-299βAcpiEvaluateObjectTypeddoes not gate onPackage.Countsys/dev/acpica/.../utcopy.c:479,487-488,494-497βCount==0buffer sized tosizeof(ACPI_OBJECT),Elementsset past end
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2006 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | Source verification narrative | 1.1 KB | β raw |
| fix.diff | suggested-fix | Fix: Add bp->Package.Count < 1 check before Elements[0] dereference. | 454 B | view raw |
| build.sh | build-script | Build/validation instructions | 366 B | view raw |
| run.sh | run-script | Run instructions (HW-gated, source-only) | 184 B | view raw |
| env.txt | environment | Guest environment | 404 B | view raw |
DF-2006 - Source Verification
Verdict: REPRODUCED (source-only confirmation)
Finding: sys/dev/acpica/aibs/atk0110.c:170-171
Mechanism: aibs_attach_sif derefs bp->Package.Elements[0] without checking Package.Count>=1. Zero-element ACPI package β Elements points past buffer β heap OOB read.
Hardware dependency: Requires ASUS ATK0110 ACPI with malicious SIF method.
Fix: Add bp->Package.Count < 1 check before Elements[0] dereference.
Verification method
Source-only confirmation. The cited code path was traced line-by-line in the audited sys/ tree. The bug exists exactly as described. This is a HW-gated driver finding β the vulnerable code path requires specific hardware (GPU, controller, PHY, TPM, etc.) not present in the QEMU audit guest. Runtime reproduction on this guest is not possible without the hardware.
Fix validation
fix.diff authored and applied to guest source. All 40 fixes in this batch
compile cleanly in a single combined kernel build: make -j6 nativekernel
KERNCONF=X86_64_GENERIC β rc=0, zero -Werror violations.
Kernel: DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026
Fix verification
not_testablenot_testable: HW-gated. fix.diff applies + compiles in batch build (rc=0 -Werror). Source trace confirms fix closes the path.
Batch build: 40 fix.diffs applied, make nativekernel β rc=0 -Werror. Bug at sys/dev/acpica/aibs/atk0110.c:170-171 source-confirmed.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- a
- c
- p
- i
- c
- a
- /
- a
- i
- b
- s
- /
- a
- t
- k
- 0
- 1
- 1
- 0
- .
- c
- :
- 1
- 7
- 0
- -
- 1
- 7
- 1
Detail
Exploit chain
none
Evidence (decisive lines)
Source trace sys/dev/acpica/aibs/atk0110.c:170-171. HW-gated (no HW in QEMU). Fix compiles in batch build rc=0.
PoC changes
Evidence pack: VERDICT.md, fix.diff, manifest.json. Fix: Elements[0] without Count>=1 check β OOB read. Add count check.
Verified recommended fix
See fix.diff. Elements[0] without Count>=1 check β OOB read. Add count check.
Verdict
REPRODUCED (source-only). sys/dev/acpica/aibs/atk0110.c:170-171: Elements[0] without Count>=1 check β OOB read. Add count check.
No comments yet.