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).
No comments yet.