Re: Linux ELF loader vulnerabilities

From: Pavel Kankovsky (peak_at_argo.troja.mff.cuni.cz)
Date: 11/11/04

  • Next message: Noam Rathaus: "Contact in HP related to OpenView / Coda"
    Date: Thu, 11 Nov 2004 20:52:27 +0100 (MET)
    To: security@isec.pl
    
    

    On Wed, 10 Nov 2004, Paul Starzetz wrote:

    > One of the Linux format loaders is the ELF (Executable and Linkable
    > Format) loader. Nowadays ELF is the standard format for Linux binaries
    > besides the a.out binary format, which is not used in practice anymore.

    BTW: a.out loader appears to be still full of integer overflow bugs.

    > 1) The Linux man pages state that a read(2) can return less than the
    > requested number of bytes, even zero. It is not clear how this can
    > happen while reading a disk file (in contrast to network sockets),
    > however here some thoughts:

    It can happen when the end of file is encountered. One might exploit this
    to create an "oracle" giving quizzical answers about unused kernel memory:
    You run your own malformed ELF binary that makes the kernel allocate N
    bytes, read M < N bytes, and interpret all N bytes including unintialized
    N-M bytes as ELF phdr entries. The fact the kernel ignores mmap() errors
    could make it interesting.

    On a NFS volume mounted with "intr" option, it can happen when the process
    receives a signal in the middle of read(). I don't dare to say whether it
    can happen in the middle of a page.

    > - - most of the standard setuid binaries on a 'normal' i386 Linux
    > installation have ELF headers stored below the 4096th byte, therefore
    > they are probably not exploitable on i386 architecture.

    I'd say that binaries with essential headers (phdr, interp) not fitting
    into the first page of the executable file are extremely rare on any
    platform. Afaik all standard tools put phdr right after ehdr, and interp
    right after phdr. Standard ehdr size is 52 bytes (64 for 64-bit arch), one
    standard phdr entry is 32 bytes (56? for 64-bit), and there is only a
    handful of entries (<=10) in an ordinary phdr. Interp is quite short,
    say <50 bytes. This makes <1000 bytes total.

    Have you find any "naturally occuring" binary with big headers?

    > 2) This bug can lead to a incorrectly mmaped binary image in the memory.
    > There are various reasons why a mmap() call can fail:
    [...]
    > Security implications in the case of a setuid binary are quite obvious:
    > we may end up with a binary without the .text or .bss section or with
    > those sections shifted (in the case they are not 'fixed' sections).

    ET_EXEC files (ordinary binaries) have fixed mapping. ET_DYN (ld.so or
    relocatable binaries; and dynamic libraries but they are irrelevant in
    this context) get MAP_FIXED after the first segment has been mapped
    successfully.

    But there's a catch: ld.so is loaded by load_elf_interp() that stop after
    the first mmap() failure. Its return value is wrong but the best thing we
    can get with ET_EXEC binaries (both with and without a dynamic linker) is
    an unmapped segment. A missing segment is likely to kill the program
    before it can do any harm.

    ET_DYN binaries may, on the other hand, be more exploitable if their
    memory layout is messed up the right way. (Isn't it ironic some people
    use ET_DYN binaries in order to be able to randomize process address
    space and make their systems more resistant?)

    > 3) This bug is similar to 2) however the code incorrectly returns the
    > kernel_read status to the calling function on mmap failure which will
    > assume that the program interpreter has been loaded. That means that the
    > kernel will start the execution of the binary file itself instead of
    > calling the program interpreter (linker) that have to finish the binary
    > loading from user space.

    As far as I can tell the kernel puts the result of kernel_read(), i.e. the
    interpreter's phdr size (<= page size), into elf_entry and initializes the
    process' instruction pointer to elf_entry. The inevitable consequence is
    that the process jumps into the large black hole at the begining of its
    address space (assuming standard Linux memory layout) and dies before it
    can do anything harmful. Do I miss anything?

    > 4) This bug leads to internal kernel file system functions beeing called
    > with an argument string exceeding the maximum path size in length
    > (PATH_MAX). It is not clear if this condition is exploitable.

    This is funny. There used to be
       elf_interpreter[elf_ppnt->p_filesz - 1] = 0;
    there but it was "optimized out" between 2.2 and 2.4.

    --Pavel Kankovsky aka Peak [ Boycott Microsoft--http://www.vcnet.com/bms ]
    "Resistance is futile. Open your source code and prepare for assimilation."


  • Next message: Noam Rathaus: "Contact in HP related to OpenView / Coda"

    Relevant Pages

    • [Full-Disclosure] Re: Linux ELF loader vulnerabilities
      ... You run your own malformed ELF binary that makes the kernel allocate N ... N-M bytes as ELF phdr entries. ... I'd say that binaries with essential headers ... Afaik all standard tools put phdr right after ehdr, ...
      (Full-Disclosure)
    • Re: Linux ELF loader vulnerabilities
      ... You run your own malformed ELF binary that makes the kernel allocate N ... N-M bytes as ELF phdr entries. ... I'd say that binaries with essential headers ... Afaik all standard tools put phdr right after ehdr, ...
      (Full-Disclosure)
    • Re: [RFC][PATCH 1/2] binfmt_elf: FatELF support in the binary loader.
      ... They employ a method similar to FatELF: ... offsets and sizes of self-contained Mach-O binaries within a container ... You can easily glue arbitrary ELF ... ELF binaries and a simple shell script that selects between them? ...
      (Linux-Kernel)
    • Re: Pedants
      ... However Jacob publishes only his binaries. ... Can we tell the quality ... a fairly strict published standard, ...
      (comp.lang.c)
    • Re: Bug report in the elf loader
      ... The elf loader does not always return the correct error code when ... The execution with 2 badly formed elf binaries leads to different error codes: ... Executing ./bb386nc ...
      (Linux-Kernel)