An ordinary NIC may not write a confidential VM's private pages
(secure DMA), so Linux gives it a
bounce buffer in shared memory and copies. The
Linux DMA lab shows those copies; this
workbook asks the security questions about the same bytes: when does
each buffer change, what can the host read, and when may the
application trust what arrived? The copies below follow Linux 7.3's
code, as dmakit models it.
What claims does this page make? · 2 points
Platform assumption: the copy points of map, sync and unmap follow Linux 7.3 swiotlb and DMA code as dmakit models it, and may differ in other kernels.
Teaching model: the descriptors, the application's checks and the host-read panel are this page's own small model, with synthetic addresses.
Address or copy? Four routes to the same buffer
A 32-bit device receives 16 bytes into O, which sits above 4 GiB. A
translation (IOMMU) changes the address the device uses; only a CPU
copy (SWIOTLB) moves bytes. Pick a route, map the buffer, and submit
only if the map succeeded.
Sharing a message shares its page
Experiments
Words used in the experiments
O, B, App
The driver's buffer at 0x100002040, private (the Linux DMA lab's Original A; 64 bytes into secure DMA's private page O; the model uses one address as both GPA and SPA), the bounce slot the kernel copies through (0x2000040, in a shared pool), and the application's buffer.
Map, sync, unmap
dma_map_single() gives the device an address; dma_sync_single_for_cpu() or _for_device() hands the buffer over; dma_unmap_single() ends it. With a bounce buffer, each can copy.
Receive, send
DMA_FROM_DEVICE (the device writes) and DMA_TO_DEVICE (the device reads).
RX16
The packet: de ad be ef, four times.
Experiment
Timeline: which buffer holds the bytes, and what the CPU copied
Intel and Arm:
The bytes after that step
This "What if" step ran on its own copy; the panels show that copy.
Buffers
Copy ledger · every CPU copy so far, never erased by a later failure
Counters
What the host read
Driver and application
A copy of 16 bytes counts 16, not 32. Counts are bytes, not time.
Descriptors and the application's checks are this page's own small
model; the copies and the IOMMU are dmakit's.
Three kinds of "ownership", all true at once
Question
Answered by
After a receive's sync
May the CPU use O now?
The DMA API (map, sync, unmap)
Yes
Whose page is O?
The RMP (SNP)
Still the VM's private page
Can the application trust the bytes?
The application's own checks
Not until it checks them
Pressing "sync" does not change who owns the page, and a private
page can hold untrusted input.
Rules that fall out
Anything in a buffer you map may be copied into shared memory, even for a receive, and even if the map then fails.
Check lengths and descriptors from the device or shared memory against what you mapped, in a private copy, and use that copy.
Validate after the last copy into O, or take your own snapshot first.
Clean up with the size you mapped, never a size the device reported.
A failed operation can leave earlier writes behind; retrying may repeat them.
To carry secrets through B at all, encrypt them in the application (the AES-GCM experiment).
Sources
Linux 7.3 kernel/dma/swiotlb.c, kernel/dma/direct.c, drivers/iommu/dma-iommu.c, as dmakit 3.0.0 modelled them when reviewed (the site now ships 4.3.0) (model limits); Linux DMA API HOWTO.
The author's own study notes on confidential computing, written from AMD's public documents (not published), workbook lessons W03 to W06, W16, W17, W25, W26 and W28, and examples E15 to E18.