Skip to content

Commit 6d5d763

Browse files
authored
fix: use checked arithmetic in bounds_check! to prevent overflow bypass (#1263)
The bounds check silently wraps on usize overflow in release builds, bypassing the check entirely. Not exploitable today since callers validate offsets before reaching the macro, but any future caller that doesn't could trigger it. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent 513b08e commit 6d5d763

1 file changed

Lines changed: 29 additions & 1 deletion

File tree

src/hyperlight_host/src/mem/shared_mem.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use crate::{HyperlightError, Result, log_then_return, new_error};
4848
/// Makes sure that the given `offset` and `size` are within the bounds of the memory with size `mem_size`.
4949
macro_rules! bounds_check {
5050
($offset:expr, $size:expr, $mem_size:expr) => {
51-
if $offset + $size > $mem_size {
51+
if $offset.checked_add($size).is_none_or(|end| end > $mem_size) {
5252
return Err(new_error!(
5353
"Cannot read value from offset {} with size {} in memory of size {}",
5454
$offset,
@@ -1249,6 +1249,34 @@ mod tests {
12491249
assert!(hshm.fill(0, mem_size, 1).is_err());
12501250
}
12511251

1252+
/// Verify that `bounds_check!` rejects offset + size combinations that
1253+
/// would overflow `usize`.
1254+
#[test]
1255+
fn bounds_check_overflow() {
1256+
let mem_size: usize = 4096;
1257+
let mut eshm = ExclusiveSharedMemory::new(mem_size).unwrap();
1258+
1259+
// ExclusiveSharedMemory methods
1260+
assert!(eshm.read_i32(usize::MAX).is_err());
1261+
assert!(eshm.write_i32(usize::MAX, 0).is_err());
1262+
assert!(eshm.copy_from_slice(&[0u8; 1], usize::MAX).is_err());
1263+
1264+
// HostSharedMemory methods
1265+
let (mut hshm, _) = eshm.build();
1266+
1267+
assert!(hshm.read::<u8>(usize::MAX).is_err());
1268+
assert!(hshm.read::<u64>(usize::MAX - 3).is_err());
1269+
assert!(hshm.write::<u8>(usize::MAX, 0).is_err());
1270+
assert!(hshm.write::<u64>(usize::MAX - 3, 0).is_err());
1271+
1272+
let mut buf = [0u8; 1];
1273+
assert!(hshm.copy_to_slice(&mut buf, usize::MAX).is_err());
1274+
assert!(hshm.copy_from_slice(&[0u8; 1], usize::MAX).is_err());
1275+
1276+
assert!(hshm.fill(0, usize::MAX, 1).is_err());
1277+
assert!(hshm.fill(0, 1, usize::MAX).is_err());
1278+
}
1279+
12521280
#[test]
12531281
fn copy_into_from() -> Result<()> {
12541282
let mem_size: usize = 4096;

0 commit comments

Comments
 (0)