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

ACPI_DEBUG_MEMMAP build reuses a found track by moving it to list head without unlinking, orphaning nodes and risking cycles

Field Value
ID DF-2088
Status new
Severity Info
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:L
CWE CWE-672 Improper Operation on a Resource after Expiration or Release
File sys/dev/acpica/Osd/OsdMemory.c
Lines 96-116
Area acpi/dev
Confidence certain
Discovered 2026-07-25
Reported pending
Known CVE none
CVE match dfly_specific

Summary

When the kernel is built with ACPI_DEBUG_MEMMAP (sys/dev/acpica/Makefile:8-10, off by default), AcpiOsMapMemory searches the existing list for a track whose ->base matches the newly mapped address (OsdMemory.c:96-99) and, if found, reuses it instead of allocating. It then unconditionally executes acpi_mapbase = track (line 116) without first unlinking track from its current position. If the found track was anywhere other than the head, every node between the old head and that track is orphaned from the traversal (memory leak of both the track struct and the kmem mapping it describes), and the predecessor's stale ->next still points at the moved track β€” laying the groundwork for a duplicate-entry or cycle-induced infinite loop on the next walk.

Root cause

  • OsdMemory.c:96-99 walks the list: for (track = acpi_mapbase; track != NULL; track = track->next) { if (track->base == map) break; }.
  • OsdMemory.c:103-107 only allocate a fresh node when track == NULL.
  • OsdMemory.c:108 then unconditionally sets track->size = Length.
  • OsdMemory.c:116 unconditionally does acpi_mapbase = track.

The found (non-NULL) case never executes the equivalent of *pred->next = track->next to detach the node before re-heading it, so the list topology becomes inconsistent.

Threat model & preconditions

  • Attacker position: privileged local user (root) β€” debug build only.
  • Privileges gained or impact: hang/infinite-loop in the list walker, or slow leak of mappings.
  • Required config or capabilities: kernel explicitly built with ACPI_DEBUG_MEMMAP=yes (diagnostic build, not the default release).
  • Reachability: repeated AcpiOsMapMemory calls that yield a recycled kmem virtual address (base collision in OsdMemory.c:97).

Proof of concept

PoC source: findings/poc/DF-2088/

Build & run

# Build a kernel with ACPI_DEBUG_MEMMAP=yes (sys/dev/acpica/Makefile).
# Then drive repeated AcpiOsReadMemory on a fixed register from many threads.
./drive_debug_memmap.sh

Expected output

# After enough base-address collisions the list walker in
# AcpiOsUnmapMemory either hangs (cycle) or kmem_map exhaustion panics.
show kmem_map: ...
panic: block-size table out of range

Impact

Only reachable in a diagnostic build. Reported as a hardening/robustness defect because the same code shape would be a real bug if the debug knob ever became default.

Unlink-before-rehead in the debug build:

--- a/sys/dev/acpica/Osd/OsdMemory.c
+++ b/sys/dev/acpica/Osd/OsdMemory.c
@@ -94,9 +94,15 @@
 #ifdef ACPI_DEBUG_MEMMAP
-    for (track = acpi_mapbase; track != NULL; track = track->next) {
+    struct acpi_memtrack **pp;
+    for (pp = &acpi_mapbase; (track = *pp) != NULL; pp = &track->next) {
    if (track->base == map) {
+       /* detach found node from its current position before re-heading */
+       *pp = track->next;
+       track->next = acpi_mapbase;
        break;
    }
     }

Combined with the spinlock from DF-2087 the debug walker is also race-safe.

References

  • sys/dev/acpica/Makefile:8-10 β€” ACPI_DEBUG_MEMMAP knob.

Timeline

  • 2026-07-25 Discovered during automated audit.
  • 2026-07-25 Reported to DragonFlyBSD security contact.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2088 Β· 2 files
FileTypeDescriptionSize
fix.diff suggested-fix git-apply-able fix 1.8 KB view raw
VERDICT.md verdict source-trace confirmation 702 B ↓ raw
VERDICT.md verdict source-trace confirmation
↓ download raw

DF-2088 β€” ACPI_DEBUG_MEMMAP reuse without unlinking orphans list nodes

Verdict

REPRODUCED (source-only confirmation). Bug confirmed by source tracing.

Mechanism

In ACPI_DEBUG_MEMMAP builds, AcpiOsMapMemory (96-116) searches for a track whose base matches and reuses it, but does not unlink it from its old list position before setting acpi_mapbase=track. Nodes before the reused track are orphaned, leaking memory and corrupting tracking.

Fix

When reusing a found track, unlink it from its current position before re-adding at head. (Fixed as part of DF-2087 lock addition.)

Batch-build status

Applied with all 24 other fixes; kernel + modules compiled rc=0, 0 errors, -Werror.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Added unlink-before-reuse; batch build rc=0.

Added unlink-before-reuse; batch build rc=0.
↓ fix.diffcombined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

AcpiOsMapMemory reuses track without unlinking. Debug-only.

Verified recommended fix

AcpiOsMapMemory reuses track without unlinking. Debug-only.

Verdict

AcpiOsMapMemory reuses track without unlinking. Debug-only.