[kernel/f20] CVE-2014-9585 ASLR brute-force possible for vdso (rhbz 1181054 1181056)

Josh Boyer jwboyer at fedoraproject.org
Mon Jan 12 18:00:41 UTC 2015


commit 1578b2969a2d367696fbcbaba86ad034cd7770f5
Author: Josh Boyer <jwboyer at fedoraproject.org>
Date:   Mon Jan 12 13:00:46 2015 -0500

    CVE-2014-9585 ASLR brute-force possible for vdso (rhbz 1181054 1181056)

 kernel.spec                                        |    7 +
 ...-Fix-the-vdso-address-randomization-algor.patch |  128 ++++++++++++++++++++
 2 files changed, 135 insertions(+), 0 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index 9870f1b..5b92f38 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -780,6 +780,9 @@ Patch26130: acpi-video-Add-disable_native_backlight-quirk-for-De.patch
 #rhbz 1094948
 Patch26131: acpi-video-Add-disable_native_backlight-quirk-for-Sa.patch
 
+#CVE-2014-9585 rhbz 1181054 1181056
+Patch26132: x86_64-vdso-Fix-the-vdso-address-randomization-algor.patch
+
 # git clone ssh://git.fedorahosted.org/git/kernel-arm64.git, git diff master...devel
 Patch30000: kernel-arm64.patch
 
@@ -1530,6 +1533,9 @@ ApplyPatch acpi-video-Add-disable_native_backlight-quirk-for-De.patch
 #rhbz 1094948
 ApplyPatch acpi-video-Add-disable_native_backlight-quirk-for-Sa.patch
 
+#CVE-2014-9585 rhbz 1181054 1181056
+ApplyPatch x86_64-vdso-Fix-the-vdso-address-randomization-algor.patch
+
 %if 0%{?aarch64patches}
 ApplyPatch kernel-arm64.patch
 %ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does.
@@ -2349,6 +2355,7 @@ fi
 #                 ||     ||
 %changelog
 * Mon Jan 12 2015 Josh Boyer <jwboyer at fedoraproject.org>
+- CVE-2014-9585 ASLR brute-force possible for vdso (rhbz 1181054 1181056)
 - Backlight fixes for Samsung and Dell machines (rhbz 1094948 1115713 1163574)
 - Add various UAS quirks (rhbz 1124119)
 - Add patch to fix loop in VDSO (rhbz 1178975)
diff --git a/x86_64-vdso-Fix-the-vdso-address-randomization-algor.patch b/x86_64-vdso-Fix-the-vdso-address-randomization-algor.patch
new file mode 100644
index 0000000..8d7f5f1
--- /dev/null
+++ b/x86_64-vdso-Fix-the-vdso-address-randomization-algor.patch
@@ -0,0 +1,128 @@
+From: Andy Lutomirski <luto at amacapital.net>
+Date: Fri, 19 Dec 2014 16:04:11 -0800
+Subject: [PATCH] x86_64, vdso: Fix the vdso address randomization algorithm
+
+The theory behind vdso randomization is that it's mapped at a random
+offset above the top of the stack.  To avoid wasting a page of
+memory for an extra page table, the vdso isn't supposed to extend
+past the lowest PMD into which it can fit.  Other than that, the
+address should be a uniformly distributed address that meets all of
+the alignment requirements.
+
+The current algorithm is buggy: the vdso has about a 50% probability
+of being at the very end of a PMD.  The current algorithm also has a
+decent chance of failing outright due to incorrect handling of the
+case where the top of the stack is near the top of its PMD.
+
+This fixes the implementation.  The paxtest estimate of vdso
+"randomisation" improves from 11 bits to 18 bits.  (Disclaimer: I
+don't know what the paxtest code is actually calculating.)
+
+It's worth noting that this algorithm is inherently biased: the vdso
+is more likely to end up near the end of its PMD than near the
+beginning.  Ideally we would either nix the PMD sharing requirement
+or jointly randomize the vdso and the stack to reduce the bias.
+
+In the mean time, this is a considerable improvement with basically
+no risk of compatibility issues, since the allowed outputs of the
+algorithm are unchanged.
+
+As an easy test, doing this:
+
+for i in `seq 10000`
+  do grep -P vdso /proc/self/maps |cut -d- -f1
+done |sort |uniq -d
+
+used to produce lots of output (1445 lines on my most recent run).
+A tiny subset looks like this:
+
+7fffdfffe000
+7fffe01fe000
+7fffe05fe000
+7fffe07fe000
+7fffe09fe000
+7fffe0bfe000
+7fffe0dfe000
+
+Note the suspicious fe000 endings.  With the fix, I get a much more
+palatable 76 repeated addresses.
+
+Reviewed-by: Kees Cook <keescook at chromium.org>
+Cc: stable at vger.kernel.org
+Signed-off-by: Andy Lutomirski <luto at amacapital.net>
+---
+ arch/x86/vdso/vma.c | 45 +++++++++++++++++++++++++++++----------------
+ 1 file changed, 29 insertions(+), 16 deletions(-)
+
+diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
+index 970463b566cf..208c2206df46 100644
+--- a/arch/x86/vdso/vma.c
++++ b/arch/x86/vdso/vma.c
+@@ -54,12 +54,17 @@ subsys_initcall(init_vdso);
+ 
+ struct linux_binprm;
+ 
+-/* Put the vdso above the (randomized) stack with another randomized offset.
+-   This way there is no hole in the middle of address space.
+-   To save memory make sure it is still in the same PTE as the stack top.
+-   This doesn't give that many random bits.
+-
+-   Only used for the 64-bit and x32 vdsos. */
++/*
++ * Put the vdso above the (randomized) stack with another randomized
++ * offset.  This way there is no hole in the middle of address space.
++ * To save memory make sure it is still in the same PTE as the stack
++ * top.  This doesn't give that many random bits.
++ *
++ * Note that this algorithm is imperfect: the distribution of the vdso
++ * start address within a PMD is biased toward the end.
++ *
++ * Only used for the 64-bit and x32 vdsos.
++ */
+ static unsigned long vdso_addr(unsigned long start, unsigned len)
+ {
+ #ifdef CONFIG_X86_32
+@@ -67,22 +72,30 @@ static unsigned long vdso_addr(unsigned long start, unsigned len)
+ #else
+ 	unsigned long addr, end;
+ 	unsigned offset;
+-	end = (start + PMD_SIZE - 1) & PMD_MASK;
++
++	/*
++	 * Round up the start address.  It can start out unaligned as a result
++	 * of stack start randomization.
++	 */
++	start = PAGE_ALIGN(start);
++
++	/* Round the lowest possible end address up to a PMD boundary. */
++	end = (start + len + PMD_SIZE - 1) & PMD_MASK;
+ 	if (end >= TASK_SIZE_MAX)
+ 		end = TASK_SIZE_MAX;
+ 	end -= len;
+-	/* This loses some more bits than a modulo, but is cheaper */
+-	offset = get_random_int() & (PTRS_PER_PTE - 1);
+-	addr = start + (offset << PAGE_SHIFT);
+-	if (addr >= end)
+-		addr = end;
++
++	if (end > start) {
++		offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
++		addr = start + (offset << PAGE_SHIFT);
++	} else {
++		addr = start;
++	}
+ 
+ 	/*
+-	 * page-align it here so that get_unmapped_area doesn't
+-	 * align it wrongfully again to the next page. addr can come in 4K
+-	 * unaligned here as a result of stack start randomization.
++	 * Forcibly align the final address in case we have a hardware
++	 * issue that requires alignment for performance reasons.
+ 	 */
+-	addr = PAGE_ALIGN(addr);
+ 	addr = align_vdso_addr(addr);
+ 
+ 	return addr;
+-- 
+2.1.0
+


More information about the scm-commits mailing list