mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
The sync I/O worker only checked that the operation offset did not start past the end of the virtual disk (offset >= size) - did not verify that the operation end (offset + len) stays within bounds. A read or write that started inside the image but extended beyond the logical size was silently passed to the raw backend. The async io_uring worker already had the correct check (offset + len > size with overflow protection). I extracted it into a shared helper in worker/common.rs and reused inside the sync path to eliminate duplication and close the gap. Fixes #8311 Signed-off-by: Alexander Lvov <alexander.lvov.git@gmail.com>
39 lines
1.1 KiB
Rust
39 lines
1.1 KiB
Rust
// Copyright 2026 The Cloud Hypervisor Authors. All rights reserved.
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
use std::io;
|
|
|
|
use crate::async_io::{AsyncIoError, AsyncIoOperation, AsyncIoResult};
|
|
|
|
pub(super) fn validate_operation_bounds(op: &AsyncIoOperation, size: u64) -> AsyncIoResult<()> {
|
|
let offset = u64::try_from(op.offset()).map_err(|_| bounds_error(op, size))?;
|
|
let len = u64::try_from(op.total_len()).map_err(|_| bounds_error(op, size))?;
|
|
let end = offset
|
|
.checked_add(len)
|
|
.ok_or_else(|| bounds_error(op, size))?;
|
|
|
|
if end > size {
|
|
return Err(bounds_error(op, size));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn bounds_error(op: &AsyncIoOperation, size: u64) -> AsyncIoError {
|
|
let error = io::Error::new(
|
|
io::ErrorKind::InvalidData,
|
|
format!(
|
|
"Invalid request offset {} and length {}, can't exceed file size {}",
|
|
op.offset(),
|
|
op.total_len(),
|
|
size
|
|
),
|
|
);
|
|
if op.is_read() {
|
|
AsyncIoError::ReadVectored(error)
|
|
} else {
|
|
AsyncIoError::WriteVectored(error)
|
|
}
|
|
}
|