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-99walks the list:for (track = acpi_mapbase; track != NULL; track = track->next) { if (track->base == map) break; }.OsdMemory.c:103-107only allocate a fresh node whentrack == NULL.OsdMemory.c:108then unconditionally setstrack->size = Length.OsdMemory.c:116unconditionally doesacpi_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
AcpiOsMapMemorycalls that yield a recycled kmem virtual address (base collision inOsdMemory.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.
Recommended fix
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_MEMMAPknob.
Timeline
- 2026-07-25 Discovered during automated audit.
- 2026-07-25 Reported to DragonFlyBSD security contact.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2088 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | git-apply-able fix | 1.8 KB | view raw |
| VERDICT.md | verdict | source-trace confirmation | 702 B | β 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
fixedAdded unlink-before-reuse; batch build rc=0.
Added unlink-before-reuse; batch 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.
No comments yet.