_bus_dmamap_sync() switches on a bitmask op: combined BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD matches no case and silently performs no bounce copy in either direction
Summary
switch(op) equality dispatch on a bitmask: the legal combined PREWRITE|POSTREAD (0x06) matches no case - no pre-write copy (device DMAs stale cross-buffer bounce contents) and no post-read copy (device data never reaches the client). pc64 replaced the switch with bitmask if-tests; the fork never got it. Proven IN A LIVE VKERNEL: combined op leaves BOTH buffers untouched ('SILENT NO-OP (bug confirmed)') with the bounce page pre-planted; bitmask if-form fix validated ('combined ... honored'). Gated on a bus_dma driver present.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5372 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| dfbusdma.c | β | 13.8 KB | view raw | |
| build_kernel.sh | β | 958 B | view raw | |
| build_image.sh | β | 1.1 KB | view raw | |
| run.sh | β | 118 B | view raw | |
| fix.diff | β | 1012 B | view raw | |
| build.log | β | 934.3 KB | β download | |
| fix-build.log | β | 25.0 KB | view raw | |
| run.log | β | 3.6 KB | view raw | |
| run.fixed.log | β | 3.2 KB | view raw | |
| env.txt | β | 348 B | view raw | |
| VERDICT.md | β | 2.3 KB | β raw | |
| manifest.json | β | 838 B | view raw | |
| verdict.json | β | 4.3 KB | view raw |
DF-5372 VERDICT β REPRODUCED (combined bus_dmamap_sync op is a silent no-op on vkernel64)
Root cause
sys/platform/vkernel64/platform/busdma_machdep.c:913-938:
_bus_dmamap_sync() dispatches on switch (op). bus_dmasync_op_t is a
bitmask (sys/sys/bus_dma.h:118-121), so the legal combined operation
BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD (0x06) matches no case and both
bcopy loops are skipped. pc64's implementation uses if (op & ...)
(pc64 busdma_machdep.c ~:1044) β the vkernel64 fork predates/misplaced that
fix.
Reproduction (VKERNEL64 vkernel, -m 512m, guest DragonFly 6.5-DEVELOPMENT)
Driver (dfbusdma.c, compiled in, SYSINIT): 8192-alignment bounce tag (default
hw.busdma.bounce_alignment=1 confirmed = 1), misaligned 64-byte buffer
loaded via bus_dmamap_load (bounce page attached, datacount=64 verified),
then:
- control
bus_dmamap_sync(tag, map, BUS_DMASYNC_PREWRITE)β client pattern appears in the bounce page ("PREWRITE alone: copy ok"). - bug case: bounce page pre-planted with "PLANTED-IN-BOUNCE!!", client
buffer set to "COMBINED-OP-PATTERN!!", then
bus_dmamap_sync(tag, map, BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD). Result: bounce page still holds PLANTED, client still holds PATTERN β neither direction copied anything ("SILENT NO-OP (bug confirmed)", "VERDICT PROVEN"). Vkernel stayed ALIVE.
Fix validation
fix.diff converts the switch to bitmask tests (pc64 form). With it applied (and DF-5370's fix, layered earlier): "combined PREWRITE|POSTREAD: honored", "VERDICT NOT PROVEN" β i.e. the previously-observed no-op is gone; both copies execute.
Notes
- No stock VKERNEL64 driver calls bus_dma (vkd/vke/vcd do not), so this is a latent data-integrity bug for any kldloaded bus_dma driver using combined sync ops β Low severity.
- PREWRITE-skip means the device would DMA stale cross-buffer contents from the shared bounce pool (data confusion); POSTREAD-skip means device data never lands (silent corruption).
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
fixedfix.diff applied (bitmask dispatch), VKERNEL64 rebuilt. Baseline: combined op SILENT NO-OP, VERDICT PROVEN (bug present). Patched: 'combined PREWRITE|POSTREAD: honored', VERDICT NOT PROVEN - both copies execute; control PREWRITE still copies; vkernel ALIVE.
run.fixed.log: 'DF5372: combined PREWRITE|POSTREAD: honored' + 'DF5372: VERDICT NOT PROVEN'; fix-build.log full rebuild output; fix.diff git-apply-able (independent hunk)
Confirmed kernel references
Detail
Exploit chain
bounce-attached map (e.g. 8192-alignment tag under default hw.busdma.bounce_alignment=1, or lowaddr-constrained tag) -> driver issues bus_dmamap_sync(tag, map, BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD) -> switch matches no case -> no bcopy in either direction -> device reads stale bounce contents / device writes never copied back (data corruption and cross-buffer data confusion within the vkernel)
Evidence (decisive lines)
run.log (baseline): 'DF5372: PREWRITE alone: copy ok' (control), 'DF5372: combined PREWRITE|POSTREAD: SILENT NO-OP (bug confirmed)', 'DF5372: VERDICT PROVEN - combined op copies nothing'. run.fixed.log (after fix.diff): 'DF5372: combined PREWRITE|POSTREAD: honored', 'DF5372: VERDICT NOT PROVEN'. env.txt: hw.busdma.bounce_alignment=1.
PoC changes
authored fresh (shared rig with DF-5370). Notables: the driver peeks the private struct bounce_page via a mirror (first word of map->bpages.stqh_first -> vaddr) to observe bounce contents directly; DFly STAILQ_HEAD has two pointers (sizeof(bus_dmamap)=72).
Verified recommended fix
Replace switch (op) with bitmask tests: if (op & BUS_DMASYNC_PREWRITE) {pre-write bcopy loop}; if (op & BUS_DMASYNC_POSTREAD) {post-read bcopy loop} - mirrors pc64; see fix.diff (validated)
Verdict
_bus_dmamap_sync() (sys/platform/vkernel64/platform/busdma_machdep.c:903-940) dispatches the sync operation with switch (op), but bus_dmasync_op_t is a bitmask (sys/sys/bus_dma.h:118-121): the legal combined operation BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD (0x06) matches no case and BOTH bcopy loops are skipped - a silent no-op that drops the pre-write copy (device then DMAs stale, previously-bounced data from the shared bounce pool) and the post-read copy (device-written data never reaches the client buffer). Proven in a live VKERNEL64 vkernel with a compiled-in driver: control sync(PREWRITE) copies correctly, while sync(PREWRITE|POSTREAD) leaves both the planted bounce-page contents and the client buffer untouched ('SILENT NO-OP (bug confirmed)', 'VERDICT PROVEN'). pc64 fixed this with bitmask if-tests (pc64 busdma_machdep.c ~:1044); the vkernel64 fork never received the change. fix.diff (bitmask form, mirroring pc64) validated: combined op then reports 'honored' and the VERDICT flips to NOT PROVEN (bug gone). Recorded impact dos = strongest demonstrated end state (functional corruption of DMA'd data); no stock VKERNEL64 driver uses bus_dma, so reachability needs a kldloaded bus_dma driver using combined sync ops - Low severity.
No comments yet.