{
  "finding_id": "DF-5073",
  "status": "reproduced",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Mechanism reproduced on the audit guest with an injected SSDT: an ACPI0003 AC-adapter whose _PSR evaluates OK but returns NO object makes hw.acpi.acline read 0 (for root and uid 1001) where the sentinel-correct value is -1. 0 is reachable only through acpi_GetIntegers uninitialized stack ACPI_OBJECT (AcpiEvaluateObject leaves ReturnBuffer->Pointer untouched on AE_OK for no-return methods, nsxfeval.c:541-545), whose residue here reads {Type=ACPI_TYPE_INTEGER, Value=0}; acpi_acad.c:111/116 persists it into sc->status and acpi_acad.c:289/233 exports it through the world-readable sysctl on every read. Impact honestly bounded to none: 21 same-thread kernel-stack grooms (connect(2), KERN_PROC_ALL sysctls, block reads) could not vary the leaked dword from 0 \u2014 the slot is owned by ACPI-evaluation frames, so no pointer-bearing kernel memory was demonstrated disclosed. Trigger is firmware-shape (boot-time AML) only; reader side is fully unprivileged. Severity Low (kernleak class).",
  "exploit_chain": "",
  "evidence": "run.sane.log (control boot: acline=1 for uid 1001 proves injected-SSDT->acpi_acad attach->_PSR->world-readable sysctl chain); run.2.log (trigger boot: acline=0 instead of -1); run.log (groom.c: 21 unprivileged reads after deep same-thread grooms, constant 0); VERDICT.md (full why-0-only-via-uninit-path derivation and honest impact=none reasoning); fix.diff (1-line root-cause fix in acpi_GetInteger)",
  "kernel_refs": [
    "sys/dev/acpica/acpi_acad.c:110",
    "sys/dev/acpica/acpi_acad.c:111",
    "sys/dev/acpica/acpi_acad.c:115",
    "sys/dev/acpica/acpi_acad.c:116",
    "sys/dev/acpica/acpi_acad.c:288",
    "sys/dev/acpica/acpi_acad.c:289",
    "sys/dev/acpica/acpi_acad.c:233",
    "sys/dev/acpica/acpi.c:2175",
    "sys/dev/acpica/acpi.c:2177",
    "sys/dev/acpica/acpi.c:2179",
    "sys/dev/acpica/acpi.c:2180",
    "sys/contrib/dev/acpica/source/components/namespace/nsxfeval.c:541"
  ],
  "poc_changes": "No seed PoC existed (new pass-2 finding). Wrote both SSDTs from scratch; had to model the no-return _PSR as If (LGreater (0,1)) {Return(One)} so iasl accepts it while still falling off the end (iasl warns 3115/3107, which is exactly the malformed-firmware shape). First groom attempt (process-level sysctl -a / ls -lR between reads) failed to move the value because each command is a separate process with a different kstack; rewrote groom.c to groom and read in the SAME thread.",
  "attempts": 3,
  "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": 960,
  "guest_dirty": 0,
  "build_cmd": "./build.sh  (scp ASL to guest; guest iasl compiles ssdt_acad_sane.asl + ssdt_acad_leak.asl; guest cc builds groom.c)",
  "run_cmd": "./run.sh  (boot A: QEMU_EXTRA=-acpitable file=ssdt_acad_sane.aml ./vm.sh up 300; boot B: QEMU_EXTRA=-acpitable file=ssdt_acad_leak.aml; then run_root/run_user sysctl hw.acpi.acline and /tmp/groom)",
  "code_hash": "46852741a9d4d858c093a39ee91d995560203556a5a079f97b586dfb4850a37a (groom.c); c18cf1d8f19214bd82589db48e15a2e079c3505efdef46a98c3f458791b73f40 (ssdt_acad_leak.asl)",
  "notes": "Root cause is DF-3793 (acpi.c acpi_GetInteger, pass 1); this finding is the call-site export primitive in acpi_acad.c (unaudited in pass 1): the garbage becomes persistent driver state and is served world-readably on every sysctl read, which also re-runs the AML evaluation. The same defect pattern exists in every acpi_GetInteger consumer that pre-seeds a sentinel; acad is the one with a world-readable, re-evaluating export. Trigger-boot also flips power_profile_set_state on the first garbage read (acpi_acad.c:118) - functional misbehavior, not security impact.",
  "recommended_fix": "In acpi_GetInteger (sys/dev/acpica/acpi.c), pre-set param.Type = ACPI_TYPE_ANY before AcpiEvaluateObject so a no-return evaluation yields AE_TYPE without reading uninitialized stack (fix.diff); defensively, acpi_acad.c:111 could also treat acpi_GetInteger failure as unknown explicitly.",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": null,
  "fix_verdict": "Fix validation skipped per contract (mandatory only for reproduced memory-corruption findings; this is Low severity, impact none). fix.diff is a 1-line root-cause fix in acpi.c authored after verification; with it, the trigger boot must read hw.acpi.acline = -1 instead of 0. Never applied to sys/.",
  "fix_evidence": "fix_baseline_reproduced=1: trigger boot on stock kernel reads acline=0 (run.2.log). Patched-kernel run not performed."
}