mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: iommu: Cap mappings per domain
Domain::mappings only shrinks on UNMAP. Without a bound a guest can issue MAP for arbitrarily many distinct virt_start values and drive the VMM heap until the host runs out. Reject MAP with VIRTIO_IOMMU_S_NOMEM at 1M entries per domain. Signed-off-by: Rob Bradford <rbradford@meta.com> Assisted-by: Claude:claude-opus-4-7
This commit is contained in:
@@ -73,6 +73,9 @@ const VIRTIO_IOMMU_F_BYPASS_CONFIG: u32 = 6;
|
||||
// Support 2MiB and 4KiB page sizes.
|
||||
const VIRTIO_IOMMU_PAGE_SIZE_MASK: u64 = (2 << 20) | (4 << 10);
|
||||
|
||||
// ~64 MiB at ~64 bytes/entry, well above any legitimate workload.
|
||||
const MAX_MAPPINGS_PER_DOMAIN: usize = 1 << 20;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C, packed)]
|
||||
#[allow(dead_code)]
|
||||
@@ -130,7 +133,6 @@ const VIRTIO_IOMMU_S_RANGE: u8 = 5;
|
||||
const VIRTIO_IOMMU_S_NOENT: u8 = 6;
|
||||
#[allow(unused)]
|
||||
const VIRTIO_IOMMU_S_FAULT: u8 = 7;
|
||||
#[allow(unused)]
|
||||
const VIRTIO_IOMMU_S_NOMEM: u8 = 8;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
@@ -323,6 +325,8 @@ enum Error {
|
||||
InvalidUnmapRequestMissingDomain,
|
||||
#[error("UNMAP range partially overlaps an existing mapping")]
|
||||
InvalidUnmapRequestPartialOverlap,
|
||||
#[error("Per-domain mapping count cap exceeded")]
|
||||
MappingCountExceeded,
|
||||
#[error("Guest sent us invalid PROBE request")]
|
||||
InvalidProbeRequest,
|
||||
#[error("Failed to performing external mapping")]
|
||||
@@ -509,6 +513,16 @@ impl Request {
|
||||
return Err(Error::InvalidMapRequest);
|
||||
}
|
||||
|
||||
{
|
||||
let domains = mapping.domains.read().unwrap();
|
||||
if let Some(d) = domains.get(&domain_id)
|
||||
&& d.mappings.len() >= MAX_MAPPINGS_PER_DOMAIN
|
||||
{
|
||||
status = VIRTIO_IOMMU_S_NOMEM;
|
||||
return Err(Error::MappingCountExceeded);
|
||||
}
|
||||
}
|
||||
|
||||
let mut mapped: Vec<u32> = Vec::new();
|
||||
let rollback = |mapped: &[u32]| {
|
||||
for ep in mapped {
|
||||
@@ -537,6 +551,11 @@ impl Request {
|
||||
status = VIRTIO_IOMMU_S_NOENT;
|
||||
return Err(Error::InvalidMapRequestMissingDomain);
|
||||
};
|
||||
if domain.mappings.len() >= MAX_MAPPINGS_PER_DOMAIN {
|
||||
rollback(&mapped);
|
||||
status = VIRTIO_IOMMU_S_NOMEM;
|
||||
return Err(Error::MappingCountExceeded);
|
||||
}
|
||||
domain.mappings.insert(
|
||||
req.virt_start,
|
||||
Mapping {
|
||||
|
||||
Reference in New Issue
Block a user