diff --git a/block/src/fixed_vhd_async.rs b/block/src/fixed_vhd_async.rs index 58dbc9a93..975ac6be4 100644 --- a/block/src/fixed_vhd_async.rs +++ b/block/src/fixed_vhd_async.rs @@ -1,5 +1,7 @@ // Copyright © 2021 Intel Corporation // +// Copyright (c) Meta Platforms, Inc. and affiliates. +// // SPDX-License-Identifier: Apache-2.0 use std::os::unix::io::RawFd; @@ -7,7 +9,7 @@ use std::os::unix::io::RawFd; use vmm_sys_util::eventfd::EventFd; use crate::BatchRequest; -use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult}; +use crate::async_io::{AsyncIo, AsyncIoCompletion, AsyncIoError, AsyncIoOperation, AsyncIoResult}; use crate::error::BlockResult; use crate::raw_async::RawFileAsync; @@ -25,6 +27,37 @@ impl FixedVhdAsync { size, }) } + + fn validate_operation_bounds(&self, op: &AsyncIoOperation) -> AsyncIoResult<()> { + let offset = u64::try_from(op.offset()).map_err(|_| self.bounds_error(op))?; + let len = u64::try_from(op.total_len()).map_err(|_| self.bounds_error(op))?; + let end = offset + .checked_add(len) + .ok_or_else(|| self.bounds_error(op))?; + + if end > self.size { + return Err(self.bounds_error(op)); + } + + Ok(()) + } + + fn bounds_error(&self, op: &AsyncIoOperation) -> AsyncIoError { + let error = std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!( + "Invalid request offset {} and length {}, can't exceed file size {}", + op.offset(), + op.total_len(), + self.size + ), + ); + if op.is_read() { + AsyncIoError::ReadVectored(error) + } else { + AsyncIoError::WriteVectored(error) + } + } } impl AsyncIo for FixedVhdAsync { @@ -71,12 +104,17 @@ impl AsyncIo for FixedVhdAsync { .write_vectored(offset, iovecs, user_data) } + fn submit_data_operation(&mut self, op: AsyncIoOperation) -> AsyncIoResult<()> { + self.validate_operation_bounds(&op)?; + self.raw_file_async.submit_data_operation(op) + } + fn fsync(&mut self, user_data: Option) -> AsyncIoResult<()> { self.raw_file_async.fsync(user_data) } - fn next_completed_request(&mut self) -> Option<(u64, i32)> { - self.raw_file_async.next_completed_request() + fn next_completion(&mut self) -> Option { + self.raw_file_async.next_completion() } fn punch_hole(&mut self, _offset: u64, _length: u64, _user_data: u64) -> AsyncIoResult<()> { @@ -98,4 +136,15 @@ impl AsyncIo for FixedVhdAsync { fn submit_batch_requests(&mut self, batch_request: &[BatchRequest]) -> AsyncIoResult<()> { self.raw_file_async.submit_batch_requests(batch_request) } + + fn submit_batch_operations( + &mut self, + batch_request: Vec, + ) -> AsyncIoResult<()> { + for op in &batch_request { + self.validate_operation_bounds(op)?; + } + + self.raw_file_async.submit_batch_operations(batch_request) + } }