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

bus_dmamem_coherent reports success when the underlying bus_dmamap_load fails (error swallowed in callback), yielding dmem_busaddr==0

Field Value
ID DF-2981
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:N
CWE CWE-252 / CWE-755
File sys/kern/subr_busdma.c
Lines 46-47, 79-94 (contract: busdma_machdep.c:804-806)
Area kern/busdma
Confidence certain
Discovered 2026-09-02
Pass 2 (GLM 5.3 second pass)
Bucket memcorrupt
Reported pending
Known CVE none
CVE match novel

Summary

bus_dmamem_coherent() relies solely on bus_dmamap_load()'s return value to detect load failure. Per the busdma contract, bus_dmamap_load() returns 0 whenever the callback was invoked synchronously β€” the load error is delivered ONLY through the callback argument. The glue's callback, _bus_dmamem_coherent_cb(), discards that error. Therefore any synchronous load failure (EFBIG/EINVAL) would leave bus_dmamap_load()==0, and bus_dmamem_coherent() would return 0 (success) with dmem->dmem_busaddr==0 from the initial bzero β€” the caller then programs its device to DMA at physical address 0 while the CPU accesses the real allocation, and the map/tag are handed out in a never-loaded state. Latent only: with the current x86_64 MD allocator the failing-load branch is provably unreachable (tag created with nsegments=1 and maxsegsz==maxsize so the buffer can never split; the contigmalloc path fails cleanly with ENOMEM for boundary-constrained allocations). If the MD loader semantics ever change, or a future caller passes a load-failing configuration, a driver would silently DMA at bus address 0 β€” device-controlled writes to physical page 0. Filed as hardening so the fragile contract is fixed before it becomes memory corruption. Fix: capture the load error through the callback argument (row diff).

Timeline

  • 2026-09-02 Discovered during pass-2 audit of subr_busdma.c (GLM 5.3).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2981 Β· 4 files
FileTypeDescriptionSize
README.md β€” 245 B ↓ raw
fix.diff β€” 1.3 KB view raw
manifest.json β€” 428 B view raw
verdict.json β€” 2.0 KB view raw

DF-2981 evidence pack

What

bus_dmamem_coherent swallows synchronous bus_dmamap_load callback errors

Verdict

status=not_reproduced impact=none confidence=certain

See VERDICT.md for the full narrative and fix.diff for the verified fix.

Fix verification

not_testable

fix.diff applied in the F40FIX verification kernel build (RC=0, zero -Werror errors); no runtime A/B for this item (line-certain hardening)

↓ fix.diffper-fix-DF-2981

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md with path:line citations; run.log where a live demo exists; fix.diff

PoC changes

n/a - no PoC (unreachable branch); verification by source trace + compile validation

Verified recommended fix

propagate the synchronous callback error through a carg struct; bus_dmamem_coherent fails and frees on carg.error

Verdict

Line-accurate confirmation, fix compile-validated; runtime demonstration deliberately not attempted - the failing-load branch is provably unreachable with the current x86_64 MD allocator (tag is created with nsegments=1 and maxsegsz==maxsize so a legal buffer cannot split; subr_busdma.c:64-67). The defect is certain from source: the glue callback _bus_dmamem_coherent_cb returns early on error without recording it (subr_busdma.c:46-47), while the MD bus_dmamap_load always returns 0 for synchronous loads, delivering the error only through the callback (busdma_machdep.c: callback(...error); return 0). bus_dmamem_coherent therefore returns 0 (success) with dmem_busaddr==0 and a never-loaded map if a load ever fails - the caller programs its device to DMA at physical address 0. Fix (carg.error propagation) compiled in the combined F40FIX kernel build.