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:
Tao Yuhong 2021-04-14 10:26:21 -04:00 committed by wenlingz
parent 7da53ce138
commit 5ecca6b256
4 changed files with 47 additions and 3 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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];
};