From: Sona Sarmadi Date: Tue, 27 Jan 2015 09:22:10 +0000 (+0100) Subject: kvm-iommu: CVE-2014-3601, CVE-2014-8369 X-Git-Tag: 2.1~534^2~22 X-Git-Url: https://code.ossystems.io/gitweb?a=commitdiff_plain;h=8cde62241772c928769ae77344325e741c414e0f;p=meta-freescale.git kvm-iommu: CVE-2014-3601, CVE-2014-8369 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 --- 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 index 00000000..e19a3c10 --- /dev/null +++ b/meta-fsl-ppc/recipes-kernel/linux/files/0001-kvm-iommu-CVE-2014-3601.patch @@ -0,0 +1,94 @@ +From e35b1e9f17e0567f96502f3a2a31dace727ed3da Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +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 +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Paolo Bonzini +Signed-off-by: Jiri Slaby +Signed-off-by: Sona Sarmadi +--- + 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 index 00000000..e43771cc --- /dev/null +++ b/meta-fsl-ppc/recipes-kernel/linux/files/0002-kvm-iommu-CVE-2014-8369.patch @@ -0,0 +1,86 @@ +From 248541357433e3035d954435dafcdb9e70afee4e Mon Sep 17 00:00:00 2001 +From: Quentin Casasnovas +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 +Signed-off-by: Vegard Nossum +Signed-off-by: Jamie Iles +Reviewed-by: Sasha Levin +Signed-off-by: Paolo Bonzini +Signed-off-by: Jiri Slaby +Signed-off-by: Sona Sarmadi +--- + 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 + diff --git a/meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb b/meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb index 195b4777..5993b59a 100644 --- a/meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb +++ b/meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb @@ -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"