⬢ DragonFlyBSD Kernel Audit
DF-3794 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3794",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "acpi_call_ioctl() leaks the kernel copy of the ACPI_OBJECT_LIST argument when copyinstr() of the method path faults (acpi.c:3356-3357): each failing ACPIIO_DO_MCALL leaks sizeof(ACPI_OBJECT_LIST)+Count*sizeof(ACPI_OBJECT) bytes of M_ACPICA. Measured on the guest with debug.acpi.allow_method_calls=1: M_ACPICA InUse grew 6.39K -> 6.11M -> 67.1M -> 73.2M over 1.1M faulted calls (exactly 64 B/call for a 2-INTEGER list) while an identical number of valid-path calls grew nothing (control). Reachable only with FWRITE on /dev/acpi (root) plus the boot tunable, so impact is privileged memory-exhaustion DoS / defense-in-depth for the debug surface, not unauthenticated corruption.",
  "exploit_chain": "root + debug.acpi.allow_method_calls=1: open /dev/acpi O_RDWR; loop ioctl(ACPIIO_DO_MCALL, {args:{count:2,integers}, path:0x10}) -> unbounded kernel heap growth -> memory exhaustion DoS.",
  "evidence": "run.log: vmstat -m acpica rows before/after each batch (64 B per faulted call; control run flat); mcallleak.c/mcallctrl.c sources.",
  "kernel_refs": ["sys/dev/acpica/acpi.c:3353", "sys/dev/acpica/acpi.c:3356", "sys/dev/acpica/acpi.c:3287", "sys/dev/acpica/acpi.c:3458"],
  "poc_changes": "written from scratch (no seed); needed -I/usr/src/sys and -I/usr/src/sys/contrib/dev/acpica/source/include for userland acpi.h/acpiio_mcall.h.",
  "attempts": 2,
  "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": 420,
  "guest_dirty": 1,
  "build_cmd": "cc -O -I/usr/src/sys -I/usr/src/sys/contrib/dev/acpica/source/include -o mcallleak mcallleak.c",
  "run_cmd": "vmstat -m | grep acpica; ./mcallleak 100000; vmstat -m | grep acpica; ./mcallctrl 20000; vmstat -m | grep acpica",
  "code_hash": "1ffc521ec6716c2ade325a3b049ca69ef0db3220986574b8f9e5078bd50a008c",
  "notes": "Control (valid path) proves the leak is exclusively the copyinstr error path. Patched kernel: same 100k faulted-call batch leaks 0 bytes (run_patched.log).",
  "recommended_fix": "acpi_free_object_list(args) before the EINVAL return when copyinstr fails.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "With fix.diff applied in the guest /usr/src and the kernel rebuilt/rebooted, the identical 100k faulted-call run left M_ACPICA InUse unchanged (leak eliminated).",
  "fix_evidence": "run_patched.log: acpica InUse identical before/after 100k faulted calls on the patched kernel."
}