From 7d3a78564ab43271375c063fe37bd9bdd0296d37 Mon Sep 17 00:00:00 2001 From: "Justin M. Forbes" Date: Thu, 19 Apr 2012 09:47:12 -0500 Subject: [PATCH] Fix KVM device assignment page leak --- ...rom-the-iommu-when-slots-are-removed.patch | 92 +++++++++++++++++++ kernel.spec | 9 ++ 2 files changed, 101 insertions(+) create mode 100644 KVM-unmap-pages-from-the-iommu-when-slots-are-removed.patch diff --git a/KVM-unmap-pages-from-the-iommu-when-slots-are-removed.patch b/KVM-unmap-pages-from-the-iommu-when-slots-are-removed.patch new file mode 100644 index 000000000..b98e392f7 --- /dev/null +++ b/KVM-unmap-pages-from-the-iommu-when-slots-are-removed.patch @@ -0,0 +1,92 @@ +commit 32f6daad4651a748a58a3ab6da0611862175722f +Author: Alex Williamson +Date: Wed Apr 11 09:51:49 2012 -0600 + + KVM: unmap pages from the iommu when slots are removed + + We've been adding new mappings, but not destroying old mappings. + This can lead to a page leak as pages are pinned using + get_user_pages, but only unpinned with put_page if they still + exist in the memslots list on vm shutdown. A memslot that is + destroyed while an iommu domain is enabled for the guest will + therefore result in an elevated page reference count that is + never cleared. + + Additionally, without this fix, the iommu is only programmed + with the first translation for a gpa. This can result in + peer-to-peer errors if a mapping is destroyed and replaced by a + new mapping at the same gpa as the iommu will still be pointing + to the original, pinned memory address. + + Signed-off-by: Alex Williamson + Signed-off-by: Marcelo Tosatti + +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index 665a260..72cbf08 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -596,6 +596,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id); + + #ifdef CONFIG_IOMMU_API + int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot); ++void kvm_iommu_unmap_pages(struct kvm *kvm, struct kvm_memory_slot *slot); + int kvm_iommu_map_guest(struct kvm *kvm); + int kvm_iommu_unmap_guest(struct kvm *kvm); + int kvm_assign_device(struct kvm *kvm, +@@ -609,6 +610,11 @@ static inline int kvm_iommu_map_pages(struct kvm *kvm, + return 0; + } + ++static inline void kvm_iommu_unmap_pages(struct kvm *kvm, ++ struct kvm_memory_slot *slot) ++{ ++} ++ + static inline int kvm_iommu_map_guest(struct kvm *kvm) + { + return -ENODEV; +diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c +index a457d21..fec1723 100644 +--- a/virt/kvm/iommu.c ++++ b/virt/kvm/iommu.c +@@ -310,6 +310,11 @@ static void kvm_iommu_put_pages(struct kvm *kvm, + } + } + ++void kvm_iommu_unmap_pages(struct kvm *kvm, struct kvm_memory_slot *slot) ++{ ++ kvm_iommu_put_pages(kvm, slot->base_gfn, slot->npages); ++} ++ + static int kvm_iommu_unmap_memslots(struct kvm *kvm) + { + int idx; +@@ -320,7 +325,7 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm) + slots = kvm_memslots(kvm); + + kvm_for_each_memslot(memslot, slots) +- kvm_iommu_put_pages(kvm, memslot->base_gfn, memslot->npages); ++ kvm_iommu_unmap_pages(kvm, memslot); + + srcu_read_unlock(&kvm->srcu, idx); + +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index 42b7393..9739b53 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -808,12 +808,13 @@ int __kvm_set_memory_region(struct kvm *kvm, + if (r) + goto out_free; + +- /* map the pages in iommu page table */ ++ /* map/unmap the pages in iommu page table */ + if (npages) { + r = kvm_iommu_map_pages(kvm, &new); + if (r) + goto out_free; +- } ++ } else ++ kvm_iommu_unmap_pages(kvm, &old); + + r = -ENOMEM; + slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots), diff --git a/kernel.spec b/kernel.spec index 382a397bf..9d50c7cf2 100644 --- a/kernel.spec +++ b/kernel.spec @@ -752,6 +752,9 @@ Patch22000: weird-root-dentry-name-debug.patch #selinux ptrace child permissions Patch22001: selinux-apply-different-permission-to-ptrace-child.patch +#rhbz 814149 814155 +Patch22006: KVM-unmap-pages-from-the-iommu-when-slots-are-removed.patch + # END OF PATCH DEFINITIONS %endif @@ -1453,6 +1456,9 @@ ApplyPatch vgaarb-vga_default_device.patch ApplyPatch x86-microcode-Fix-sysfs-warning-during-module-unload-on-unsupported-CPUs.patch ApplyPatch x86-microcode-Ensure-that-module-is-only-loaded-for-supported-AMD-CPUs.patch +#rhbz 814149 814155 +ApplyPatch KVM-unmap-pages-from-the-iommu-when-slots-are-removed.patch + # END OF PATCH APPLICATIONS %endif @@ -2313,6 +2319,9 @@ fi # ||----w | # || || %changelog +* Thu Apr 19 2012 Justin M. Forbes +- Fix KVM device assignment page leak (rhbz 814149 814155) + * Wed Apr 18 2012 Justin M. Forbes - 3.4.0-0.rc3.git2.1 - Linux v3.4-rc3-36-g592fe89