[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-stable] [PATCH 088/113] intel-iommu: send PSI always even if acros
From: |
Michael Roth |
Subject: |
[Qemu-stable] [PATCH 088/113] intel-iommu: send PSI always even if across PDEs |
Date: |
Mon, 18 Jun 2018 20:42:54 -0500 |
From: Peter Xu <address@hidden>
SECURITY IMPLICATION: without this patch, any guest with both assigned
device and a vIOMMU might encounter stale IO page mappings even if guest
has already unmapped the page, which may lead to guest memory
corruption. The stale mappings will only be limited to the guest's own
memory range, so it should not affect the host memory or other guests on
the host.
During IOVA page table walking, there is a special case when the PSI
covers one whole PDE (Page Directory Entry, which contains 512 Page
Table Entries) or more. In the past, we skip that entry and we don't
notify the IOMMU notifiers. This is not correct. We should send UNMAP
notification to registered UNMAP notifiers in this case.
For UNMAP only notifiers, this might cause IOTLBs cached in the devices
even if they were already invalid. For MAP/UNMAP notifiers like
vfio-pci, this will cause stale page mappings.
This special case doesn't trigger often, but it is very easy to be
triggered by nested device assignments, since in that case we'll
possibly map the whole L2 guest RAM region into the device's IOVA
address space (several GBs at least), which is far bigger than normal
kernel driver usages of the device (tens of MBs normally).
Without this patch applied to L1 QEMU, nested device assignment to L2
guests will dump some errors like:
qemu-system-x86_64: VFIO_MAP_DMA: -17
qemu-system-x86_64: vfio_dma_map(0x557305420c30, 0xad000, 0x1000,
0x7f89a920d000) = -17 (File exists)
CC: QEMU Stable <address@hidden>
Acked-by: Jason Wang <address@hidden>
[peterx: rewrite the commit message]
Signed-off-by: Peter Xu <address@hidden>
Reviewed-by: Michael S. Tsirkin <address@hidden>
Signed-off-by: Michael S. Tsirkin <address@hidden>
(cherry picked from commit 36d2d52bdb45f5b753a61fdaf0fe7891f1f5b61d)
Signed-off-by: Michael Roth <address@hidden>
---
hw/i386/intel_iommu.c | 42 ++++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index c2380fdfdc..a03ae403f8 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -722,6 +722,15 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t
iova, bool is_write,
typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private);
+static int vtd_page_walk_one(IOMMUTLBEntry *entry, int level,
+ vtd_page_walk_hook hook_fn, void *private)
+{
+ assert(hook_fn);
+ trace_vtd_page_walk_one(level, entry->iova, entry->translated_addr,
+ entry->addr_mask, entry->perm);
+ return hook_fn(entry, private);
+}
+
/**
* vtd_page_walk_level - walk over specific level for IOVA range
*
@@ -781,28 +790,37 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t
start,
*/
entry_valid = read_cur | write_cur;
+ entry.target_as = &address_space_memory;
+ entry.iova = iova & subpage_mask;
+ entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
+ entry.addr_mask = ~subpage_mask;
+
if (vtd_is_last_slpte(slpte, level)) {
- entry.target_as = &address_space_memory;
- entry.iova = iova & subpage_mask;
/* NOTE: this is only meaningful if entry_valid == true */
entry.translated_addr = vtd_get_slpte_addr(slpte, aw);
- entry.addr_mask = ~subpage_mask;
- entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
if (!entry_valid && !notify_unmap) {
trace_vtd_page_walk_skip_perm(iova, iova_next);
goto next;
}
- trace_vtd_page_walk_one(level, entry.iova, entry.translated_addr,
- entry.addr_mask, entry.perm);
- if (hook_fn) {
- ret = hook_fn(&entry, private);
- if (ret < 0) {
- return ret;
- }
+ ret = vtd_page_walk_one(&entry, level, hook_fn, private);
+ if (ret < 0) {
+ return ret;
}
} else {
if (!entry_valid) {
- trace_vtd_page_walk_skip_perm(iova, iova_next);
+ if (notify_unmap) {
+ /*
+ * The whole entry is invalid; unmap it all.
+ * Translated address is meaningless, zero it.
+ */
+ entry.translated_addr = 0x0;
+ ret = vtd_page_walk_one(&entry, level, hook_fn, private);
+ if (ret < 0) {
+ return ret;
+ }
+ } else {
+ trace_vtd_page_walk_skip_perm(iova, iova_next);
+ }
goto next;
}
ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, aw), iova,
--
2.11.0
- [Qemu-stable] [PATCH 079/113] qdev: rename typedef qdev_resetfn() -> DeviceReset(), (continued)
- [Qemu-stable] [PATCH 079/113] qdev: rename typedef qdev_resetfn() -> DeviceReset(), Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 077/113] s390x/css: disabled subchannels cannot be status pending, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 076/113] raw: Check byte range uniformly, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 080/113] qdev: add helpers to be more explicit when using abstract QOM parent functions, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 007/113] spapr: Adjust default VSMT value for better migration compatibility, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 081/113] s390x/virtio: Convert virtio-ccw from *_exit to *_unrealize, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 083/113] s390x/ccw: make sure all ccw devices are properly reset, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 084/113] console: Avoid segfault in screendump, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 082/113] virtio-ccw: common reset handler, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 085/113] hw/intc/arm_gicv3: Fix APxR<n> register dispatching, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 088/113] intel-iommu: send PSI always even if across PDEs,
Michael Roth <=
- [Qemu-stable] [PATCH 086/113] intel-iommu: Redefine macros to enable supporting 48 bit address width, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 087/113] intel-iommu: Extend address width to 48 bits, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 089/113] intel-iommu: remove IntelIOMMUNotifierNode, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 008/113] spapr: set vsmt to MAX(8, smp_threads), Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 090/113] intel-iommu: add iommu lock, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 093/113] intel-iommu: pass in address space when page walk, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 091/113] intel-iommu: only do page walk for MAP notifiers, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 092/113] intel-iommu: introduce vtd_page_walk_info, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 094/113] intel-iommu: trace domain id during page walk, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 095/113] util: implement simple iova tree, Michael Roth, 2018/06/18