[linux] 02/03: binfmt_elf: use ELF_ET_DYN_BASE only for PIE (CVE-2017-1000370, CVE-2017-1000371)

debian-kernel at lists.debian.org debian-kernel at lists.debian.org
Thu Aug 17 20:24:10 UTC 2017


This is an automated email from the git hooks/post-receive script.

benh pushed a commit to branch stretch-security
in repository linux.

commit 69821fc1d60ac8ee4986dd510eaf2886a9c3b74c
Author: Ben Hutchings <ben at decadent.org.uk>
Date:   Sun Aug 6 13:30:48 2017 +0100

    binfmt_elf: use ELF_ET_DYN_BASE only for PIE (CVE-2017-1000370, CVE-2017-1000371)
---
 debian/changelog                                   |   2 +
 ...nfmt_elf-use-elf_et_dyn_base-only-for-pie.patch | 167 +++++++++++++++++++++
 debian/patches/series                              |   1 +
 3 files changed, 170 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 254ab93..adc1c60 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,8 @@
 linux (4.9.30-2+deb9u4) UNRELEASED; urgency=medium
 
   * [x86] KVM: fix singlestepping over syscall (CVE-2017-7518)
+  * binfmt_elf: use ELF_ET_DYN_BASE only for PIE (CVE-2017-1000370,
+    CVE-2017-1000371)
 
  -- Ben Hutchings <ben at decadent.org.uk>  Sun, 06 Aug 2017 15:21:20 +0100
 
diff --git a/debian/patches/bugfix/all/binfmt_elf-use-elf_et_dyn_base-only-for-pie.patch b/debian/patches/bugfix/all/binfmt_elf-use-elf_et_dyn_base-only-for-pie.patch
new file mode 100644
index 0000000..83150d1
--- /dev/null
+++ b/debian/patches/bugfix/all/binfmt_elf-use-elf_et_dyn_base-only-for-pie.patch
@@ -0,0 +1,167 @@
+From: Kees Cook <keescook at chromium.org>
+Date: Mon, 10 Jul 2017 15:52:37 -0700
+Subject: binfmt_elf: use ELF_ET_DYN_BASE only for PIE
+Origin: https://git.kernel.org/linus/eab09532d40090698b05a07c1c87f39fdbc5fab5
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-1000370
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-1000371
+
+The ELF_ET_DYN_BASE position was originally intended to keep loaders
+away from ET_EXEC binaries.  (For example, running "/lib/ld-linux.so.2
+/bin/cat" might cause the subsequent load of /bin/cat into where the
+loader had been loaded.)
+
+With the advent of PIE (ET_DYN binaries with an INTERP Program Header),
+ELF_ET_DYN_BASE continued to be used since the kernel was only looking
+at ET_DYN.  However, since ELF_ET_DYN_BASE is traditionally set at the
+top 1/3rd of the TASK_SIZE, a substantial portion of the address space
+is unused.
+
+For 32-bit tasks when RLIMIT_STACK is set to RLIM_INFINITY, programs are
+loaded above the mmap region.  This means they can be made to collide
+(CVE-2017-1000370) or nearly collide (CVE-2017-1000371) with
+pathological stack regions.
+
+Lowering ELF_ET_DYN_BASE solves both by moving programs below the mmap
+region in all cases, and will now additionally avoid programs falling
+back to the mmap region by enforcing MAP_FIXED for program loads (i.e.
+if it would have collided with the stack, now it will fail to load
+instead of falling back to the mmap region).
+
+To allow for a lower ELF_ET_DYN_BASE, loaders (ET_DYN without INTERP)
+are loaded into the mmap region, leaving space available for either an
+ET_EXEC binary with a fixed location or PIE being loaded into mmap by
+the loader.  Only PIE programs are loaded offset from ELF_ET_DYN_BASE,
+which means architectures can now safely lower their values without risk
+of loaders colliding with their subsequently loaded programs.
+
+For 64-bit, ELF_ET_DYN_BASE is best set to 4GB to allow runtimes to use
+the entire 32-bit address space for 32-bit pointers.
+
+Thanks to PaX Team, Daniel Micay, and Rik van Riel for inspiration and
+suggestions on how to implement this solution.
+
+Fixes: d1fd836dcf00 ("mm: split ET_DYN ASLR from mmap ASLR")
+Link: http://lkml.kernel.org/r/20170621173201.GA114489@beast
+Signed-off-by: Kees Cook <keescook at chromium.org>
+Acked-by: Rik van Riel <riel at redhat.com>
+Cc: Daniel Micay <danielmicay at gmail.com>
+Cc: Qualys Security Advisory <qsa at qualys.com>
+Cc: Thomas Gleixner <tglx at linutronix.de>
+Cc: Ingo Molnar <mingo at redhat.com>
+Cc: "H. Peter Anvin" <hpa at zytor.com>
+Cc: Alexander Viro <viro at zeniv.linux.org.uk>
+Cc: Dmitry Safonov <dsafonov at virtuozzo.com>
+Cc: Andy Lutomirski <luto at amacapital.net>
+Cc: Grzegorz Andrejczuk <grzegorz.andrejczuk at intel.com>
+Cc: Masahiro Yamada <yamada.masahiro at socionext.com>
+Cc: Benjamin Herrenschmidt <benh at kernel.crashing.org>
+Cc: Catalin Marinas <catalin.marinas at arm.com>
+Cc: Heiko Carstens <heiko.carstens at de.ibm.com>
+Cc: James Hogan <james.hogan at imgtec.com>
+Cc: Martin Schwidefsky <schwidefsky at de.ibm.com>
+Cc: Michael Ellerman <mpe at ellerman.id.au>
+Cc: Paul Mackerras <paulus at samba.org>
+Cc: Pratyush Anand <panand at redhat.com>
+Cc: Russell King <linux at armlinux.org.uk>
+Cc: Will Deacon <will.deacon at arm.com>
+Cc: <stable at vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+---
+ arch/x86/include/asm/elf.h | 13 +++++-----
+ fs/binfmt_elf.c            | 59 +++++++++++++++++++++++++++++++++++++++-------
+ 2 files changed, 58 insertions(+), 14 deletions(-)
+
+--- a/arch/x86/include/asm/elf.h
++++ b/arch/x86/include/asm/elf.h
+@@ -246,12 +246,13 @@ extern int force_personality32;
+ #define CORE_DUMP_USE_REGSET
+ #define ELF_EXEC_PAGESIZE	4096
+ 
+-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+-   use of this is to invoke "./ld.so someprog" to test out a new version of
+-   the loader.  We need to make sure that it is out of the way of the program
+-   that it will "exec", and that there is sufficient room for the brk.  */
+-
+-#define ELF_ET_DYN_BASE		(TASK_SIZE / 3 * 2)
++/*
++ * This is the base location for PIE (ET_DYN with INTERP) loads. On
++ * 64-bit, this is raised to 4GB to leave the entire 32-bit address
++ * space open for things that want to use the area for 32-bit pointers.
++ */
++#define ELF_ET_DYN_BASE		(mmap_is_ia32() ? 0x000400000UL : \
++						  0x100000000UL)
+ 
+ /* This yields a mask that user programs can use to figure out what
+    instruction set this CPU supports.  This could be done in user space,
+--- a/fs/binfmt_elf.c
++++ b/fs/binfmt_elf.c
+@@ -911,17 +911,60 @@ static int load_elf_binary(struct linux_
+ 		elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
+ 
+ 		vaddr = elf_ppnt->p_vaddr;
++		/*
++		 * If we are loading ET_EXEC or we have already performed
++		 * the ET_DYN load_addr calculations, proceed normally.
++		 */
+ 		if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
+ 			elf_flags |= MAP_FIXED;
+ 		} else if (loc->elf_ex.e_type == ET_DYN) {
+-			/* Try and get dynamic programs out of the way of the
+-			 * default mmap base, as well as whatever program they
+-			 * might try to exec.  This is because the brk will
+-			 * follow the loader, and is not movable.  */
+-			load_bias = ELF_ET_DYN_BASE - vaddr;
+-			if (current->flags & PF_RANDOMIZE)
+-				load_bias += arch_mmap_rnd();
+-			load_bias = ELF_PAGESTART(load_bias);
++			/*
++			 * This logic is run once for the first LOAD Program
++			 * Header for ET_DYN binaries to calculate the
++			 * randomization (load_bias) for all the LOAD
++			 * Program Headers, and to calculate the entire
++			 * size of the ELF mapping (total_size). (Note that
++			 * load_addr_set is set to true later once the
++			 * initial mapping is performed.)
++			 *
++			 * There are effectively two types of ET_DYN
++			 * binaries: programs (i.e. PIE: ET_DYN with INTERP)
++			 * and loaders (ET_DYN without INTERP, since they
++			 * _are_ the ELF interpreter). The loaders must
++			 * be loaded away from programs since the program
++			 * may otherwise collide with the loader (especially
++			 * for ET_EXEC which does not have a randomized
++			 * position). For example to handle invocations of
++			 * "./ld.so someprog" to test out a new version of
++			 * the loader, the subsequent program that the
++			 * loader loads must avoid the loader itself, so
++			 * they cannot share the same load range. Sufficient
++			 * room for the brk must be allocated with the
++			 * loader as well, since brk must be available with
++			 * the loader.
++			 *
++			 * Therefore, programs are loaded offset from
++			 * ELF_ET_DYN_BASE and loaders are loaded into the
++			 * independently randomized mmap region (0 load_bias
++			 * without MAP_FIXED).
++			 */
++			if (elf_interpreter) {
++				load_bias = ELF_ET_DYN_BASE;
++				if (current->flags & PF_RANDOMIZE)
++					load_bias += arch_mmap_rnd();
++				elf_flags |= MAP_FIXED;
++			} else
++				load_bias = 0;
++
++			/*
++			 * Since load_bias is used for all subsequent loading
++			 * calculations, we must lower it by the first vaddr
++			 * so that the remaining calculations based on the
++			 * ELF vaddrs will be correctly offset. The result
++			 * is then page aligned.
++			 */
++			load_bias = ELF_PAGESTART(load_bias - vaddr);
++
+ 			total_size = total_mapping_size(elf_phdata,
+ 							loc->elf_ex.e_phnum);
+ 			if (!total_size) {
diff --git a/debian/patches/series b/debian/patches/series
index 8aee0bb..e9c3182 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -133,6 +133,7 @@ bugfix/all/mqueue-fix-a-use-after-free-in-sys_mq_notify.patch
 bugfix/all/fs-exec.c-account-for-argv-envp-pointers.patch
 bugfix/all/dentry-name-snapshots.patch
 bugfix/x86/kvm-x86-fix-singlestepping-over-syscall.patch
+bugfix/all/binfmt_elf-use-elf_et_dyn_base-only-for-pie.patch
 
 # Fix exported symbol versions
 bugfix/ia64/revert-ia64-move-exports-to-definitions.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/kernel/linux.git



More information about the Kernel-svn-changes mailing list