Validate that PCI MMIO regions are within the expected range.
Bug: 237249346
Test: Built and ran pVM firmware manually
Change-Id: Ic506486c8961f40fa6f08c602813bf17796be8e7
diff --git a/pvmfw/src/virtio/hal.rs b/pvmfw/src/virtio/hal.rs
index c6c7a99..5f70b33 100644
--- a/pvmfw/src/virtio/hal.rs
+++ b/pvmfw/src/virtio/hal.rs
@@ -1,5 +1,9 @@
+use super::pci::PCI_INFO;
use crate::memory::{alloc_shared, dealloc_shared, phys_to_virt, virt_to_phys};
-use core::ptr::{copy_nonoverlapping, NonNull};
+use core::{
+ ops::Range,
+ ptr::{copy_nonoverlapping, NonNull},
+};
use log::debug;
use virtio_drivers::{BufferDirection, Hal, PhysAddr, PAGE_SIZE};
@@ -26,7 +30,21 @@
0
}
- fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull<u8> {
+ fn mmio_phys_to_virt(paddr: PhysAddr, size: usize) -> NonNull<u8> {
+ let pci_info = PCI_INFO.get().expect("VirtIO HAL used before PCI_INFO was initialised");
+ // Check that the region is within the PCI MMIO range that we read from the device tree. If
+ // not, the host is probably trying to do something malicious.
+ if !contains_range(
+ &pci_info.bar_range,
+ &(paddr.try_into().expect("PCI MMIO region start was outside of 32-bit address space")
+ ..paddr
+ .checked_add(size)
+ .expect("PCI MMIO region end overflowed")
+ .try_into()
+ .expect("PCI MMIO region end was outside of 32-bit address space")),
+ ) {
+ panic!("PCI MMIO region was outside of expected BAR range.");
+ }
phys_to_virt(paddr)
}
@@ -68,3 +86,8 @@
}
}
}
+
+/// Returns true if `inner` is entirely contained within `outer`.
+fn contains_range(outer: &Range<u32>, inner: &Range<u32>) -> bool {
+ inner.start >= outer.start && inner.end <= outer.end
+}