mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
block: Validate segment count for DISCARD and WRITE_ZEROES requests
Split the data length check into two conditions: - reject descriptors shorter than one virtio_blk_discard_write_zeroes segment, and - reject payloads exceeding MAX_DISCARD_WRITE_ZEROES_SEG segments Previously only the minimum length was checked and extra segments were silently dropped. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
fc79d08d7d
commit
d3cad420a5
@@ -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::<virtio_blk_discard_write_zeroes>() 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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user