]> code.ossystems Code Review - meta-freescale.git/commitdiff
kvm-iommu: CVE-2014-3601, CVE-2014-8369
authorSona Sarmadi <sona.sarmadi@enea.com>
Tue, 27 Jan 2015 09:22:10 +0000 (10:22 +0100)
committerZhenhua Luo <zhenhua.luo@freescale.com>
Tue, 3 Feb 2015 02:05:41 +0000 (10:05 +0800)
CVE-2014-3601
Fixes the third parameter of kvm_iommu_put_pages
The third parameter of kvm_iommu_put_pages is wrong,
It should be 'gfn - slot->base_gfn'.

CVE-2014-8369
Fixes excessive pages un-pinning in kvm_iommu_map error path.
(This vulnerability exists because of an incorrect fix for CVE-2014-3601

Reference:
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3601
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-8369
https://bugzilla.redhat.com/show_bug.cgi?id=1156518
https://lkml.org/lkml/2014/10/24/460

Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
meta-fsl-ppc/recipes-kernel/linux/files/0001-kvm-iommu-CVE-2014-3601.patch [new file with mode: 0644]
meta-fsl-ppc/recipes-kernel/linux/files/0002-kvm-iommu-CVE-2014-8369.patch [new file with mode: 0644]
meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb

diff --git a/meta-fsl-ppc/recipes-kernel/linux/files/0001-kvm-iommu-CVE-2014-3601.patch b/meta-fsl-ppc/recipes-kernel/linux/files/0001-kvm-iommu-CVE-2014-3601.patch
new file mode 100644 (file)
index 0000000..e19a3c1
--- /dev/null
@@ -0,0 +1,94 @@
+From e35b1e9f17e0567f96502f3a2a31dace727ed3da Mon Sep 17 00:00:00 2001
+From: "Michael S. Tsirkin" <mst@redhat.com>
+Date: Tue, 19 Aug 2014 19:14:50 +0800
+Subject: [PATCH] kvm: iommu: fix the third parameter of kvm_iommu_put_pages
+ (CVE-2014-3601)
+
+commit 350b8bdd689cd2ab2c67c8a86a0be86cfa0751a7 upstream.
+
+The third parameter of kvm_iommu_put_pages is wrong,
+It should be 'gfn - slot->base_gfn'.
+
+By making gfn very large, malicious guest or userspace can cause kvm to
+go to this error path, and subsequently to pass a huge value as size.
+Alternatively if gfn is small, then pages would be pinned but never
+unpinned, causing host memory leak and local DOS.
+
+Passing a reasonable but large value could be the most dangerous case,
+because it would unpin a page that should have stayed pinned, and thus
+allow the device to DMA into arbitrary memory.  However, this cannot
+happen because of the condition that can trigger the error:
+
+- out of memory (where you can't allocate even a single page)
+  should not be possible for the attacker to trigger
+
+- when exceeding the iommu's address space, guest pages after gfn
+  will also exceed the iommu's address space, and inside
+  kvm_iommu_put_pages() the iommu_iova_to_phys() will fail.  The
+  page thus would not be unpinned at all.
+
+Upstream-Status: Backport
+
+Reported-by: Jack Morgenstein <jackm@mellanox.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
+---
+ virt/kvm/iommu.c | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
+index c329c8f..dec9971 100644
+--- a/virt/kvm/iommu.c
++++ b/virt/kvm/iommu.c
+@@ -61,6 +61,14 @@ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
+       return pfn;
+ }
++static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
++{
++      unsigned long i;
++
++      for (i = 0; i < npages; ++i)
++              kvm_release_pfn_clean(pfn + i);
++}
++
+ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
+ {
+       gfn_t gfn, end_gfn;
+@@ -123,6 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
+               if (r) {
+                       printk(KERN_ERR "kvm_iommu_map_address:"
+                              "iommu failed to map pfn=%llx\n", pfn);
++                      kvm_unpin_pages(kvm, pfn, page_size);
+                       goto unmap_pages;
+               }
+@@ -134,7 +143,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
+       return 0;
+ unmap_pages:
+-      kvm_iommu_put_pages(kvm, slot->base_gfn, gfn);
++      kvm_iommu_put_pages(kvm, slot->base_gfn, gfn - slot->base_gfn);
+       return r;
+ }
+@@ -272,14 +281,6 @@ out_unlock:
+       return r;
+ }
+-static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
+-{
+-      unsigned long i;
+-
+-      for (i = 0; i < npages; ++i)
+-              kvm_release_pfn_clean(pfn + i);
+-}
+-
+ static void kvm_iommu_put_pages(struct kvm *kvm,
+                               gfn_t base_gfn, unsigned long npages)
+ {
+-- 
+1.9.1
+
diff --git a/meta-fsl-ppc/recipes-kernel/linux/files/0002-kvm-iommu-CVE-2014-8369.patch b/meta-fsl-ppc/recipes-kernel/linux/files/0002-kvm-iommu-CVE-2014-8369.patch
new file mode 100644 (file)
index 0000000..e43771c
--- /dev/null
@@ -0,0 +1,86 @@
+From 248541357433e3035d954435dafcdb9e70afee4e Mon Sep 17 00:00:00 2001
+From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
+Date: Fri, 17 Oct 2014 22:55:59 +0200
+Subject: [PATCH] kvm: fix excessive pages un-pinning in kvm_iommu_map error
+ path.
+
+commit 3d32e4dbe71374a6780eaf51d719d76f9a9bf22f upstream.
+
+The third parameter of kvm_unpin_pages() when called from
+kvm_iommu_map_pages() is wrong, it should be the number of pages to un-pin
+and not the page size.
+
+This error was facilitated with an inconsistent API: kvm_pin_pages() takes
+a size, but kvn_unpin_pages() takes a number of pages, so fix the problem
+by matching the two.
+
+This was introduced by commit 350b8bd ("kvm: iommu: fix the third parameter
+of kvm_iommu_put_pages (CVE-2014-3601)"), which fixes the lack of
+un-pinning for pages intended to be un-pinned (i.e. memory leak) but
+unfortunately potentially aggravated the number of pages we un-pin that
+should have stayed pinned. As far as I understand though, the same
+practical mitigations apply.
+
+This issue was found during review of Red Hat 6.6 patches to prepare
+Ksplice rebootless updates.
+
+Thanks to Vegard for his time on a late Friday evening to help me in
+understanding this code.
+
+Fix for CVE-2014-8369
+
+Upstream-Status: Backport
+
+Fixes: 350b8bd ("kvm: iommu: fix the third parameter of... (CVE-2014-3601)")
+Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
+Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
+Signed-off-by: Jamie Iles <jamie.iles@oracle.com>
+Reviewed-by: Sasha Levin <sasha.levin@oracle.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
+---
+ virt/kvm/iommu.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
+index dec9971..a650aa4 100644
+--- a/virt/kvm/iommu.c
++++ b/virt/kvm/iommu.c
+@@ -43,13 +43,13 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
+                               gfn_t base_gfn, unsigned long npages);
+ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
+-                         unsigned long size)
++                         unsigned long npages)
+ {
+       gfn_t end_gfn;
+       pfn_t pfn;
+       pfn     = gfn_to_pfn_memslot(slot, gfn);
+-      end_gfn = gfn + (size >> PAGE_SHIFT);
++      end_gfn = gfn + npages;
+       gfn    += 1;
+       if (is_error_noslot_pfn(pfn))
+@@ -119,7 +119,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
+                * Pin all pages we are about to map in memory. This is
+                * important because we unmap and unpin in 4kb steps later.
+                */
+-              pfn = kvm_pin_pages(slot, gfn, page_size);
++              pfn = kvm_pin_pages(slot, gfn, page_size >> PAGE_SHIFT);
+               if (is_error_noslot_pfn(pfn)) {
+                       gfn += 1;
+                       continue;
+@@ -131,7 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
+               if (r) {
+                       printk(KERN_ERR "kvm_iommu_map_address:"
+                              "iommu failed to map pfn=%llx\n", pfn);
+-                      kvm_unpin_pages(kvm, pfn, page_size);
++                      kvm_unpin_pages(kvm, pfn, page_size >> PAGE_SHIFT);
+                       goto unmap_pages;
+               }
+-- 
+1.9.1
+
index 195b47771db90114760d44b1fff790d23879b721..5993b59a570866b95f171a0d56465db45b8f7f24 100644 (file)
@@ -17,6 +17,8 @@ SRC_URI = "git://git.freescale.com/ppc/sdk/linux.git;nobranch=1 \
     file://0002-HID-CVE-2014-3182.patch \
     file://0003-HID-CVE-2014-3184.patch \
     file://0004-USB-CVE-2014-3185.patch \
+    file://0001-kvm-iommu-CVE-2014-3601.patch \
+    file://0002-kvm-iommu-CVE-2014-8369.patch \
 "
 SRCREV = "6619b8b55796cdf0cec04b66a71288edd3057229"