| // Portions Copyright 2019 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE-BSD-3-Clause file. |
| // |
| // Copyright (C) 2024 Red Hat, Inc. All rights reserved. |
| // |
| // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause |
| |
| use std::collections::VecDeque; |
| use std::io::{self, Read, Write}; |
| use std::mem::{size_of, MaybeUninit}; |
| use std::ops::Deref; |
| use std::ptr::copy_nonoverlapping; |
| use std::{cmp, result}; |
| |
| use crate::{DescriptorChain, Error}; |
| use vm_memory::bitmap::{BitmapSlice, WithBitmapSlice}; |
| use vm_memory::{ |
| Address, ByteValued, GuestMemory, GuestMemoryRegion, MemoryRegionAddress, VolatileSlice, |
| }; |
| |
| pub type Result<T> = result::Result<T, Error>; |
| |
| #[derive(Clone)] |
| struct DescriptorChainConsumer<'a, B> { |
| buffers: VecDeque<VolatileSlice<'a, B>>, |
| bytes_consumed: usize, |
| } |
| |
| impl<'a, B: BitmapSlice> DescriptorChainConsumer<'a, B> { |
| fn available_bytes(&self) -> usize { |
| // This is guaranteed not to overflow because the total length of the chain |
| // is checked during all creations of `DescriptorChainConsumer` (see |
| // `Reader::new()` and `Writer::new()`). |
| self.buffers |
| .iter() |
| .fold(0usize, |count, vs| count + vs.len()) |
| } |
| |
| fn bytes_consumed(&self) -> usize { |
| self.bytes_consumed |
| } |
| |
| /// Consumes at most `count` bytes from the `DescriptorChain`. Callers must provide a function |
| /// that takes a `&[VolatileSlice]` and returns the total number of bytes consumed. This |
| /// function guarantees that the combined length of all the slices in the `&[VolatileSlice]` is |
| /// less than or equal to `count`. |
| /// |
| /// # Errors |
| /// |
| /// If the provided function returns any error then no bytes are consumed from the buffer and |
| /// the error is returned to the caller. |
| fn consume<F>(&mut self, count: usize, f: F) -> io::Result<usize> |
| where |
| F: FnOnce(&[&VolatileSlice<B>]) -> io::Result<usize>, |
| { |
| let mut buflen = 0; |
| let mut bufs = Vec::with_capacity(self.buffers.len()); |
| for vs in &self.buffers { |
| if buflen >= count { |
| break; |
| } |
| |
| bufs.push(vs); |
| |
| let rem = count - buflen; |
| if rem < vs.len() { |
| buflen += rem; |
| } else { |
| buflen += vs.len(); |
| } |
| } |
| |
| if bufs.is_empty() { |
| return Ok(0); |
| } |
| |
| let bytes_consumed = f(&bufs)?; |
| |
| // This can happen if a driver tricks a device into reading/writing more data than |
| // fits in a `usize`. |
| let total_bytes_consumed = |
| self.bytes_consumed |
| .checked_add(bytes_consumed) |
| .ok_or_else(|| { |
| io::Error::new(io::ErrorKind::InvalidData, Error::DescriptorChainOverflow) |
| })?; |
| |
| let mut rem = bytes_consumed; |
| while let Some(vs) = self.buffers.pop_front() { |
| if rem < vs.len() { |
| // Split the slice and push the remainder back into the buffer list. Safe because we |
| // know that `rem` is not out of bounds due to the check and we checked the bounds |
| // on `vs` when we added it to the buffer list. |
| self.buffers.push_front(vs.offset(rem).unwrap()); |
| break; |
| } |
| |
| // No need for checked math because we know that `vs.size() <= rem`. |
| rem -= vs.len(); |
| } |
| |
| self.bytes_consumed = total_bytes_consumed; |
| |
| Ok(bytes_consumed) |
| } |
| |
| fn split_at(&mut self, offset: usize) -> Result<DescriptorChainConsumer<'a, B>> { |
| let mut rem = offset; |
| let pos = self.buffers.iter().position(|vs| { |
| if rem < vs.len() { |
| true |
| } else { |
| rem -= vs.len(); |
| false |
| } |
| }); |
| |
| if let Some(at) = pos { |
| let mut other = self.buffers.split_off(at); |
| |
| if rem > 0 { |
| // There must be at least one element in `other` because we checked |
| // its `size` value in the call to `position` above. |
| let front = other.pop_front().expect("empty VecDeque after split"); |
| self.buffers |
| .push_back(front.subslice(0, rem).map_err(Error::VolatileMemoryError)?); |
| other.push_front(front.offset(rem).map_err(Error::VolatileMemoryError)?); |
| } |
| |
| Ok(DescriptorChainConsumer { |
| buffers: other, |
| bytes_consumed: 0, |
| }) |
| } else if rem == 0 { |
| Ok(DescriptorChainConsumer { |
| buffers: VecDeque::new(), |
| bytes_consumed: 0, |
| }) |
| } else { |
| Err(Error::SplitOutOfBounds(offset)) |
| } |
| } |
| } |
| |
| /// Provides high-level interface over the sequence of memory regions |
| /// defined by readable descriptors in the descriptor chain. |
| /// |
| /// Note that virtio spec requires driver to place any device-writable |
| /// descriptors after any device-readable descriptors (2.6.4.2 in Virtio Spec v1.1). |
| /// Reader will skip iterating over descriptor chain when first writable |
| /// descriptor is encountered. |
| #[derive(Clone)] |
| pub struct Reader<'a, B = ()> { |
| buffer: DescriptorChainConsumer<'a, B>, |
| } |
| |
| impl<'a, B: BitmapSlice> Reader<'a, B> { |
| /// Construct a new Reader wrapper over `desc_chain`. |
| 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>, |
| 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>>>>()?; |
| Ok(Reader { |
| buffer: DescriptorChainConsumer { |
| buffers, |
| bytes_consumed: 0, |
| }, |
| }) |
| } |
| |
| /// Reads an object from the descriptor chain buffer. |
| pub fn read_obj<T: ByteValued>(&mut self) -> io::Result<T> { |
| let mut obj = MaybeUninit::<T>::uninit(); |
| |
| // SAFETY: `MaybeUninit` guarantees that the pointer is valid for |
| // `size_of::<T>()` bytes. |
| let buf = unsafe { |
| ::std::slice::from_raw_parts_mut(obj.as_mut_ptr() as *mut u8, size_of::<T>()) |
| }; |
| |
| self.read_exact(buf)?; |
| |
| // SAFETY: any type that implements `ByteValued` can be considered initialized |
| // even if it is filled with random data. |
| Ok(unsafe { obj.assume_init() }) |
| } |
| |
| /// Returns number of bytes available for reading. May return an error if the combined |
| /// lengths of all the buffers in the DescriptorChain would cause an integer overflow. |
| pub fn available_bytes(&self) -> usize { |
| self.buffer.available_bytes() |
| } |
| |
| /// Returns number of bytes already read from the descriptor chain buffer. |
| pub fn bytes_read(&self) -> usize { |
| self.buffer.bytes_consumed() |
| } |
| |
| /// Splits this `Reader` into two at the given offset in the `DescriptorChain` buffer. |
| /// After the split, `self` will be able to read up to `offset` bytes while the returned |
| /// `Reader` can read up to `available_bytes() - offset` bytes. Returns an error if |
| /// `offset > self.available_bytes()`. |
| pub fn split_at(&mut self, offset: usize) -> Result<Reader<'a, B>> { |
| self.buffer.split_at(offset).map(|buffer| Reader { buffer }) |
| } |
| } |
| |
| impl<'a, B: BitmapSlice> io::Read for Reader<'a, B> { |
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
| self.buffer.consume(buf.len(), |bufs| { |
| let mut rem = buf; |
| let mut total = 0; |
| for vs in bufs { |
| let copy_len = cmp::min(rem.len(), vs.len()); |
| |
| // SAFETY: Safe because we verify that we do not read outside |
| // of the slice's bound. The slice guard will only get dropped |
| // after the function returns. This will keep the pointer valid |
| // while reads are happening. |
| unsafe { |
| copy_nonoverlapping(vs.ptr_guard().as_ptr(), rem.as_mut_ptr(), copy_len); |
| } |
| rem = &mut rem[copy_len..]; |
| total += copy_len; |
| } |
| Ok(total) |
| }) |
| } |
| } |
| |
| /// Provides high-level interface over the sequence of memory regions |
| /// defined by writable descriptors in the descriptor chain. |
| /// |
| /// Note that virtio spec requires driver to place any device-writable |
| /// descriptors after any device-readable descriptors (2.6.4.2 in Virtio Spec v1.1). |
| /// Writer will start iterating the descriptors from the first writable one and will |
| /// assume that all following descriptors are writable. |
| #[derive(Clone)] |
| pub struct Writer<'a, B = ()> { |
| buffer: DescriptorChainConsumer<'a, B>, |
| } |
| |
| impl<'a, B: BitmapSlice> Writer<'a, B> { |
| /// Construct a new Writer wrapper over `desc_chain`. |
| 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>, |
| 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>>>>()?; |
| |
| Ok(Writer { |
| buffer: DescriptorChainConsumer { |
| buffers, |
| bytes_consumed: 0, |
| }, |
| }) |
| } |
| |
| /// Writes an object to the descriptor chain buffer. |
| pub fn write_obj<T: ByteValued>(&mut self, val: T) -> io::Result<()> { |
| self.write_all(val.as_slice()) |
| } |
| |
| /// Returns number of bytes available for writing. May return an error if the combined |
| /// lengths of all the buffers in the DescriptorChain would cause an overflow. |
| pub fn available_bytes(&self) -> usize { |
| self.buffer.available_bytes() |
| } |
| |
| /// Returns number of bytes already written to the descriptor chain buffer. |
| pub fn bytes_written(&self) -> usize { |
| self.buffer.bytes_consumed() |
| } |
| |
| /// Splits this `Writer` into two at the given offset in the `DescriptorChain` buffer. |
| /// After the split, `self` will be able to write up to `offset` bytes while the returned |
| /// `Writer` can write up to `available_bytes() - offset` bytes. Returns an error if |
| /// `offset > self.available_bytes()`. |
| pub fn split_at(&mut self, offset: usize) -> Result<Writer<'a, B>> { |
| self.buffer.split_at(offset).map(|buffer| Writer { buffer }) |
| } |
| } |
| |
| impl<'a, B: BitmapSlice> io::Write for Writer<'a, B> { |
| fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| self.buffer.consume(buf.len(), |bufs| { |
| let mut rem = buf; |
| let mut total = 0; |
| for vs in bufs { |
| let copy_len = cmp::min(rem.len(), vs.len()); |
| |
| // SAFETY: Safe because we ensure that we do not write over the |
| // slice's bounds. The slice guard will only get dropped after |
| // the function returns. This will keep the pointer valid while |
| // writes are happening. |
| unsafe { |
| copy_nonoverlapping(rem.as_ptr(), vs.ptr_guard_mut().as_ptr(), copy_len); |
| } |
| vs.bitmap().mark_dirty(0, copy_len); |
| rem = &rem[copy_len..]; |
| total += copy_len; |
| } |
| Ok(total) |
| }) |
| } |
| |
| fn flush(&mut self) -> io::Result<()> { |
| // Nothing to flush since the writes go straight into the buffer. |
| Ok(()) |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| use crate::{Descriptor, Queue, QueueOwnedT, QueueT}; |
| use vm_memory::{GuestAddress, GuestMemoryMmap, Le32}; |
| |
| use crate::mock::MockSplitQueue; |
| use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; |
| |
| const MAX_QUEUE_SIZE: u16 = 16; |
| |
| #[derive(Copy, Clone, PartialEq, Eq)] |
| pub enum DescriptorType { |
| Readable, |
| Writable, |
| } |
| |
| /// Test utility function to create a descriptor chain in guest memory. |
| pub fn create_descriptor_chain( |
| memory: &GuestMemoryMmap, |
| descriptor_array_addr: GuestAddress, |
| descriptors: Vec<(DescriptorType, u32)>, |
| spaces_between_regions: u32, |
| ) -> Result<DescriptorChain<&GuestMemoryMmap>> { |
| let descriptors_len = descriptors.len(); |
| let mut descs = vec![]; |
| |
| let queue = MockSplitQueue::create(memory, descriptor_array_addr, MAX_QUEUE_SIZE); |
| |
| let mut buffers_start_addr = queue.end(); |
| |
| for (index, (type_, size)) in descriptors.into_iter().enumerate() { |
| let mut flags = 0; |
| if let DescriptorType::Writable = type_ { |
| flags |= VRING_DESC_F_WRITE; |
| } |
| if index + 1 < descriptors_len { |
| flags |= VRING_DESC_F_NEXT; |
| } |
| |
| descs.push(Descriptor::new( |
| buffers_start_addr.raw_value(), |
| size, |
| flags as u16, |
| (index + 1) as u16, |
| )); |
| |
| let offset = size + spaces_between_regions; |
| buffers_start_addr = buffers_start_addr |
| .checked_add(u64::from(offset)) |
| .ok_or(Error::InvalidChain)?; |
| } |
| |
| queue.build_desc_chain(&descs).unwrap(); |
| |
| let avail_ring = queue.avail_addr(); |
| |
| let mut queue: Queue = Queue::new(MAX_QUEUE_SIZE).unwrap(); |
| queue |
| .try_set_desc_table_address(descriptor_array_addr) |
| .unwrap(); |
| queue.try_set_avail_ring_address(avail_ring).unwrap(); |
| queue.set_ready(true); |
| |
| let chain = queue.iter(memory).unwrap().next().unwrap(); |
| |
| Ok(chain.clone()) |
| } |
| |
| #[test] |
| fn reader_test_inv_desc_addr() { |
| let memory: GuestMemoryMmap = |
| GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), 0x1000)]).unwrap(); |
| |
| let queue = MockSplitQueue::create(&memory, GuestAddress(0x0), MAX_QUEUE_SIZE); |
| |
| // set addr out of memory |
| let descriptor = Descriptor::new(0x1001, 1, 0, 1_u16); |
| queue.build_desc_chain(&[descriptor]).unwrap(); |
| |
| let avail_ring = queue.avail_addr(); |
| |
| let mut queue: Queue = Queue::new(MAX_QUEUE_SIZE).unwrap(); |
| queue.try_set_desc_table_address(GuestAddress(0x0)).unwrap(); |
| queue.try_set_avail_ring_address(avail_ring).unwrap(); |
| queue.set_ready(true); |
| |
| let chain = queue.iter(&memory).unwrap().next().unwrap(); |
| |
| assert!(Reader::new(&memory, chain).is_err()); |
| } |
| |
| #[test] |
| fn reader_test_simple_chain() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![ |
| (Readable, 8), |
| (Readable, 16), |
| (Readable, 18), |
| (Readable, 64), |
| ], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); |
| assert_eq!(reader.available_bytes(), 106); |
| assert_eq!(reader.bytes_read(), 0); |
| |
| let mut buffer = [0_u8; 64]; |
| if let Err(e) = reader.read_exact(&mut buffer) { |
| panic!("read_exact should not fail here: {:?}", e); |
| } |
| |
| assert_eq!(reader.available_bytes(), 42); |
| assert_eq!(reader.bytes_read(), 64); |
| |
| match reader.read(&mut buffer) { |
| Err(e) => panic!("read should not fail here: {:?}", e), |
| Ok(length) => assert_eq!(length, 42), |
| } |
| |
| assert_eq!(reader.available_bytes(), 0); |
| assert_eq!(reader.bytes_read(), 106); |
| } |
| |
| #[test] |
| fn writer_test_simple_chain() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![ |
| (Writable, 8), |
| (Writable, 16), |
| (Writable, 18), |
| (Writable, 64), |
| ], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); |
| assert_eq!(writer.available_bytes(), 106); |
| assert_eq!(writer.bytes_written(), 0); |
| |
| let buffer = [0_u8; 64]; |
| if let Err(e) = writer.write_all(&buffer) { |
| panic!("write_all should not fail here: {:?}", e); |
| } |
| |
| assert_eq!(writer.available_bytes(), 42); |
| assert_eq!(writer.bytes_written(), 64); |
| |
| match writer.write(&buffer) { |
| Err(e) => panic!("write should not fail here {:?}", e), |
| Ok(length) => assert_eq!(length, 42), |
| } |
| |
| assert_eq!(writer.available_bytes(), 0); |
| assert_eq!(writer.bytes_written(), 106); |
| } |
| |
| #[test] |
| fn reader_test_incompatible_chain() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain(&memory, GuestAddress(0x0), vec![(Writable, 8)], 0) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); |
| assert_eq!(reader.available_bytes(), 0); |
| assert_eq!(reader.bytes_read(), 0); |
| |
| assert!(reader.read_obj::<u8>().is_err()); |
| |
| assert_eq!(reader.available_bytes(), 0); |
| assert_eq!(reader.bytes_read(), 0); |
| } |
| |
| #[test] |
| fn writer_test_incompatible_chain() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain(&memory, GuestAddress(0x0), vec![(Readable, 8)], 0) |
| .expect("create_descriptor_chain failed"); |
| let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); |
| assert_eq!(writer.available_bytes(), 0); |
| assert_eq!(writer.bytes_written(), 0); |
| |
| assert!(writer.write_obj(0u8).is_err()); |
| |
| assert_eq!(writer.available_bytes(), 0); |
| assert_eq!(writer.bytes_written(), 0); |
| } |
| |
| #[test] |
| fn reader_writer_shared_chain() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![ |
| (Readable, 16), |
| (Readable, 16), |
| (Readable, 96), |
| (Writable, 64), |
| (Writable, 1), |
| (Writable, 3), |
| ], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain.clone()).expect("failed to create Reader"); |
| let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); |
| |
| assert_eq!(reader.bytes_read(), 0); |
| assert_eq!(writer.bytes_written(), 0); |
| |
| let mut buffer = Vec::with_capacity(200); |
| |
| assert_eq!( |
| reader |
| .read_to_end(&mut buffer) |
| .expect("read should not fail here"), |
| 128 |
| ); |
| |
| // The writable descriptors are only 68 bytes long. |
| writer |
| .write_all(&buffer[..68]) |
| .expect("write should not fail here"); |
| |
| assert_eq!(reader.available_bytes(), 0); |
| assert_eq!(reader.bytes_read(), 128); |
| assert_eq!(writer.available_bytes(), 0); |
| assert_eq!(writer.bytes_written(), 68); |
| } |
| |
| #[test] |
| fn reader_writer_shattered_object() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let secret: Le32 = 0x1234_5678.into(); |
| |
| // Create a descriptor chain with memory regions that are properly separated. |
| let chain_writer = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![(Writable, 1), (Writable, 1), (Writable, 1), (Writable, 1)], |
| 123, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut writer = Writer::new(&memory, chain_writer).expect("failed to create Writer"); |
| if let Err(e) = writer.write_obj(secret) { |
| panic!("write_obj should not fail here: {:?}", e); |
| } |
| |
| // Now create new descriptor chain pointing to the same memory and try to read it. |
| let chain_reader = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![(Readable, 1), (Readable, 1), (Readable, 1), (Readable, 1)], |
| 123, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain_reader).expect("failed to create Reader"); |
| match reader.read_obj::<Le32>() { |
| Err(e) => panic!("read_obj should not fail here: {:?}", e), |
| Ok(read_secret) => assert_eq!(read_secret, secret), |
| } |
| } |
| |
| #[test] |
| fn reader_unexpected_eof() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![(Readable, 256), (Readable, 256)], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| |
| let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); |
| |
| let mut buf = vec![0; 1024]; |
| |
| assert_eq!( |
| reader |
| .read_exact(&mut buf[..]) |
| .expect_err("read more bytes than available") |
| .kind(), |
| io::ErrorKind::UnexpectedEof |
| ); |
| } |
| |
| #[test] |
| fn split_border() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![ |
| (Readable, 16), |
| (Readable, 16), |
| (Readable, 96), |
| (Writable, 64), |
| (Writable, 1), |
| (Writable, 3), |
| ], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain.clone()).expect("failed to create Reader"); |
| |
| let other = reader.split_at(32).expect("failed to split Reader"); |
| assert_eq!(reader.available_bytes(), 32); |
| assert_eq!(other.available_bytes(), 96); |
| |
| let mut writer = Writer::new(&memory, chain.clone()).expect("failed to create Writer"); |
| let other = writer.split_at(64).expect("failed to split Writer"); |
| assert_eq!(writer.available_bytes(), 64); |
| assert_eq!(other.available_bytes(), 4); |
| } |
| |
| #[test] |
| fn split_middle() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![ |
| (Readable, 16), |
| (Readable, 16), |
| (Readable, 96), |
| (Writable, 64), |
| (Writable, 1), |
| (Writable, 3), |
| ], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); |
| |
| let other = reader.split_at(24).expect("failed to split Reader"); |
| assert_eq!(reader.available_bytes(), 24); |
| assert_eq!(other.available_bytes(), 104); |
| } |
| |
| #[test] |
| fn split_end() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![ |
| (Readable, 16), |
| (Readable, 16), |
| (Readable, 96), |
| (Writable, 64), |
| (Writable, 1), |
| (Writable, 3), |
| ], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); |
| |
| let other = reader.split_at(128).expect("failed to split Reader"); |
| assert_eq!(reader.available_bytes(), 128); |
| assert_eq!(other.available_bytes(), 0); |
| } |
| |
| #[test] |
| fn split_beginning() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![ |
| (Readable, 16), |
| (Readable, 16), |
| (Readable, 96), |
| (Writable, 64), |
| (Writable, 1), |
| (Writable, 3), |
| ], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); |
| |
| let other = reader.split_at(0).expect("failed to split Reader"); |
| assert_eq!(reader.available_bytes(), 0); |
| assert_eq!(other.available_bytes(), 128); |
| } |
| |
| #[test] |
| fn split_outofbounds() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![ |
| (Readable, 16), |
| (Readable, 16), |
| (Readable, 96), |
| (Writable, 64), |
| (Writable, 1), |
| (Writable, 3), |
| ], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); |
| |
| if reader.split_at(256).is_ok() { |
| panic!("successfully split Reader with out of bounds offset"); |
| } |
| } |
| |
| #[test] |
| fn read_full() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![(Readable, 16), (Readable, 16), (Readable, 16)], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); |
| |
| let mut buf = [0u8; 64]; |
| assert_eq!( |
| reader.read(&mut buf[..]).expect("failed to read to buffer"), |
| 48 |
| ); |
| } |
| |
| #[test] |
| fn write_full() { |
| use DescriptorType::*; |
| |
| let memory_start_addr = GuestAddress(0x0); |
| let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap(); |
| |
| let chain = create_descriptor_chain( |
| &memory, |
| GuestAddress(0x0), |
| vec![(Writable, 16), (Writable, 16), (Writable, 16)], |
| 0, |
| ) |
| .expect("create_descriptor_chain failed"); |
| let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); |
| |
| let buf = [0xdeu8; 64]; |
| assert_eq!( |
| writer.write(&buf[..]).expect("failed to write from buffer"), |
| 48 |
| ); |
| |
| assert!(writer.flush().is_ok()); |
| } |
| } |