mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: iommu: Enforce input_range on MAP requests
The device offers VIRTIO_IOMMU_F_INPUT_RANGE when the address width is constrained, but never validates that guest MAP requests fall inside the advertised range. The virtio spec requires such requests to fail with VIRTIO_IOMMU_S_RANGE. Signed-off-by: Rob Bradford <rbradford@meta.com> Assisted-by: Claude:claude-opus-4-7
This commit is contained in:
@@ -347,6 +347,7 @@ impl Request {
|
||||
mapping: &Arc<IommuMapping>,
|
||||
ext_mapping: &BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
msi_iova_space: (u64, u64),
|
||||
input_range: Option<(u64, u64)>,
|
||||
) -> result::Result<usize, Error> {
|
||||
let desc = desc_chain
|
||||
.next()
|
||||
@@ -490,6 +491,13 @@ impl Request {
|
||||
return Err(Error::InvalidMapRequest);
|
||||
}
|
||||
|
||||
if let Some((lo, hi)) = input_range
|
||||
&& (req.virt_start < lo || req.virt_end > hi)
|
||||
{
|
||||
status = VIRTIO_IOMMU_S_RANGE;
|
||||
return Err(Error::InvalidMapRequest);
|
||||
}
|
||||
|
||||
// Copy the value to use it as a proper reference.
|
||||
let domain_id = req.domain;
|
||||
|
||||
@@ -611,6 +619,13 @@ impl Request {
|
||||
.map_err(Error::GuestMemory)?;
|
||||
debug!("Unmap request 0x{req:x?}");
|
||||
|
||||
if let Some((lo, hi)) = input_range
|
||||
&& (req.virt_start < lo || req.virt_end > hi)
|
||||
{
|
||||
status = VIRTIO_IOMMU_S_RANGE;
|
||||
return Err(Error::InvalidUnmapRequest);
|
||||
}
|
||||
|
||||
// Copy the value to use it as a proper reference.
|
||||
let domain_id = req.domain;
|
||||
let virt_start = req.virt_start;
|
||||
@@ -808,6 +823,7 @@ struct IommuEpollHandler {
|
||||
mapping: Arc<IommuMapping>,
|
||||
ext_mapping: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
|
||||
msi_iova_space: (u64, u64),
|
||||
input_range: Option<(u64, u64)>,
|
||||
}
|
||||
|
||||
impl IommuEpollHandler {
|
||||
@@ -820,6 +836,7 @@ impl IommuEpollHandler {
|
||||
&self.mapping,
|
||||
&self.ext_mapping.lock().unwrap(),
|
||||
self.msi_iova_space,
|
||||
self.input_range,
|
||||
)?;
|
||||
|
||||
self.request_queue
|
||||
@@ -1032,6 +1049,7 @@ pub struct Iommu {
|
||||
seccomp_action: SeccompAction,
|
||||
exit_evt: EventFd,
|
||||
msi_iova_space: (u64, u64),
|
||||
input_range: Option<(u64, u64)>,
|
||||
}
|
||||
|
||||
type EndpointsState = Vec<(u32, u32)>;
|
||||
@@ -1091,13 +1109,14 @@ impl Iommu {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if address_width_bits < 64 {
|
||||
let input_range = if address_width_bits < 64 {
|
||||
avail_features |= 1u64 << VIRTIO_IOMMU_F_INPUT_RANGE;
|
||||
config.input_range = VirtioIommuRange64 {
|
||||
start: 0,
|
||||
end: (1u64 << address_width_bits) - 1,
|
||||
}
|
||||
}
|
||||
let end = (1u64 << address_width_bits) - 1;
|
||||
config.input_range = VirtioIommuRange64 { start: 0, end };
|
||||
Some((0, end))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mapping = Arc::new(IommuMapping {
|
||||
endpoints: Arc::new(RwLock::new(endpoints)),
|
||||
@@ -1124,6 +1143,7 @@ impl Iommu {
|
||||
seccomp_action,
|
||||
exit_evt,
|
||||
msi_iova_space,
|
||||
input_range,
|
||||
},
|
||||
mapping,
|
||||
))
|
||||
@@ -1251,6 +1271,7 @@ impl VirtioDevice for Iommu {
|
||||
mapping: self.mapping.clone(),
|
||||
ext_mapping: self.ext_mapping.clone(),
|
||||
msi_iova_space: self.msi_iova_space,
|
||||
input_range: self.input_range,
|
||||
};
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
|
||||
Reference in New Issue
Block a user