Skip to content

Commit eab0953

Browse files
keestorvalds
authored andcommitted
binfmt_elf: use ELF_ET_DYN_BASE only for PIE
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: d1fd836 ("mm: split ET_DYN ASLR from mmap ASLR") Link: http://lkml.kernel.org/r/20170621173201.GA114489@beast Signed-off-by: Kees Cook <keescook@chromium.org> Acked-by: Rik van Riel <riel@redhat.com> Cc: Daniel Micay <danielmicay@gmail.com> Cc: Qualys Security Advisory <qsa@qualys.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Dmitry Safonov <dsafonov@virtuozzo.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Grzegorz Andrejczuk <grzegorz.andrejczuk@intel.com> Cc: Masahiro Yamada <yamada.masahiro@socionext.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: James Hogan <james.hogan@imgtec.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Paul Mackerras <paulus@samba.org> Cc: Pratyush Anand <panand@redhat.com> Cc: Russell King <linux@armlinux.org.uk> Cc: Will Deacon <will.deacon@arm.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent c257a34 commit eab0953

File tree

2 files changed

+58
-14
lines changed

2 files changed

+58
-14
lines changed

arch/x86/include/asm/elf.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,13 @@ extern int force_personality32;
245245
#define CORE_DUMP_USE_REGSET
246246
#define ELF_EXEC_PAGESIZE 4096
247247

248-
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
249-
use of this is to invoke "./ld.so someprog" to test out a new version of
250-
the loader. We need to make sure that it is out of the way of the program
251-
that it will "exec", and that there is sufficient room for the brk. */
252-
253-
#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
248+
/*
249+
* This is the base location for PIE (ET_DYN with INTERP) loads. On
250+
* 64-bit, this is raised to 4GB to leave the entire 32-bit address
251+
* space open for things that want to use the area for 32-bit pointers.
252+
*/
253+
#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \
254+
0x100000000UL)
254255

255256
/* This yields a mask that user programs can use to figure out what
256257
instruction set this CPU supports. This could be done in user space,

fs/binfmt_elf.c

+51-8
Original file line numberDiff line numberDiff line change
@@ -927,17 +927,60 @@ static int load_elf_binary(struct linux_binprm *bprm)
927927
elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
928928

929929
vaddr = elf_ppnt->p_vaddr;
930+
/*
931+
* If we are loading ET_EXEC or we have already performed
932+
* the ET_DYN load_addr calculations, proceed normally.
933+
*/
930934
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
931935
elf_flags |= MAP_FIXED;
932936
} else if (loc->elf_ex.e_type == ET_DYN) {
933-
/* Try and get dynamic programs out of the way of the
934-
* default mmap base, as well as whatever program they
935-
* might try to exec. This is because the brk will
936-
* follow the loader, and is not movable. */
937-
load_bias = ELF_ET_DYN_BASE - vaddr;
938-
if (current->flags & PF_RANDOMIZE)
939-
load_bias += arch_mmap_rnd();
940-
load_bias = ELF_PAGESTART(load_bias);
937+
/*
938+
* This logic is run once for the first LOAD Program
939+
* Header for ET_DYN binaries to calculate the
940+
* randomization (load_bias) for all the LOAD
941+
* Program Headers, and to calculate the entire
942+
* size of the ELF mapping (total_size). (Note that
943+
* load_addr_set is set to true later once the
944+
* initial mapping is performed.)
945+
*
946+
* There are effectively two types of ET_DYN
947+
* binaries: programs (i.e. PIE: ET_DYN with INTERP)
948+
* and loaders (ET_DYN without INTERP, since they
949+
* _are_ the ELF interpreter). The loaders must
950+
* be loaded away from programs since the program
951+
* may otherwise collide with the loader (especially
952+
* for ET_EXEC which does not have a randomized
953+
* position). For example to handle invocations of
954+
* "./ld.so someprog" to test out a new version of
955+
* the loader, the subsequent program that the
956+
* loader loads must avoid the loader itself, so
957+
* they cannot share the same load range. Sufficient
958+
* room for the brk must be allocated with the
959+
* loader as well, since brk must be available with
960+
* the loader.
961+
*
962+
* Therefore, programs are loaded offset from
963+
* ELF_ET_DYN_BASE and loaders are loaded into the
964+
* independently randomized mmap region (0 load_bias
965+
* without MAP_FIXED).
966+
*/
967+
if (elf_interpreter) {
968+
load_bias = ELF_ET_DYN_BASE;
969+
if (current->flags & PF_RANDOMIZE)
970+
load_bias += arch_mmap_rnd();
971+
elf_flags |= MAP_FIXED;
972+
} else
973+
load_bias = 0;
974+
975+
/*
976+
* Since load_bias is used for all subsequent loading
977+
* calculations, we must lower it by the first vaddr
978+
* so that the remaining calculations based on the
979+
* ELF vaddrs will be correctly offset. The result
980+
* is then page aligned.
981+
*/
982+
load_bias = ELF_PAGESTART(load_bias - vaddr);
983+
941984
total_size = total_mapping_size(elf_phdata,
942985
loc->elf_ex.e_phnum);
943986
if (!total_size) {

0 commit comments

Comments
 (0)