Skip to content
  • Kees Cook's avatar
    binfmt_elf: move brk out of mmap when doing direct loader exec · bbdc6076
    Kees Cook authored
    Commmit eab09532 ("binfmt_elf: use ELF_ET_DYN_BASE only for PIE"),
    made changes in the rare case when the ELF loader was directly invoked
    (e.g to set a non-inheritable LD_LIBRARY_PATH, testing new versions of
    the loader), by moving into the mmap region to avoid both ET_EXEC and
    PIE binaries.  This had the effect of also moving the brk region into
    mmap, which could lead to the stack and brk being arbitrarily close to
    each other.  An unlucky process wouldn't get its requested stack size
    and stack allocations could end up scribbling on the heap.
    
    This is illustrated here.  In the case of using the loader directly, brk
    (so helpfully identified as "[heap]") is allocated with the _loader_ not
    the binary.  For example, with ASLR entirely disabled, you can see this
    more clearly:
    
    $ /bin/cat /proc/self/maps
    555555554000-55555555c000 r-xp 00000000 ... /bin/cat
    55555575b000-55555575c000 r--p 00007000 ... /bin/cat
    55555575c000-55555575d000 rw-p 00008000 ... /bin/cat
    55555575d000-55555577e000 rw-p 00000000 ... [heap]
    ...
    7ffff7ff7000-7ffff7ffa000 r--p 00000000 ... [vvar]
    7ffff7ffa000-7ffff7ffc000 r-xp 00000000 ... [vdso]
    7ffff7ffc000-7ffff7ffd000 r--p 00027000 ... /lib/x86_64-linux-gnu/ld-2.27.so
    7ffff7ffd000-7ffff7ffe000 rw-p 00028000 ... /lib/x86_64-linux-gnu/ld-2.27.so
    7ffff7ffe000-7ffff7fff000 rw-p 00000000 ...
    7ffffffde000-7ffffffff000 rw-p 00000000 ... [stack]
    
    $ /lib/x86_64-linux-gnu/ld-2.27.so /bin/cat /proc/self/maps
    ...
    7ffff7bcc000-7ffff7bd4000 r-xp 00000000 ... /bin/cat
    7ffff7bd4000-7ffff7dd3000 ---p 00008000 ... /bin/cat
    7ffff7dd3000-7ffff7dd4000 r--p 00007000 ... /bin/cat
    7ffff7dd4000-7ffff7dd5000 rw-p 00008000 ... /bin/cat
    7ffff7dd5000-7ffff7dfc000 r-xp 00000000 ... /lib/x86_64-linux-gnu/ld-2.27.so
    7ffff7fb2000-7ffff7fd6000 rw-p 00000000 ...
    7ffff7ff7000-7ffff7ffa000 r--p 00000000 ... [vvar]
    7ffff7ffa000-7ffff7ffc000 r-xp 00000000 ... [vdso]
    7ffff7ffc000-7ffff7ffd000 r--p 00027000 ... /lib/x86_64-linux-gnu/ld-2.27.so
    7ffff7ffd000-7ffff7ffe000 rw-p 00028000 ... /lib/x86_64-linux-gnu/ld-2.27.so
    7ffff7ffe000-7ffff8020000 rw-p 00000000 ... [heap]
    7ffffffde000-7ffffffff000 rw-p 00000000 ... [stack]
    
    The solution is to move brk out of mmap and into ELF_ET_DYN_BASE since
    nothing is there in the direct loader case (and ET_EXEC is still far
    away at 0x400000).  Anything that ran before should still work (i.e.
    the ultimately-launched binary already had the brk very far from its
    text, so this should be no different from a COMPAT_BRK standpoint).  The
    only risk I see here is that if someone started to suddenly depend on
    the entire memory space lower than the mmap region being available when
    launching binaries via a direct loader execs which seems highly
    unlikely, I'd hope: this would mean a binary would _not_ work when
    exec()ed normally.
    
    (Note that this is only done under CONFIG_ARCH_HAS_ELF_RANDOMIZATION
    when randomization is turned on.)
    
    Link: http://lkml.kernel.org/r/20190422225727.GA21011@beast
    Link: https://lkml.kernel.org/r/CAGXu5jJ5sj3emOT2QPxQkNQk0qbU6zEfu9=Omfhx_p0nCKPSjA@mail.gmail.com
    Fixes: eab09532
    
     ("binfmt_elf: use ELF_ET_DYN_BASE only for PIE")
    Signed-off-by: default avatarKees Cook <keescook@chromium.org>
    Reported-by: default avatarAli Saidi <alisaidi@amazon.com>
    Cc: Ali Saidi <alisaidi@amazon.com>
    Cc: Guenter Roeck <linux@roeck-us.net>
    Cc: Michal Hocko <mhocko@suse.com>
    Cc: Matthew Wilcox <willy@infradead.org>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Jann Horn <jannh@google.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    bbdc6076