aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2022-08-19 21:59:44 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2022-08-25 16:40:15 +0000
commit10affcbdac737429d8b14697a126ddb2b405917c (patch)
tree6cd07086e06d65b86386e3cd68d7dbf4d5bd0778
parentbb5b19a12c611a8a53b24def420f98ab10c262fe (diff)
downloadsrc-10affcbdac737429d8b14697a126ddb2b405917c.tar.gz
src-10affcbdac737429d8b14697a126ddb2b405917c.zip
bhyve: Validate host PAs used to map passthrough BARs.
Reject attempts to map host physical address ranges that are not subsets of a passthrough device's BAR into a guest. Reviewed by: markj, emaste MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D36238 (cherry picked from commit c94f30ea85b745a5137471876013f79689e0af03)
-rw-r--r--sys/amd64/vmm/io/ppt.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/sys/amd64/vmm/io/ppt.c b/sys/amd64/vmm/io/ppt.c
index 4de45ff6d6f9..ee60646db0e7 100644
--- a/sys/amd64/vmm/io/ppt.c
+++ b/sys/amd64/vmm/io/ppt.c
@@ -439,6 +439,23 @@ ppt_unassign_all(struct vm *vm)
return (0);
}
+static bool
+ppt_valid_bar_mapping(struct pptdev *ppt, vm_paddr_t hpa, size_t len)
+{
+ struct pci_map *pm;
+ pci_addr_t base, size;
+
+ for (pm = pci_first_bar(ppt->dev); pm != NULL; pm = pci_next_bar(pm)) {
+ if (!PCI_BAR_MEM(pm->pm_value))
+ continue;
+ base = pm->pm_value & PCIM_BAR_MEM_BASE;
+ size = (pci_addr_t)1 << pm->pm_size;
+ if (hpa >= base && hpa + len <= base + size)
+ return (true);
+ }
+ return (false);
+}
+
int
ppt_map_mmio(struct vm *vm, int bus, int slot, int func,
vm_paddr_t gpa, size_t len, vm_paddr_t hpa)
@@ -447,10 +464,17 @@ ppt_map_mmio(struct vm *vm, int bus, int slot, int func,
struct pptseg *seg;
struct pptdev *ppt;
+ if (len % PAGE_SIZE != 0 || len == 0 || gpa % PAGE_SIZE != 0 ||
+ hpa % PAGE_SIZE != 0 || gpa + len < gpa || hpa + len < hpa)
+ return (EINVAL);
+
error = ppt_find(vm, bus, slot, func, &ppt);
if (error)
return (error);
+ if (!ppt_valid_bar_mapping(ppt, hpa, len))
+ return (EINVAL);
+
for (i = 0; i < MAX_MMIOSEGS; i++) {
seg = &ppt->mmio[i];
if (seg->len == 0) {