diff --git a/block/src/lib.rs b/block/src/lib.rs index 288db3fbf..b6c083cef 100644 --- a/block/src/lib.rs +++ b/block/src/lib.rs @@ -70,7 +70,11 @@ use crate::vhdx::VhdxError; const SECTOR_SHIFT: u8 = 9; pub const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT; -/// Field offsets within `struct virtio_blk_discard_write_zeroes`. +/// Maximum number of segments per DISCARD or WRITE_ZEROES request. +pub const MAX_DISCARD_WRITE_ZEROES_SEG: u32 = 1; + +/// Size and field offsets within `struct virtio_blk_discard_write_zeroes`. +const DISCARD_WZ_SEG_SIZE: u32 = mem::size_of::() as u32; const DISCARD_WZ_SECTOR_OFFSET: u64 = mem::offset_of!(virtio_blk_discard_write_zeroes, sector) as u64; const DISCARD_WZ_NUM_SECTORS_OFFSET: u64 = @@ -105,6 +109,8 @@ pub enum Error { RawFileError(#[source] std::io::Error), #[error("The requested operation does not support multiple descriptors")] TooManyDescriptors, + #[error("Request contains too many segments")] + TooManySegments, #[error("Failure in vhdx")] VhdxError(#[source] VhdxError), } @@ -591,9 +597,12 @@ impl Request { return Err(ExecuteError::BadRequest(Error::TooManyDescriptors)); }; - if data_len < 16 { + if data_len < DISCARD_WZ_SEG_SIZE { return Err(ExecuteError::BadRequest(Error::DescriptorLengthTooSmall)); } + if data_len > DISCARD_WZ_SEG_SIZE * MAX_DISCARD_WRITE_ZEROES_SEG { + return Err(ExecuteError::BadRequest(Error::TooManySegments)); + } let mut discard_sector = [0u8; 8]; let mut discard_num_sectors = [0u8; 4]; @@ -630,9 +639,12 @@ impl Request { return Err(ExecuteError::BadRequest(Error::TooManyDescriptors)); }; - if data_len < 16 { + if data_len < DISCARD_WZ_SEG_SIZE { return Err(ExecuteError::BadRequest(Error::DescriptorLengthTooSmall)); } + if data_len > DISCARD_WZ_SEG_SIZE * MAX_DISCARD_WRITE_ZEROES_SEG { + return Err(ExecuteError::BadRequest(Error::TooManySegments)); + } let mut wz_sector = [0u8; 8]; let mut wz_num_sectors = [0u8; 4]; diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index edd1327f4..97d7c58c1 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -23,7 +23,8 @@ use block::disk_file::DiskBackend; use block::error::BlockError; use block::fcntl::{LockError, LockGranularity, LockGranularityChoice, LockType, get_lock_state}; use block::{ - ExecuteAsync, ExecuteError, Request, RequestType, VirtioBlockConfig, build_serial, fcntl, + ExecuteAsync, ExecuteError, MAX_DISCARD_WRITE_ZEROES_SEG, Request, RequestType, + VirtioBlockConfig, build_serial, fcntl, }; use event_monitor::event; use log::{debug, error, info, warn}; @@ -829,12 +830,12 @@ impl Block { if avail_features & (1u64 << VIRTIO_BLK_F_WRITE_ZEROES) != 0 { config.max_write_zeroes_sectors = u32::MAX; - config.max_write_zeroes_seg = 1; + config.max_write_zeroes_seg = MAX_DISCARD_WRITE_ZEROES_SEG; config.write_zeroes_may_unmap = if discard_supported { 1 } else { 0 }; } if avail_features & (1u64 << VIRTIO_BLK_F_DISCARD) != 0 { config.max_discard_sectors = u32::MAX; - config.max_discard_seg = 1; + config.max_discard_seg = MAX_DISCARD_WRITE_ZEROES_SEG; config.discard_sector_alignment = (logical_block_size / SECTOR_SIZE) as u32; }