HV: vpci: check if address is in VM BAR MMIO space
When guest doing BAR re-programming, we should check whether the base address of the BAR is valid.This patch does this check by: 1. whether the gpa is located in the responding MMIO window 2. whether the gpa is aligned with the BAR size Tracked-On: #6011 Signed-off-by: Tao Yuhong <yuhong.tao@intel.com> Reviewed-by: Eddie Dong <eddie.dong@intel.com> Reviewed-by: Li Fei <fei1.li@intel.com>
This commit is contained in:
parent
7da53ce138
commit
5ecca6b256
|
@ -106,11 +106,20 @@ uint32_t pci_vdev_read_vbar(const struct pci_vdev *vdev, uint32_t idx)
|
|||
return bar;
|
||||
}
|
||||
|
||||
static bool is_pci_mem_bar_base_valid(struct acrn_vm *vm, uint64_t base)
|
||||
{
|
||||
struct acrn_vpci *vpci = &vm->vpci;
|
||||
struct pci_mmio_res *res = (base < (1UL << 32UL)) ? &(vpci->res32): &(vpci->res64);
|
||||
|
||||
return ((base >= res->start) && (base <= res->end));
|
||||
}
|
||||
|
||||
static void pci_vdev_update_vbar_base(struct pci_vdev *vdev, uint32_t idx)
|
||||
{
|
||||
struct pci_vbar *vbar;
|
||||
uint64_t base = 0UL;
|
||||
uint32_t lo, hi, offset;
|
||||
struct pci_mmio_res *res;
|
||||
|
||||
vbar = &vdev->vbars[idx];
|
||||
offset = pci_bar_offset(idx);
|
||||
|
@ -137,7 +146,19 @@ static void pci_vdev_update_vbar_base(struct pci_vdev *vdev, uint32_t idx)
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO: 1. check whether the address locate in the MMIO windows 2. base must aligned with size */
|
||||
if ( (base != 0UL) && (!is_pci_io_bar(vbar))) {
|
||||
if ((!is_pci_mem_bar_base_valid(vpci2vm(vdev->vpci), base)) || (!mem_aligned_check(base, vdev->vbars[idx].size))) {
|
||||
res = (base < (1UL << 32UL)) ? &(vdev->vpci->res32): &(vdev->vpci->res64);
|
||||
/* VM tries to reprogram vbar address out of pci mmio bar window, it can be caused by:
|
||||
* 1. For SOS, <board>.xml is misaligned with the actual native platform, and we get wrong mmio window.
|
||||
* 2. Malicious operation from VM, it tries to reprogram vbar address out of pci mmio bar window
|
||||
*/
|
||||
pr_err("%s reprogram PCI:%02x:%02x.%x BAR%d to addr:0x%lx,"
|
||||
" which is out of mmio window[0x%lx - 0x%lx] or not aligned with size: 0x%lx",
|
||||
__func__, vdev->bdf.bits.b, vdev->bdf.bits.d, vdev->bdf.bits.f, idx, base, res->start,
|
||||
res->end, vdev->vbars[idx].size);
|
||||
}
|
||||
}
|
||||
|
||||
vdev->vbars[idx].base_gpa = base;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
#include "vpci_priv.h"
|
||||
#include <asm/pci_dev.h>
|
||||
#include <hash.h>
|
||||
#include <board_info.h>
|
||||
|
||||
|
||||
static void vpci_init_vdevs(struct acrn_vm *vm);
|
||||
static int32_t vpci_read_cfg(struct acrn_vpci *vpci, union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t *val);
|
||||
|
@ -219,20 +221,29 @@ void init_vpci(struct acrn_vm *vm)
|
|||
struct pci_mmcfg_region *pci_mmcfg;
|
||||
|
||||
vm->iommu = create_iommu_domain(vm->vm_id, hva2hpa(vm->arch_vm.nworld_eptp), 48U);
|
||||
/* Build up vdev list for vm */
|
||||
vpci_init_vdevs(vm);
|
||||
|
||||
vm_config = get_vm_config(vm->vm_id);
|
||||
/* virtual PCI MMCONFIG for SOS is same with the physical value */
|
||||
if (vm_config->load_order == SOS_VM) {
|
||||
pci_mmcfg = get_mmcfg_region();
|
||||
vm->vpci.pci_mmcfg = *pci_mmcfg;
|
||||
vm->vpci.res32.start = MMIO32_START;
|
||||
vm->vpci.res32.end = MMIO32_END;
|
||||
vm->vpci.res64.start = MMIO64_START;
|
||||
vm->vpci.res64.end = MMIO64_END;
|
||||
} else {
|
||||
vm->vpci.pci_mmcfg.address = UOS_VIRT_PCI_MMCFG_BASE;
|
||||
vm->vpci.pci_mmcfg.start_bus = UOS_VIRT_PCI_MMCFG_START_BUS;
|
||||
vm->vpci.pci_mmcfg.end_bus = UOS_VIRT_PCI_MMCFG_END_BUS;
|
||||
vm->vpci.res32.start = UOS_VIRT_PCI_MEMBASE32;
|
||||
vm->vpci.res32.end = UOS_VIRT_PCI_MEMLIMIT32;
|
||||
vm->vpci.res64.start = UOS_VIRT_PCI_MEMBASE64;
|
||||
vm->vpci.res64.end = UOS_VIRT_PCI_MEMLIMIT64;
|
||||
}
|
||||
|
||||
/* Build up vdev list for vm */
|
||||
vpci_init_vdevs(vm);
|
||||
|
||||
register_mmio_emulation_handler(vm, vpci_mmio_cfg_access, vm->vpci.pci_mmcfg.address,
|
||||
vm->vpci.pci_mmcfg.address + get_pci_mmcfg_size(&vm->vpci.pci_mmcfg), &vm->vpci, false);
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
#define UOS_VIRT_PCI_MMCFG_BASE 0xE0000000UL
|
||||
#define UOS_VIRT_PCI_MMCFG_START_BUS 0x0U
|
||||
#define UOS_VIRT_PCI_MMCFG_END_BUS 0xFFU
|
||||
#define UOS_VIRT_PCI_MEMBASE32 0x80000000UL /* 2GB */
|
||||
#define UOS_VIRT_PCI_MEMLIMIT32 0xE0000000UL /* 3.5GB */
|
||||
#define UOS_VIRT_PCI_MEMBASE64 0x4000000000UL /* 256GB */
|
||||
#define UOS_VIRT_PCI_MEMLIMIT64 0x8000000000UL /* 512GB */
|
||||
|
||||
void build_vrsdp(struct acrn_vm *vm);
|
||||
|
||||
|
|
|
@ -163,11 +163,19 @@ union pci_cfg_addr_reg {
|
|||
} bits;
|
||||
};
|
||||
|
||||
/* start address & end address of MMIO BAR */
|
||||
struct pci_mmio_res {
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
};
|
||||
|
||||
struct acrn_vpci {
|
||||
spinlock_t lock;
|
||||
union pci_cfg_addr_reg addr;
|
||||
struct pci_mmcfg_region pci_mmcfg;
|
||||
uint32_t pci_vdev_cnt;
|
||||
struct pci_mmio_res res32; /* 32-bit mmio start/end address */
|
||||
struct pci_mmio_res res64; /* 64-bit mmio start/end address */
|
||||
struct pci_vdev pci_vdevs[CONFIG_MAX_PCI_DEV_NUM];
|
||||
struct hlist_head vdevs_hlist_heads [VDEV_LIST_HASHSIZE];
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue