summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@fedoraproject.org>2015-01-12 13:00:46 -0500
committerJosh Boyer <jwboyer@fedoraproject.org>2015-01-12 13:00:49 -0500
commitdca3c158ea1942845f8d148e06bf13908574959d (patch)
tree5fd72f3b2134952c520f1272fbe6ad0c6fcd8f5b
parent5ef0eabc68a877321b20f94cd63efa16cc2350da (diff)
downloadkernel-dca3c158ea1942845f8d148e06bf13908574959d.tar.gz
kernel-dca3c158ea1942845f8d148e06bf13908574959d.tar.xz
kernel-dca3c158ea1942845f8d148e06bf13908574959d.zip
CVE-2014-9585 ASLR brute-force possible for vdso (rhbz 1181054 1181056)
-rw-r--r--kernel.spec7
-rw-r--r--x86_64-vdso-Fix-the-vdso-address-randomization-algor.patch128
2 files changed, 135 insertions, 0 deletions
diff --git a/kernel.spec b/kernel.spec
index 0f84dc59..50103ff1 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -666,6 +666,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
@@ -1441,6 +1444,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.
@@ -2316,6 +2322,7 @@ fi
# || ||
%changelog
* Mon Jan 12 2015 Josh Boyer <jwboyer@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 00000000..8d7f5f1c
--- /dev/null
+++ b/x86_64-vdso-Fix-the-vdso-address-randomization-algor.patch
@@ -0,0 +1,128 @@
+From: Andy Lutomirski <luto@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@chromium.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Andy Lutomirski <luto@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
+