Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ lto = true
codegen-units = 1

[workspace.dependencies]
vm-memory = "0.17.1"
vm-memory = "0.18.0"
vmm-sys-util = "0.15.0"
2 changes: 1 addition & 1 deletion fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ memfd = "0.6.3"
virtio-queue = { path = "../virtio-queue", features = ["test-utils"] }
virtio-vsock = { path = "../virtio-vsock" }
virtio-queue-ser = { path = "../virtio-queue-ser" }
vm-memory = { version = "0.17.1", features = ["backend-mmap", "backend-atomic"] }
vm-memory = { version = "0.18.0", features = ["backend-mmap", "backend-atomic"] }
common = { path = "common" }
virtio-blk = { path = "../virtio-blk", features = ["backend-stdio"] }

Expand Down
2 changes: 1 addition & 1 deletion fuzz/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ virtio-queue = { path = "../../virtio-queue", features = ["test-utils"] }
virtio-vsock = { path = "../../virtio-vsock" }
virtio-queue-ser = { path = "../../virtio-queue-ser" }
virtio-blk = { path = "../../virtio-blk" }
vm-memory = { version = "0.17.1", features = ["backend-mmap", "backend-atomic"] }
vm-memory = { version = "0.18.0", features = ["backend-mmap", "backend-atomic"] }
50 changes: 44 additions & 6 deletions fuzz/common/src/vsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ mod tests {
use virtio_queue::desc::RawDescriptor;
use virtio_queue::mock::MockSplitQueue;
use virtio_vsock::packet::VsockPacket;
use vm_memory::{Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
use vm_memory::{Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, Permissions};

// Random values to be used by the tests for the header fields.
const SRC_CID: u64 = 1;
Expand All @@ -199,13 +199,47 @@ mod tests {
const HEADER_WRITE_ADDR: u64 = 0x100;
const DATA_WRITE_ADDR: u64 = 0x1000;

/// For `get_mem_ptr()`: Whether we access the RX or TX ring.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum RxTx {
/// Receive ring
Rx,
/// Transmission ring
Tx,
}

/// Return a host pointer to the slice at `[addr, addr + length)`. Use this only for
/// comparison in `assert_eq!()`.
fn get_mem_ptr<M: GuestMemory>(
mem: &M,
addr: GuestAddress,
length: usize,
rx_tx: RxTx,
) -> *const u8 {
let access = match rx_tx {
RxTx::Rx => Permissions::Write,
RxTx::Tx => Permissions::Read,
};

assert!(length > 0);
let slice = mem
.get_slices(addr, length, access)
.unwrap()
.next()
.unwrap()
.unwrap();
assert_eq!(slice.len(), length, "Fragmented guest memory area");
slice.ptr_guard().as_ptr()
}

// We are generating the same operations for packets created from either RX or TX.
// Because we need as a first function the write to memory, we are passing the functions as
// both an input & output parameter even though this is typically an anti-pattern.
fn create_basic_vsock_packet_ops<B: vm_memory::bitmap::BitmapSlice>(
packet: &mut VsockPacket<B>,
mem: &GuestMemoryMmap,
functions: &mut Vec<VsockFunction>,
rx_tx: RxTx,
) {
// We are actually calling the functions that we want the fuzzer to call to validate
// the test case. To easily track the functions and their order, we just add them to
Expand All @@ -214,15 +248,19 @@ mod tests {
functions.push(VsockFunction::HeaderSlice);
assert_eq!(
header_slice.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(HEADER_WRITE_ADDR))
.unwrap()
get_mem_ptr(
mem,
GuestAddress(HEADER_WRITE_ADDR),
header_slice.len(),
rx_tx
)
);

let data_slice = packet.data_slice().unwrap();
functions.push(VsockFunction::DataSlice);
assert_eq!(
data_slice.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(DATA_WRITE_ADDR)).unwrap()
get_mem_ptr(mem, GuestAddress(DATA_WRITE_ADDR), data_slice.len(), rx_tx)
);

packet.set_src_cid(SRC_CID);
Expand Down Expand Up @@ -338,7 +376,7 @@ mod tests {

let mut packet =
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
create_basic_vsock_packet_ops(&mut packet, &mem, &mut functions);
create_basic_vsock_packet_ops(&mut packet, &mem, &mut functions, RxTx::Tx);
let vsock_fuzz_input = VsockInput {
functions,
descriptors,
Expand Down Expand Up @@ -389,7 +427,7 @@ mod tests {
let mut packet =
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
let mut functions = Vec::new();
create_basic_vsock_packet_ops(&mut packet, &mem, &mut functions);
create_basic_vsock_packet_ops(&mut packet, &mem, &mut functions, RxTx::Rx);
let vsock_fuzz_input = VsockInput {
functions,
descriptors,
Expand Down
12 changes: 8 additions & 4 deletions virtio-blk/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
//! approach.

use std::fmt::{self, Display};
use std::mem::size_of;
use std::ops::Deref;
use std::result;

Expand All @@ -36,7 +37,7 @@ use virtio_queue::{
desc::{split::Descriptor as SplitDescriptor, RawDescriptor},
DescriptorChain,
};
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError};
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, Permissions};

/// Block request parsing errors.
#[derive(Debug)]
Expand Down Expand Up @@ -179,9 +180,12 @@ impl Request {

// Check that the address of the status is valid in guest memory.
// We will write an u8 status here after executing the request.
let _ = mem.check_address(desc.addr()).ok_or_else(|| {
Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(desc.addr()))
})?;
if !mem.check_range(desc.addr(), size_of::<u8>(), Permissions::Write) {
return Err(Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(
desc.addr(),
)));
}

Ok(())
}

Expand Down
2 changes: 2 additions & 0 deletions virtio-queue-ser/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

## Changed

- Updated vm-memory from 0.17.1 to 0.18.0

## Fixed

# v0.14.0
Expand Down
2 changes: 2 additions & 0 deletions virtio-queue/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

## Changed

- Updated vm-memory from 0.17.1 to 0.18.0

## Fixed

# v0.17.0
Expand Down
6 changes: 3 additions & 3 deletions virtio-queue/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::mem::size_of;
use std::ops::Deref;

use vm_memory::bitmap::{BitmapSlice, WithBitmapSlice};
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryRegion};
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory};

use crate::{desc::split::Descriptor, Error, Reader, Writer};
use virtio_bindings::bindings::virtio_ring::VRING_DESC_ALIGN_SIZE;
Expand Down Expand Up @@ -92,7 +92,7 @@ where
pub fn writer<'a, B: BitmapSlice>(self, mem: &'a M::Target) -> Result<Writer<'a, B>, Error>
where
M::Target: Sized,
<<M::Target as GuestMemory>::R as GuestMemoryRegion>::B: WithBitmapSlice<'a, S = B>,
<M::Target as GuestMemory>::Bitmap: WithBitmapSlice<'a, S = B>,
{
Writer::new(mem, self).map_err(|_| Error::InvalidChain)
}
Expand All @@ -101,7 +101,7 @@ where
pub fn reader<'a, B: BitmapSlice>(self, mem: &'a M::Target) -> Result<Reader<'a, B>, Error>
where
M::Target: Sized,
<<M::Target as GuestMemory>::R as GuestMemoryRegion>::B: WithBitmapSlice<'a, S = B>,
<M::Target as GuestMemory>::Bitmap: WithBitmapSlice<'a, S = B>,
{
Reader::new(mem, self).map_err(|_| Error::InvalidChain)
}
Expand Down
89 changes: 39 additions & 50 deletions virtio-queue/src/descriptor_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ use std::{cmp, result};

use crate::{DescriptorChain, Error};
use vm_memory::bitmap::{BitmapSlice, WithBitmapSlice};
use vm_memory::{
Address, ByteValued, GuestMemory, GuestMemoryRegion, MemoryRegionAddress, VolatileSlice,
};
use vm_memory::{ByteValued, GuestMemory, Permissions, VolatileSlice};

pub type Result<T> = result::Result<T, Error>;

Expand Down Expand Up @@ -160,33 +158,29 @@ impl<'a, B: BitmapSlice> Reader<'a, B> {
pub fn new<M, T>(mem: &'a M, desc_chain: DescriptorChain<T>) -> Result<Reader<'a, B>>
where
M: GuestMemory,
<<M as GuestMemory>::R as GuestMemoryRegion>::B: WithBitmapSlice<'a, S = B>,
<M as GuestMemory>::Bitmap: WithBitmapSlice<'a, S = B>,
T: Deref,
T::Target: GuestMemory + Sized,
{
let mut total_len: usize = 0;
let buffers = desc_chain
.readable()
.map(|desc| {
// Verify that summing the descriptor sizes does not overflow.
// This can happen if a driver tricks a device into reading more data than
// fits in a `usize`.
total_len = total_len
.checked_add(desc.len() as usize)
.ok_or(Error::DescriptorChainOverflow)?;

let region = mem
.find_region(desc.addr())
.ok_or(Error::FindMemoryRegion)?;
let offset = desc
.addr()
.checked_sub(region.start_addr().raw_value())
.unwrap();
region
.get_slice(MemoryRegionAddress(offset.raw_value()), desc.len() as usize)
.map_err(Error::GuestMemoryError)
})
.collect::<Result<VecDeque<VolatileSlice<'a, B>>>>()?;
let mut buffers = VecDeque::<VolatileSlice<'a, B>>::new();

for desc in desc_chain.readable() {
// Verify that summing the descriptor sizes does not overflow.
// This can happen if a driver tricks a device into reading more data than
// fits in a `usize`.
total_len = total_len
.checked_add(desc.len() as usize)
.ok_or(Error::DescriptorChainOverflow)?;

let slices = mem
.get_slices(desc.addr(), desc.len() as usize, Permissions::Read)
.map_err(Error::GuestMemoryError)?;
for slice in slices {
buffers.push_back(slice.map_err(Error::GuestMemoryError)?);
}
}

Ok(Reader {
buffer: DescriptorChainConsumer {
buffers,
Expand Down Expand Up @@ -272,33 +266,28 @@ impl<'a, B: BitmapSlice> Writer<'a, B> {
pub fn new<M, T>(mem: &'a M, desc_chain: DescriptorChain<T>) -> Result<Writer<'a, B>>
where
M: GuestMemory,
<<M as GuestMemory>::R as GuestMemoryRegion>::B: WithBitmapSlice<'a, S = B>,
<M as GuestMemory>::Bitmap: WithBitmapSlice<'a, S = B>,
T: Deref,
T::Target: GuestMemory + Sized,
{
let mut total_len: usize = 0;
let buffers = desc_chain
.writable()
.map(|desc| {
// Verify that summing the descriptor sizes does not overflow.
// This can happen if a driver tricks a device into writing more data than
// fits in a `usize`.
total_len = total_len
.checked_add(desc.len() as usize)
.ok_or(Error::DescriptorChainOverflow)?;

let region = mem
.find_region(desc.addr())
.ok_or(Error::FindMemoryRegion)?;
let offset = desc
.addr()
.checked_sub(region.start_addr().raw_value())
.unwrap();
region
.get_slice(MemoryRegionAddress(offset.raw_value()), desc.len() as usize)
.map_err(Error::GuestMemoryError)
})
.collect::<Result<VecDeque<VolatileSlice<'a, B>>>>()?;
let mut buffers = VecDeque::<VolatileSlice<'a, B>>::new();

for desc in desc_chain.writable() {
// Verify that summing the descriptor sizes does not overflow.
// This can happen if a driver tricks a device into writing more data than
// fits in a `usize`.
total_len = total_len
.checked_add(desc.len() as usize)
.ok_or(Error::DescriptorChainOverflow)?;

let slices = mem
.get_slices(desc.addr(), desc.len() as usize, Permissions::Write)
.map_err(Error::GuestMemoryError)?;
for slice in slices {
buffers.push_back(slice.map_err(Error::GuestMemoryError)?);
}
}

Ok(Writer {
buffer: DescriptorChainConsumer {
Expand Down Expand Up @@ -369,7 +358,7 @@ mod tests {
desc::{split::Descriptor as SplitDescriptor, RawDescriptor},
Queue, QueueOwnedT, QueueT,
};
use vm_memory::{GuestAddress, GuestMemoryMmap, Le32};
use vm_memory::{Address, GuestAddress, GuestMemoryMmap, Le32};

use crate::mock::MockSplitQueue;
use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE};
Expand Down
23 changes: 7 additions & 16 deletions virtio-queue/src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::num::Wrapping;
use std::ops::Deref;
use std::sync::atomic::{fence, Ordering};

use vm_memory::{Address, Bytes, GuestAddress, GuestMemory};
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, Permissions};

use crate::defs::{
DEFAULT_AVAIL_RING_ADDR, DEFAULT_DESC_TABLE_ADDR, DEFAULT_USED_RING_ADDR,
Expand Down Expand Up @@ -313,32 +313,23 @@ impl QueueT for Queue {
if !self.ready {
error!("attempt to use virtio queue that is not marked ready");
false
} else if desc_table
.checked_add(desc_table_size)
.is_none_or(|v| !mem.address_in_range(v))
{
} else if !mem.check_range(desc_table, desc_table_size as usize, Permissions::Read) {
error!(
"virtio queue descriptor table goes out of bounds: start:0x{:08x} size:0x{:08x}",
"virtio queue descriptor table is not accessible: start:0x{:08x} size:0x{:08x}",
desc_table.raw_value(),
desc_table_size
);
false
} else if avail_ring
.checked_add(avail_ring_size)
.is_none_or(|v| !mem.address_in_range(v))
{
} else if !mem.check_range(avail_ring, avail_ring_size as usize, Permissions::Read) {
error!(
"virtio queue available ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
"virtio queue available ring is not accessible: start:0x{:08x} size:0x{:08x}",
avail_ring.raw_value(),
avail_ring_size
);
false
} else if used_ring
.checked_add(used_ring_size)
.is_none_or(|v| !mem.address_in_range(v))
{
} else if !mem.check_range(used_ring, used_ring_size as usize, Permissions::Write) {
error!(
"virtio queue used ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
"virtio queue used ring is not accessible: start:0x{:08x} size:0x{:08x}",
used_ring.raw_value(),
used_ring_size
);
Expand Down
Loading