mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: balloon: Clamp range to region before PUNCH_HOLE
release_memory_range took (range_base, range_len) verbatim from a guest-controlled descriptor (free-page-reporting and inflate paths) and called fallocate(PUNCH_HOLE | KEEP_SIZE) on the backing file before any length check ran. find_region only validates that range_base lands inside *some* region; range_len can extend past the region's end. When the operator uses --memory-zone file=PATH against a host file larger than the zone, the punch zeroes host file content past the guest's memory extent. Free-page reporting is advisory, so the VMM is allowed to act on a subset of a free range. Clamp range_len to the bytes that actually fit within the region returned by find_region. Going past the end of a region is most likely a guest bug so log it. Signed-off-by: Dylan Reid <dgreid@fb.com>
This commit is contained in:
@@ -23,7 +23,7 @@ use std::sync::{Arc, Barrier};
|
|||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use event_monitor::event;
|
use event_monitor::event;
|
||||||
use log::{error, info};
|
use log::{error, info, warn};
|
||||||
use seccompiler::SeccompAction;
|
use seccompiler::SeccompAction;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@@ -201,15 +201,30 @@ impl BalloonEpollHandler {
|
|||||||
let region = memory.find_region(range_base).ok_or(Error::GuestMemory(
|
let region = memory.find_region(range_base).ok_or(Error::GuestMemory(
|
||||||
GuestMemoryError::InvalidGuestAddress(range_base),
|
GuestMemoryError::InvalidGuestAddress(range_base),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
|
// No underflow possible because range_base was found in the region by `find_region`.
|
||||||
|
let offset = range_base.0 - region.start_addr().0;
|
||||||
|
let region_limit = region.len() - offset;
|
||||||
|
let len = std::cmp::min(range_len as u64, region_limit);
|
||||||
|
if len < range_len as u64 {
|
||||||
|
warn!(
|
||||||
|
"Clamping reported range at GPA 0x{:x} from {} to {} bytes \
|
||||||
|
to fit inside its memory region",
|
||||||
|
range_base.0, range_len, len
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(f_off) = region.file_offset() {
|
if let Some(f_off) = region.file_offset() {
|
||||||
let offset = range_base.0 - region.start_addr().0;
|
|
||||||
// SAFETY: FFI call with valid arguments
|
// SAFETY: FFI call with valid arguments
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
libc::fallocate64(
|
libc::fallocate64(
|
||||||
f_off.file().as_raw_fd(),
|
f_off.file().as_raw_fd(),
|
||||||
libc::FALLOC_FL_PUNCH_HOLE | libc::FALLOC_FL_KEEP_SIZE,
|
libc::FALLOC_FL_PUNCH_HOLE | libc::FALLOC_FL_KEEP_SIZE,
|
||||||
(offset + f_off.start()) as libc::off64_t,
|
(offset + f_off.start()) as libc::off64_t,
|
||||||
range_len as libc::off64_t,
|
len as libc::off64_t,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -218,7 +233,7 @@ impl BalloonEpollHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::advise_memory_range(memory, range_base, range_len, libc::MADV_DONTNEED)
|
Self::advise_memory_range(memory, range_base, len as usize, libc::MADV_DONTNEED)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_memory_range_4k(
|
fn release_memory_range_4k(
|
||||||
|
|||||||
Reference in New Issue
Block a user