Skip to content

Conversation

@XanClic
Copy link

@XanClic XanClic commented Dec 17, 2025

Summary of the PR

Update the vm-memory dependency to 0.18.0. This PR supersedes #378.

0.18.0 is a breaking change, first and foremost because it renames the GuestMemory trait to GuestMemoryBackend, replacing it with a new GuestMemory trait that can abstract not only physical but also virtual memory, but in turn has a limited interface and requires specifying the required permissions for any memory access.

(Luckily, most memory accesses use the Bytes trait, which already implicitly specifies the access mode by way of which method is used, e.g. load() vs. store().)

This PR first changes some calls to use the methods that will still be available:

  • check_range() instead of check_address()
  • Specifically for virtio_queue::descriptor_utils::{Reader, Writer}::new(): Do not resolve memory accesses through guest memory regions, just collect slices through get_slices()
  • For virtio_vsock::packet: Replace get_slice() by a helper function that calls get_slices() and returns an error if the given guest memory region maps to more than a single slice. This is not ideal: get_slice() has been removed to make users aware that guest memory regions may not always map to a single slice in their memory, especially for virtual memory, and this is just ignoring that. However, it shouldn’t be a regression, so support for this can be implemented later, I think. (Maybe via bounce buffers if the interface must stay compatible?)
  • get_host_address() is removed; we only need it for testing, so we can just use get_single_slice().as_ptr() there, basically.

Then it bumps the vm-memory version, at which point we need to:

  • Pass the required access permissions,
  • Deal with get_slices() returning a Result<Iterator, E> instead of a plain Iterator,
  • Get the bitmap type via GuestMemory::Bitmap instead of <GuestMemory::R as GuestMemoryRegion>::B, and
  • Make the verification code’s SingleRegionGuestMemory implement GuestMemoryBackend instead of GuestMemory.

Compatibility Note

Note that users should still be able to depend on vm-memory 0.17.2+, even with vm-virtio updating to 0.18.0. This is because 0.17.2 internally depends on 0.18.0 and just re-exports all symbols, just some under different names (i.e. GuestMemoryBackend as GuestMemory).

Requirements

Before submitting your PR, please make sure you addressed the following
requirements:

  • All commits in this PR have Signed-Off-By trailers (with
    git commit -s), and the commit message has max 60 characters for the
    summary and max 75 characters for each description line.
  • All added/changed functionality has a corresponding unit/integration
    test.
  • All added/changed public-facing functionality has entries in the "Upcoming
    Release" section of CHANGELOG.md (if no such section exists, please create one).
  • Any newly added unsafe code is properly documented.

To verify whether a given memory region is accessible, use
`check_range()` instead of `check_address()`:
- First, it just makes sense to check the full range instead of a single
  byte.  (There is no difference in the virtio-blk status byte case,
  though.)
- Second, vm-memory 0.18 has changed its `GuestMemory` type to a much
  more restricted interface so it can properly represent virtual memory.
  This new version only has `check_range()`, not `check_address()`, so
  switching to the former will facilitate updating our vm-memory
  dependency.

Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
There is no reason to go through the `GuestMemoryRegion` to get a slice
in guest memory, we can just use `GuestMemory::get_slice()` directly.

This is not least in preparation for a vm-memory update that makes
`GuestMemory` potentially represent virtual memory, in which case we
will no longer be able to easily translate memory addresses into
`GuestMemoryRegion`s.

Another change that will come with that is that `get_slice()` will be
removed in favor of an iterating `get_slices()`.  This would require us
replacing `.map()` with `.flat_map()`, but with us generating errors on
both iterator levels (in the `chain.readable()`/`chain.writable()`
iterator, and in the `.get_slices()` iterator), this is quite hard to
represent in this functional style.

So just use a `for .. in` loop with `.push_back()` into the `VecDeque`.
Given that none of our iterators has a `.size_hint()` implementation, it
doesn’t make a difference in performance anyway.

And while at it, we may as well already use `get_slices()` rather than
`get_slice()`.  (And similarly, push the slices in a `for .. in` loop
because there is no `Vec::try_extend()`.)

Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
vm-memory is deprecating `get_slice()` in favor of `get_slices()`.  Add
a helper function to virtio-vsock/src/packet.rs to translate a guest
memory range into a single slice, returning an error if the range is
fragmented.

This should not change anything for non-virtual guest memory (unless
requesting memory ranges across `GuestMemoryRegion` boundaries, which
should have always required handling scatter-gather slices), so I think
it is a reasonable band-aid for now.

To properly support fragmented virtual memory, `VsockPacket`’s interface
would need to be changed, removing `header_slice()` and `data_slice()`,
replaced by methods that return some form of scatter-gather lists for
both.

Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Add a function that retrieves a guest memory region’s base host pointer.
With vm-memory’s changes to `GuestMemory`, `.get_host_address()` is no
longer going to work.

(The `rx_tx` parameter is unused for now, but will be evaluated in a
follow-up patch to determine the necessary access permissions to get the
host slice.)

Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Like in virtio-vsock/src/packet.rs, add a `get_mem_ptr()` function in
the test module to replace `.get_host_address()`.

Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
@XanClic
Copy link
Author

XanClic commented Dec 17, 2025

Sorry, kani fails:

Check 4634: <vm_memory::guest_memory::GuestMemoryBackendSliceIterator<'_, queue::verification::SingleRegionGuestMemory> as std::iter::Iterator>::try_fold::<(), {closure@std::iter::Iterator::all::check<std::result::Result<vm_memory::VolatileSlice<'_>, vm_memory::GuestMemoryError>, {closure@<queue::verification::SingleRegionGuestMemory as vm_memory::GuestMemoryBackend>::check_range::{closure#0}}>::{closure#0}}, std::ops::ControlFlow<()>>.unwind.0
         - Status: FAILURE
         - Description: "unwinding assertion loop 0"
         - Location: ../../../../runner/.rustup/toolchains/nightly-2025-08-06-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2425:9 in function <vm_memory::guest_memory::GuestMemoryBackendSliceIterator<'_, queue::verification::SingleRegionGuestMemory> as std::iter::Iterator>::try_fold::<(), {closure@std::iter::Iterator::all::check<std::result::Result<vm_memory::VolatileSlice<'_>, vm_memory::GuestMemoryError>, {closure@<queue::verification::SingleRegionGuestMemory as vm_memory::GuestMemoryBackend>::check_range::{closure#0}}>::{closure#0}}, std::ops::ControlFlow<()>>

I’ll try to find out how to fix this, but probably only at the start of next year. I’m not really sure whether it can even be fixed inside of vm-virtio alone.

As far as I understand so far, it doesn’t seem to be anything in the GuestMemoryBackendSliceIterator itself, but just the fact that it is an iterator in the first place. That is, even if I make <GuestMemoryBackendSliceIterator as Iterator>::next() really simple so that it’s just the same as get_slice(), it still fails:

fn next(&mut self) -> Option<Self::Item> {
    if self.count == 0 {
        return None;
    }

    let count = self.count;
    self.count = 0;
    Some(
        self.mem
            .to_region_addr(self.addr)
            .ok_or(Error::InvalidGuestAddress(self.addr))
            .and_then(|(r, addr)| r.get_slice(addr, count))
    )
}

But limiting check_range() to a single element makes it work:

fn check_range(&self, base: GuestAddress, len: usize) -> bool {                    
    // get_slices() ensures that if no error happens, the cumulative length of all slices     
    // equal `len`.                                                                
    self.get_slices(base, len).take(1).all(|r| r.is_ok())
}

With take(2), it fails again, regardless of whether it’s the original GuestMemoryBackendSliceIterator implementation, or the simplified one above. So it just seems to dislike iterating as a whole, regardless of what the iterator does.

@stefano-garzarella
Copy link
Member

I’ll try to find out how to fix this, but probably only at the start of next year. I’m not really sure whether it can even be fixed inside of vm-virtio alone.

Don't worry at all, take your time, and thank you very much for this PR!
CCing @MatiasVara @priyasiddharth for an help on kani proof.

The main change is that `GuestMemory` can now handle virtual memory,
which requires passing the needed access permissions.

The previous `GuestMemory` is now called `GuestMemoryBackend`, so we
need to use that in the kani verification code.  We also need to
override the provided `check_range()` method because of some problem
with iterating over the `get_slices()` result.

As for getting the memory’s bitmap type, we need to use
`GuestMemory::Bitmap` instead of going through the region type.

Finally, there is no longer a `GuestMemory::get_slice()` (only
`get_slices()`), but the previous commits have already prepared for
that.

Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
@XanClic
Copy link
Author

XanClic commented Dec 17, 2025

Fixed it (I hope it’s acceptable) by overriding the provided check_range() method: get_slices() will only ever return a single slice, because it’s physical memory and there is only a single region, so we can assert that and check that slice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants