From dc1e2adaec327ec374d7ae247ec8a9ba5556d1f1 Mon Sep 17 00:00:00 2001 From: "Li, Fei1" Date: Mon, 14 Oct 2019 23:26:57 +0800 Subject: [PATCH] hv: vpci: add PCI BAR re-program address check In theory, guest could re-program PCI BAR address to any address. However, ACRN hypervisor only support [0, top_address_space) EPT memory mapping. So we need to check whether the PCI BAR re-program address is within this scope. Tracked-On: #3475 Signed-off-by: Li, Fei1 Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/ept.c | 12 ++++++++++++ hypervisor/common/hypercall.c | 4 +--- hypervisor/dm/vpci/pci_pt.c | 21 +++++++++++++-------- hypervisor/include/arch/x86/guest/ept.h | 11 +++++++++++ 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/hypervisor/arch/x86/guest/ept.c b/hypervisor/arch/x86/guest/ept.c index 8b5eeeea8..67d7490e7 100644 --- a/hypervisor/arch/x86/guest/ept.c +++ b/hypervisor/arch/x86/guest/ept.c @@ -18,6 +18,18 @@ #define ACRN_DBG_EPT 6U +bool ept_is_mr_valid(const struct acrn_vm *vm, uint64_t base, uint64_t size) +{ + bool valid = true; + uint64_t end = base + size; + uint64_t top_address_space = vm->arch_vm.ept_mem_ops.info->ept.top_address_space; + if ((end <= base) || (end > top_address_space)) { + valid = false; + } + + return valid; +} + void destroy_ept(struct acrn_vm *vm) { /* Destroy secure world */ diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index 08be792d8..c294884ac 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -626,7 +626,6 @@ static int32_t add_vm_memory_region(struct acrn_vm *vm, struct acrn_vm *target_v static int32_t set_vm_memory_region(struct acrn_vm *vm, struct acrn_vm *target_vm, const struct vm_memory_region *region) { - uint64_t gpa_end; uint64_t *pml4_page; int32_t ret; @@ -635,8 +634,7 @@ static int32_t set_vm_memory_region(struct acrn_vm *vm, __func__, target_vm->vm_id, region->size); ret = -EINVAL; } else { - gpa_end = region->gpa + region->size; - if (gpa_end > target_vm->arch_vm.ept_mem_ops.info->ept.top_address_space) { + if (!ept_is_mr_valid(target_vm, region->gpa, region->size)) { pr_err("%s, invalid gpa: 0x%llx, size: 0x%llx, top_address_space: 0x%llx", __func__, region->gpa, region->size, target_vm->arch_vm.ept_mem_ops.info->ept.top_address_space); diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index b3c5194e2..e2ab86908 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -248,15 +248,20 @@ static void vdev_pt_remap_generic_mem_vbar(struct pci_vdev *vdev, uint32_t idx) vbar->size); } - /* Map the physical BAR in the guest MMIO space */ - ept_add_mr(vm, (uint64_t *)(vm->arch_vm.nworld_eptp), - pbar_base, /* HPA (pbar) */ - vbar_base, /* GPA (new vbar) */ - vbar->size, - EPT_WR | EPT_RD | EPT_UNCACHED); + if (ept_is_mr_valid(vm, vbar_base, vbar->size)) { + /* Map the physical BAR in the guest MMIO space */ + ept_add_mr(vm, (uint64_t *)(vm->arch_vm.nworld_eptp), + pbar_base, /* HPA (pbar) */ + vbar_base, /* GPA (new vbar) */ + vbar->size, + EPT_WR | EPT_RD | EPT_UNCACHED); - /* Remember the previously mapped MMIO vbar */ - vdev->bar_base_mapped[idx] = vbar_base; + /* Remember the previously mapped MMIO vbar */ + vdev->bar_base_mapped[idx] = vbar_base; + } else { + pr_fatal("%s, %x:%x.%x set invalid bar[%d] address: 0x%llx\n", __func__, + vdev->bdf.bits.b, vdev->bdf.bits.d, vdev->bdf.bits.f, idx, vbar_base); + } } } } diff --git a/hypervisor/include/arch/x86/guest/ept.h b/hypervisor/include/arch/x86/guest/ept.h index cb16cde90..f72a8ed31 100644 --- a/hypervisor/include/arch/x86/guest/ept.h +++ b/hypervisor/include/arch/x86/guest/ept.h @@ -18,6 +18,17 @@ typedef void (*pge_handler)(uint64_t *pgentry, uint64_t size); #define INVALID_HPA (0x1UL << 52U) #define INVALID_GPA (0x1UL << 52U) /* External Interfaces */ +/** + * @brief Check guest-physical memory region mapping valid + * + * @param[in] vm the pointer that points to VM data structure + * @param[in] base The specified start guest physical address of guest + * physical memory region + * @param[in] size The size of guest physical memory region + * + * @retval true if the guest-physical memory region mapping valid, false otherwise. + */ +bool ept_is_mr_valid(const struct acrn_vm *vm, uint64_t base, uint64_t size); /** * @brief EPT page tables destroy *