summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin M. Forbes <jforbes@redhat.com>2012-04-19 09:47:12 -0500
committerJustin M. Forbes <jforbes@redhat.com>2012-04-19 09:47:12 -0500
commit7d3a78564ab43271375c063fe37bd9bdd0296d37 (patch)
treeae014eeb4bf2d6375589c2230a4ae215dae1827c
parentbd6c35f05a2cf5e5015455691bfba2e57712902c (diff)
downloadkernel-7d3a78564ab43271375c063fe37bd9bdd0296d37.tar.gz
kernel-7d3a78564ab43271375c063fe37bd9bdd0296d37.tar.xz
kernel-7d3a78564ab43271375c063fe37bd9bdd0296d37.zip
Fix KVM device assignment page leak
-rw-r--r--KVM-unmap-pages-from-the-iommu-when-slots-are-removed.patch92
-rw-r--r--kernel.spec9
2 files changed, 101 insertions, 0 deletions
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 <alex.williamson@redhat.com>
+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 <alex.williamson@redhat.com>
+ Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
+
+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 <jforbes@redhat.com>
+- Fix KVM device assignment page leak (rhbz 814149 814155)
+
* Wed Apr 18 2012 Justin M. Forbes <jforbes@redhat.com> - 3.4.0-0.rc3.git2.1
- Linux v3.4-rc3-36-g592fe89