From 677fe92c679c501fe54aa8590444143c4114557e Mon Sep 17 00:00:00 2001 From: Pedro Henrique Penna Date: Wed, 28 Oct 2026 17:17:18 -0700 Subject: [PATCH 1/3] openvmm: refuse virtio device buffers outside the e820 RAM ranges Pin microsoft/openvmm#4794 at bd2b27a2ef9339bd16692c93facb8d84952dc9f8, five commits on 832d5bb48, the previous pin, which is the head of feature/microvm/dev. The microVM memory layout requires that DMA ranges lie wholly inside a RAM range of the e820 map and cross neither the MMIO aperture nor a reserved boot structure, but each microVM virtio device received the whole guest memory. A descriptor failed only when its buffer left guest memory, as in the aperture, and then only for the part that did, so a guest could point a device buffer at the shared virtio interrupt-status page at 0x30000, which the devices themselves update, or at the ISA hole. The guest can write those pages directly, so this did not weaken isolation, but the devices enforced less than the layout states. The first commit adds guest memory views, which admit only the accesses that lie wholly inside a set of page-aligned ranges and refuse any other before touching memory, on every access path, page locks included, while sharing the mappings of the memory that they restrict, so that admitted accesses keep their zero-copy paths. The second makes a virtio queue check each descriptor's whole buffer, and each indirect table, against the device's memory before handing the chain to the device, and refuse the chain as malformed when the memory does not admit it, so that a device reads and writes none of a buffer that lies even partly outside the admitted ranges. Rings already lie in subranges that the memory refuses as a whole when a queue starts. The third lets an MMIO transport restrict its device to a set of ranges and report each refusal by setting DEVICE_NEEDS_RESET, with a configuration-change notification once the driver has set DRIVER_OK, as virtio 1.2 provides for a device in an error state. A refused ring fails DRIVER_OK and leaves DEVICE_NEEDS_RESET alone set. A reset clears the mark. The transport keeps the whole memory for the shared interrupt-status word. The fourth returns the RAM ranges of the microVM e820 map from the loader that builds it, and the fifth restricts every microVM virtio device to them: the layout's RAM, which after a restore includes the RAM that the restore activates, less the interrupt-status page and the ISA hole. The protocol vectors and built-in CPU profiles that nvx-rs copies are unchanged. Refs #554 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- openvmm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openvmm b/openvmm index 832d5bb48..bd2b27a2e 160000 --- a/openvmm +++ b/openvmm @@ -1 +1 @@ -Subproject commit 832d5bb48dadd2cc5221f2c8b8905e6b80d13d53 +Subproject commit bd2b27a2ef9339bd16692c93facb8d84952dc9f8 From 5d917731edd94a88649eb60dcb07f25ac0566b98 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Penna Date: Wed, 28 Oct 2026 17:18:05 -0700 Subject: [PATCH 2/3] doc: map the device DMA restriction in the OpenVMM roadmap Record the five commits that the previous commit pins as positions 355-359 of the microVM chain, and move the NVX pin to bd2b27a2e. Positions 355-359 restrict the DMA of the microVM virtio devices to the RAM ranges of the e820 map: guest memory views, the virtio queue's whole-buffer check, the MMIO transport's restriction and needs-reset report, the loader's e820 RAM ranges, and the microVM worker that applies them. Position 355 changes only guestmem, which no other commit of the chain changes, so it can go upstream on its own, as positions 350-352 can, and position 356 adds only the queue's check on top of it. Positions 357-359 build on the fork's shared interrupt-status transport, MP-table loader, and microVM worker; say so in the table's remarks. The pin is now 202 commits past the mapped tip. Positions 353 and 354 are no longer only a proposal: microsoft/openvmm#4775 merged them, so position 354, 832d5bb48, is the head of feature/microvm/dev. Say so in the scope, and name microsoft/openvmm#4794 as the proposal of positions 355-359. Refs #554 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- doc/openvmm-upstream-roadmap.md | 45 +++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/doc/openvmm-upstream-roadmap.md b/doc/openvmm-upstream-roadmap.md index 788d04b9a..4d1b670ec 100644 --- a/doc/openvmm-upstream-roadmap.md +++ b/doc/openvmm-upstream-roadmap.md @@ -9,21 +9,23 @@ - Mapped fork tip: `a0556d7d85ce1fff89f5b45a98f15c5c79cbb6fb`, position 157. The graph, PR summary, and commit mapping below cover positions 001-157 and the fixups at positions 334-340, 344, and 345. -- NVX's pinned OpenVMM revision: `832d5bb48dadd2cc5221f2c8b8905e6b80d13d53`, position 354. - Positions 353 and 354, which microsoft/openvmm#4775 proposes for `feature/microvm/dev`, are - two commits on position 352, `b92daa350`, the head of `feature/microvm/dev` since - microsoft/openvmm#4773 merged positions 350-352. Those are three commits on position 349, - `d2338ea22`, which microsoft/openvmm#4769 merged with position 348. Positions 348 and 349 are - two commits on position 347, `57d0a18b3`, which microsoft/openvmm#4767 merged with position - 346. Positions 346 and 347 are two commits on position 345, `e68871cc6`, which - microsoft/openvmm#4762 merged with position 344. Positions 344 and 345 are two commits on - position 343, `a12d9167f`, which microsoft/openvmm#4749 merged with positions 341 and 342. - Positions 341-343 are three commits on position 340, `2b681564d`, which microsoft/openvmm#4735 - merged with position 339. Positions 339 and 340 are two commits on position 338, `8a0d945ed`, - which microsoft/openvmm#4734 merged, and position 338 is one commit on `79a501b63`, the head - of the `feature/microvm/release/v2.3` branch of microsoft/openvmm. The pin is 197 commits past - the mapped tip on the same first-parent chain. Positions 158-333, 341-343, and 346-354 are not - yet assigned to PRs; see [Commits after the mapped tip](#commits-after-the-mapped-tip). +- NVX's pinned OpenVMM revision: `bd2b27a2ef9339bd16692c93facb8d84952dc9f8`, position 359. + Positions 355-359, which microsoft/openvmm#4794 proposes for `feature/microvm/dev`, are + five commits on position 354, `832d5bb48`, the head of `feature/microvm/dev` since + microsoft/openvmm#4775 merged positions 353 and 354. Those are two commits on position 352, + `b92daa350`, which microsoft/openvmm#4773 merged with positions 350 and 351. Positions + 350-352 are three commits on position 349, `d2338ea22`, which microsoft/openvmm#4769 merged + with position 348. Positions 348 and 349 are two commits on position 347, `57d0a18b3`, which + microsoft/openvmm#4767 merged with position 346. Positions 346 and 347 are two commits on + position 345, `e68871cc6`, which microsoft/openvmm#4762 merged with position 344. Positions + 344 and 345 are two commits on position 343, `a12d9167f`, which microsoft/openvmm#4749 + merged with positions 341 and 342. Positions 341-343 are three commits on position 340, + `2b681564d`, which microsoft/openvmm#4735 merged with position 339. Positions 339 and 340 are + two commits on position 338, `8a0d945ed`, which microsoft/openvmm#4734 merged, and position + 338 is one commit on `79a501b63`, the head of the `feature/microvm/release/v2.3` branch of + microsoft/openvmm. The pin is 202 commits past the mapped tip on the same first-parent chain. + Positions 158-333, 341-343, and 346-359 are not yet assigned to PRs; see + [Commits after the mapped tip](#commits-after-the-mapped-tip). - Upstream main: `22c0485be597f87a76771e1db03eaa823a685ffc` (2026-10-22), the fork base. ## Upstream status @@ -313,8 +315,8 @@ The physical branch is one first-parent chain: -> PR14 fixup [336] -> PR09 fixup [337] -> PR02 fixup [338] -> PR20 fixup [339] -> PR23 fixup [340] -> unassigned [341-343] -> PR18 fixups [344-345] - -> unassigned [346-354] - -> 832d5bb48 (NVX pin) + -> unassigned [346-359] + -> bd2b27a2e (NVX pin) ``` For upstream review, PR01-PR08 and PR14 can be rebased independently onto current upstream main, @@ -336,8 +338,8 @@ PR18's position 111. ## Commits after the mapped tip -The NVX pin extends the chain past position 157 without merges. Of the 197 later commits, -positions 158-333, 341-343, and 346-354 are not yet classified or assigned to PRs, positions +The NVX pin extends the chain past position 157 without merges. Of the 202 later commits, +positions 158-333, 341-343, and 346-359 are not yet classified or assigned to PRs, positions 334-337 are the fixups of the `feature/microvm/release/v2.3` rebase, position 338 is a PR02 fixup, positions 339 and 340 are PR20 and PR23 fixups, and positions 344 and 345 are PR18 fixups. @@ -389,6 +391,7 @@ This table groups them by topic in chain order; ranges are inclusive, as in the | 350-352 | `8c1772d83..b92daa350` | 3 | HTTP blob disks bound each request in time, retry the ones that fail transiently on a new connection, and show them in inspect, so that a network path that silently stops delivering a connection's packets no longer hangs a guest's disk read (microsoft/openvmm#4773) | | 353 | `057a2eaa6` | 1 | Test that the microVM virtio-fs device takes a dormant slot's state into the device of an aggregate of a directory and a file, which then saves the aggregate | | 354 | `832d5bb48` | 1 | A platform restore may bind an aggregate, `--mount-aggregate` with its children, policy paths, and owner mode, to the filesystem slot that the snapshot left dormant, validated as at a cold boot, while the slot's device and the captured command line stay as captured; other tiers keep binding only a `--mount` (microsoft/openvmm#4775) | +| 355-359 | `2607a7d55..bd2b27a2e` | 5 | microVM virtio devices reach only the RAM ranges of the e820 map: guest memory views that admit only a set of ranges, a virtio queue that refuses a descriptor unless its memory admits the whole buffer, an MMIO transport that restricts device DMA and marks a device that addresses other memory as needing reset, and the loader's e820 RAM ranges, to which every microVM device is restricted (microsoft/openvmm#4794) | Some of these commits change mapped work rather than add to it. Positions 246-250 remove the legacy microVM clock paths and change files that PR10 and PR17 also change. Position 252 makes @@ -401,6 +404,10 @@ position 293 restricted it. Assigning the later commits therefore means revisiting those PRs, not only appending new ones. Positions 350-352, by contrast, change only `disk_blob`, which upstream main and the fork base have alike and no other commit of the chain changes, so they can go upstream on their own. +Position 355 likewise changes only `guestmem`, which no other commit of the chain changes, so it +can go upstream on its own, and position 356 adds only the virtio queue's check on top of it. +Positions 357-359 build on the fork's virtio-mmio shared interrupt-status transport, MP-table +loader, and microVM worker. ## PR summary From 8457a9916f30211ff5e4c0613217ff496d8bb731 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Penna Date: Wed, 28 Oct 2026 14:54:31 -0700 Subject: [PATCH 3/3] doc: note that microVM devices refuse DMA outside RAM Section 2.3 requires that loader writes and DMA ranges lie wholly inside a RAM range of the e820 map and cross neither the MMIO aperture nor a reserved boot structure, but said nothing about who enforces it. The Linux direct loader always kept its writes inside RAM; with the pinned OpenVMM, the virtio devices now enforce the rule for DMA too. Note the enforcement after the requirement: each device reaches only the RAM ranges of the e820 map and the RAM that a restore activates beyond them, and refuses a queue whose rings, or a descriptor whose buffer, lies even partly outside them, as in the interrupt-status page, the ISA hole, or across the aperture. It reads and writes none of it, stops serving the queue, and sets DEVICE_NEEDS_RESET, notifying the driver through a configuration change once DRIVER_OK is set. A refused ring fails DRIVER_OK instead, leaving DEVICE_NEEDS_RESET alone set. A device reset clears the mark, and only the transports update the interrupt-status page. Fixes #554 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- doc/design/2.3-memory-layout.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/design/2.3-memory-layout.md b/doc/design/2.3-memory-layout.md index 080e729ec..f1277dee5 100644 --- a/doc/design/2.3-memory-layout.md +++ b/doc/design/2.3-memory-layout.md @@ -48,6 +48,18 @@ splits low and high RAM around the aperture, and never reports the aperture as RAM. Loader writes and DMA ranges must fit wholly inside a RAM range and may not cross the MMIO aperture or a reserved boot structure. +The Linux direct loader places its writes inside RAM, and the virtio devices +enforce the rule for DMA: each device reaches only the RAM ranges of the e820 +map and the RAM that a restore activates beyond them. A device refuses a queue +whose rings, or a descriptor whose buffer, lies even partly outside those +ranges, such as in the interrupt-status page, in the ISA hole, or across the +aperture. It reads and writes none of it, stops serving that queue, and sets +`DEVICE_NEEDS_RESET` in its status, sending a configuration-change +notification if the driver has set `DRIVER_OK`. A refused ring instead fails +`DRIVER_OK`: the device resets as for any queue that cannot start, and its +status holds `DEVICE_NEEDS_RESET` alone, without a notification. Only a device +reset clears the mark. The transports alone update the interrupt-status page. + ## 2.3.1 Memory Capacity Snapshot capture may declare an immutable RAM capacity at least as large as