From 9375c634dccf4485fb17bb4e179f18bf9bfb1134 Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Mon, 16 Mar 2020 17:43:09 +0800 Subject: [PATCH] hv: unmap SR-IOV VF MMIO when the VF physical device is disabled To avoid information leakage, we need to ensure that the device is inaccessble when it does not exist. For SR-IOV disabled VF device, we have the following operations. 1. The configuration space accessing will get 0xFFFFFFFF as a return value after set the device state to zombie. 2. The BAR MMIO EPT mapping are removed, the accesssing causes EPT violation. 3. The device will be detached from IOMMU. 4. The IRQ pin and vector are released. Tracked-On: #4433 Signed-off-by: Yuan Liu Acked-by: Eddie Dong --- hypervisor/dm/vpci/pci_pt.c | 35 ++++++++++++++++++++++++++++++++-- hypervisor/dm/vpci/vpci.c | 1 + hypervisor/dm/vpci/vpci_priv.h | 1 + hypervisor/dm/vpci/vsriov.c | 2 -- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index c4d25b761..899623f25 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -388,8 +388,8 @@ void init_vdev_pt(struct pci_vdev *vdev, bool is_pf_vdev) pci_pdev_write_cfg(vdev->pdev->bdf, PCIR_COMMAND, 2U, pci_command); } } else { - /* VF is assigned to a UOS */ - if (vdev->vpci != vdev->phyfun->vpci) { + if (!is_own_device(vdev->phyfun->vpci->vm, vdev)) { + /* VF is assigned to a UOS */ uint32_t vid, did; vdev->nr_bars = PCI_BAR_COUNT; @@ -399,6 +399,37 @@ void init_vdev_pt(struct pci_vdev *vdev, bool is_pf_vdev) (vdev->phyfun->sriov.capoff + PCIR_SRIOV_VF_DEV_ID), 2U); pci_vdev_write_vcfg(vdev, PCIR_VENDOR, 2U, vid); pci_vdev_write_vcfg(vdev, PCIR_DEVICE, 2U, did); + } else { + /* VF is unassinged */ + uint32_t bar_idx; + + for (bar_idx = 0U; bar_idx < vdev->nr_bars; bar_idx++) { + vdev_pt_map_mem_vbar(vdev, bar_idx); + } + } + } +} + +/* + * @brief Destruct a specified passthrough vdev structure. + * + * The function deinit_vdev_pt is the destructor corresponding to the function init_vdev_pt. + * + * @param vdev pointer to vdev data structure + * + * @pre vdev != NULL + * + * @return None + */ +void deinit_vdev_pt(struct pci_vdev *vdev) { + + /* Check if the vdev is an unassigned SR-IOV VF device */ + if ((vdev->phyfun != NULL) && (is_own_device(vdev->phyfun->vpci->vm, vdev))) { + uint32_t bar_idx; + + /* Delete VF MMIO from EPT table since the VF physical device has gone */ + for (bar_idx = 0U; bar_idx < vdev->nr_bars; bar_idx++) { + vdev_pt_unmap_mem_vbar(vdev, bar_idx); } } } diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index 2fada8836..e4ac8200e 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -377,6 +377,7 @@ static void vpci_init_pt_dev(struct pci_vdev *vdev) static void vpci_deinit_pt_dev(struct pci_vdev *vdev) { + deinit_vdev_pt(vdev); remove_vdev_pt_iommu_domain(vdev); deinit_vmsix(vdev); deinit_vmsi(vdev); diff --git a/hypervisor/dm/vpci/vpci_priv.h b/hypervisor/dm/vpci/vpci_priv.h index ce6d0e9a5..132dbb137 100644 --- a/hypervisor/dm/vpci/vpci_priv.h +++ b/hypervisor/dm/vpci/vpci_priv.h @@ -102,6 +102,7 @@ static inline bool msicap_access(const struct pci_vdev *vdev, uint32_t offset) } void init_vdev_pt(struct pci_vdev *vdev, bool is_pf_vdev); +void deinit_vdev_pt(struct pci_vdev *vdev); void vdev_pt_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val); void vdev_pt_map_msix(struct pci_vdev *vdev, bool hold_lock); diff --git a/hypervisor/dm/vpci/vsriov.c b/hypervisor/dm/vpci/vsriov.c index b8d9bcd04..6e8730f15 100644 --- a/hypervisor/dm/vpci/vsriov.c +++ b/hypervisor/dm/vpci/vsriov.c @@ -239,8 +239,6 @@ static void disable_vfs(struct pci_vdev *pf_vdev) * resources * * If the VF drivers are still running in SOS or UOS, the MMIO access will return 0xFF. - * - * TODO For security reasons, we need to enforce a return of 0xFF to avoid information leakage. */ num_vfs = read_sriov_reg(pf_vdev, PCIR_SRIOV_NUMVFS); first = read_sriov_reg(pf_vdev, PCIR_SRIOV_FST_VF_OFF);