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

acpi_asus_probe dereferences the unchecked INIT evaluation result: NULL Obj or non-String object -> NULL/wild pointer panic at probe

Summary

The AcpiEvaluateObject status is discarded; Buf.Pointer starts NULL so on failure Obj==NULL, yet String.Pointer is dereferenced with no NULL/Type check. If INIT returns a non-String the union read at offset 16 is a garbage pointer into strncmp. Even the intended NULL-string branch FALLS THROUGH to strncmp(NULL, ...) for non-Samsung non-EeePC platforms - deterministic panic. Firmware-gated boot DoS. Validate-status/Obj/Type fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4408 Β· 5 files
FileTypeDescriptionSize
README.md β€” 2.6 KB ↓ raw
VERDICT.md β€” 2.7 KB ↓ raw
env.txt β€” 1.9 KB view raw
fix.diff β€” 1.8 KB view raw
verdict.json β€” 2.5 KB view raw

DF-4408 β€” acpi_asus_probe dereferences an unchecked ACPI evaluation result (NULL / non-String INIT object)

  • File: sys/dev/acpica/acpi_asus/acpi_asus.c (pass 2, GLM 5.3; no known findings on this file)
  • Class: CWE-476 (NULL pointer dereference) + CWE-690 (unchecked return value)
  • Severity: Low β€” firmware-gated (needs an ACPI node with HID ATK0100/ASUS010 whose INIT method is missing, fails, or returns a non-String). Trigger is probe time (boot), or a root-forced re-probe/re-scan. Kernel panic (DoS), no info leak, no corruption primitive.

Defect (path:line)

acpi_asus_probe, acpi_asus.c:579-586:

AcpiEvaluateObject(sc->handle, "INIT", &Args, &Buf);   /* status ignored */
Obj = Buf.Pointer;                                     /* NULL on failure */

if (Obj->String.Pointer == NULL) {                     /* NULL deref if Obj==NULL */

and the fall-through of that same branch, acpi_asus.c:613-621:

}              /* Obj->String.Pointer == NULL but neither Samsung (ODEM) nor
                * EeePC (ASUS010) matched: falls out of the if-block */
...
for (model = acpi_asus_models; model->name != NULL; model++) {
    if (strncmp(Obj->String.Pointer, model->name, 3) == 0) {   /* strncmp(NULL,...) */

Three concrete panic paths, all deterministic: 1. INIT missing / evaluation fails (AE_NOT_FOUND etc.): Buf.Pointer stays NULL (buffer was Buf.Pointer = NULL; Buf.Length = ACPI_ALLOCATE_BUFFER, acpi_asus.c:576-577) β†’ Obj->String.Pointer faults at once. 2. INIT returns an Integer/Package/Buffer: Obj->Type != ACPI_TYPE_STRING is never checked; String.Pointer (offset 16 in union acpi_object) reads bytes outside the returned member β†’ wild pointer into strncmp. 3. INIT returns a String whose Pointer is NULL and the DSDT is neither ODEM (Samsung) nor ASUS010 (EeePC): the intended branch handles Samsung and EeePC but then falls through into the model-name loop and does strncmp(NULL, model->name, 3).

Same family: acpi_asus.c:621-624, 710 pass Obj->String.Pointer to strncmp/sbuf_printf("%s") unvalidated.

Build / run

Not runnable on the audit guest: acpidump shows zero ATK0100/ASUS010 nodes (see env.txt), so acpi_asus never probes here. On a machine with a broken INIT method this panics during boot; a root user can also force it via devctl-driven reprobe. No unprivileged trigger exists.

Check the evaluation status, Obj != NULL, and Obj->Type == ACPI_TYPE_STRING before any use, and make the NULL-String-Pointer branch return instead of falling through β€” see fix.diff. (FreeBSD's copy has the same gap; fix should go upstream.)

VERDICT.md
↓ download raw

DF-4408 VERDICT β€” untested (source-verified; firmware-gated boot-time panic)

Reproduced?

No. Status untested: triggering requires an ACPI device whose HID matches ATK0100 or ASUS010 (acpi_asus.c:553,561) and a broken INIT method. The audit guest's ACPI namespace contains zero such nodes (verified live β€” env.txt), so the driver never even probes. Loading a crafted DSDT requires root (and on this guest, a custom QEMU BIOS blob). This is a firmware-compatibility crash of the class that historically hit real laptops (e.g. Samsung P30 PRs upstream), not an unprivileged attack path.

Defect (certain from source)

acpi_asus_probe evaluates INIT and uses the result blind:

  1. acpi_asus.c:579 β€” AcpiEvaluateObject(sc->handle, "INIT", &Args, &Buf) return status discarded. Buffer was reset at acpi_asus.c:576-577 (Buf.Pointer = NULL; Buf.Length = ACPI_ALLOCATE_BUFFER), so on failure (no INIT method, AML error, serializer trouble) Buf.Pointer remains NULL.
  2. acpi_asus.c:586 β€” if (Obj->String.Pointer == NULL) dereferences Obj with no Obj != NULL check β†’ panic in probe.
  3. No Obj->Type == ACPI_TYPE_STRING validation: if INIT returns an Integer (some BIOS variants do), Obj->String.Pointer is read from union bytes that belong to a different member (ACPI_OBJECT_STRING.Pointer sits at offset 16, past ACPI_OBJECT_INTEGER.Value at offset 8) β†’ garbage pointer β†’ strncmp wild read at acpi_asus.c:621.
  4. Even the intended NULL-string branch falls through: when Obj->String.Pointer == NULL but the DSDT is neither Samsung ODEM (acpi_asus.c:597) nor ASUS010 EeePC (acpi_asus.c:605), control leaves the if block and reaches strncmp(Obj->String.Pointer, ...) at acpi_asus.c:621 with a NULL first argument β†’ guaranteed panic. This makes the defect reachable on any ATK0100 machine whose INIT misbehaves, not just exotic ones.

Impact: NULL/wild-pointer dereference in device_probe context β†’ kernel panic at attach (boot-time or rescan DoS). No write primitive, no disclosure.

Fix

fix.diff: validate status + Obj != NULL + Type == ACPI_TYPE_STRING, keep the Samsung/EeePC NULL-string detection branch, and make its tail return ENXIO instead of falling into the model loop. Not validated on hardware (no applicable firmware on guest) β†’ fix_status: not_testable.

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
baseline no→ patch + rebuild →patched clean

fix.diff authored from source analysis; cannot be built/validated on the audit guest - driver only builds/attaches with ATK0100/ASUS010 firmware (optional acpi_asus, absent namespace).

findings/poc/DF-4408/fix.diff; env.txt
↓ fix.diffper-fix-DF-4408

Confirmed kernel references

Detail

Evidence (decisive lines)

findings/poc/DF-4408/VERDICT.md (path:line trace incl. union-offset analysis for non-String returns), README.md, env.txt (live guest ACPI probe), fix.diff

Verified recommended fix

Validate AcpiEvaluateObject status, Obj != NULL, and Obj->Type == ACPI_TYPE_STRING before use, and make the NULL-string branch return ENXIO instead of falling through to strncmp(NULL); see fix.diff.

Verdict

Source-verified NULL/wild-pointer dereference in acpi_asus_probe: the AcpiEvaluateObject(INIT) status is ignored (acpi_asus.c:579), Buf.Pointer is NULL on failure, Obj->String.Pointer is dereferenced with no Obj NULL or Type check (acpi_asus.c:586), and even the intended NULL-string branch falls through to strncmp(Obj->String.Pointer=NULL, ...) at acpi_asus.c:621 when the platform is neither Samsung ODEM nor ASUS010 EeePC. Deterministic kernel panic at probe (boot-time DoS) on any ATK0100/ASUS010 machine with a missing, failing, or non-String INIT method. Untested at runtime: the audit guest ACPI namespace has zero ATK0100/ASUS010 nodes (verified live, env.txt) so the driver never attaches; no unprivileged trigger path exists (probe runs at boot or under root-forced rescan; DSDT replacement requires root).