COMMAND

    execve

SYSTEMS AFFECTED

    linux-2.2.12

PROBLEM

    'ben' found following.  He  discovered a really nasty stack  smash
    bug  in  linux-2.2.12.   Previous  versions  of  kernel  were  not
    checked.  The implications of this bug could be very dire.  It may
    be possible  to easily  obtain root  privilege on  any box running
    this kernel.

    Basically the problem is that  the execve system call checks  that
    argv is  a valid  pointer but  it doesn't  check that  all of  the
    pointers  in  argv  array  are  valid  pointers.   If you pass bad
    pointers into the execve system call you can corrupt the processes
    stack before it returns to user space. Then when the kernel  hands
    off the process to the elf  loader code and which begins to  setup
    the processes  it can  be made  to execute  some malicious code in
    place of the program's main function.

    This is particularly scary because  all of this occurs BEFORE  the
    program begins executing its  main function and AFTER  the program
    returns to  user space  with privilege.   Therefore no  matter how
    well  audited  the  program  may  be  it  can  be  used as to gain
    privilege.

    Alan Cox does not  share same opinion as  Ben.  However, Ben  sent
    additional info.   Here is  one ltrace  fragment where  my program
    only corrupts one of the parameters:

        [pid 578] execv("/bin/grep", 0x7ffffcdc <unfinished ...>
        [pid 578] __libc_start_main(0x0804a4e0, 200, 0x7fffb3a4, 0x08048bf4, 0x080516dc <unfinished ...>
        [pid 578] --- SIGSEGV (Segmentation fault) ---
        [pid 578] +++ killed by SIGSEGV +++
        --- SIGCHLD (Child exited) ---

    Here is some information from gdb:

        (gdb) core-file /tmp/core
        Core was generated by `=>> -#/g_v6Ej18HRtU	{d:7&a:ɳ^Qt:XA:W'.
        Program terminated with signal 11, Segmentation fault.
        Reading symbols from /lib/libc.so.6...done.
        Reading symbols from /lib/ld-linux.so.2...done.
        #0  0x2aae60f6 in getenv (name=0x2aba8562 "LLOC_TRIM_THRESHOLD_")
            at ../sysdeps/generic/getenv.c:88
        ../sysdeps/generic/getenv.c:88: No such file or directory.
        (gdb) bt
        #0  0x2aae60f6 in getenv (name=0x2aba8562 "LLOC_TRIM_THRESHOLD_")
            at ../sysdeps/generic/getenv.c:88
        #1  0x2aae689b in __secure_getenv (name=0x2aba8560 "MALLOC_TRIM_THRESHOLD_")
            at secure-getenv.c:29
        #2  0x2ab1e2e0 in ptmalloc_init () at malloc.c:1689
        #3  0x2aade211 in __libc_preinit (argc=200, argv=0x7fffb3a4, envp=0x7fffb6c8)
            at set-init.c:26
        #4  0x2aade030 in __libc_start_main (main=0x804a4e0 <strcpy+5500>, argc=200,
            argv=0x7fffb3a4, init=0x8048bf4, fini=0x80516dc <strcpy+34680>,
            rtld_fini=0x2aab5ad4 <_dl_fini>, stack_end=0x7fffb39c)
            at ../sysdeps/generic/libc-start.c:68
        (gdb)

    This  was  just  one  run.   There  were  other  runs  where  more
    interesting things happened.   There was one  in particular  where
    the pointer  to init  was corrupted.   Ben putted  the source code
    for the program I was debugging at the time when he stumbled  into
    this at:

        ftp://ftp.bastille-linux.org/bastille/broken-fuzz.c.gz

    Note:  this  is not a  working program!!!   Do not take  this as a
    release. Its its current form  its only purpose is to  demonstrate
    the problem.  To trigger  the problem simply run the  program with
    the -ba  option and  the name  of your  favorite exectuable.  e.g.
    "./fuzz -ba grep"

    Matt Chapman sent a demo program.  This program (on his system  at
    least 5 bad arguments  are needed) reproducibly dies  with SIGSEGV
    on  2.2.12.   A  similarly  configured  system  with kernel 2.0.36
    correctly reports EFAULT.  This  would not normally be a  problem,
    however... the below  program will not  dump core for  an ordinary
    user, only  root, which  makes us  believe that  the fault  occurs
    after the process has  gained the root euid  from /bin/su.  A  gdb
    trace suggests the usual heap corruption in glibc, which does  not
    seem to be related to the  arguments passed to execve (as long  as
    they are bad), so there's doubt if it is exploitable.  However  it
    is most likely a bug somewhere.

    #include <unistd.h>
    #include <errno.h>

    #define BADPTR (char *)0x10   /* for example */

    int main(int argc, char **argv, char **envp)
    {
            char *args[7];
            int i;

            args[0] = "su";
            for (i = 1; i < 6; i++) {
                    args[i] = BADPTR;
            }
            args[6] = NULL;

            execve("/bin/su", args, envp);

            printf("%s\n", strerror(errno));
	    return 1;
    }

    Apparently the  Linux execve(  ) bug  is caused  by the failure of
    copy_strings( )  in /usr/src/linux/fs/exec.c  to check  the return
    value of strlen_user( ).   On error, strlen_user( ) returns  zero,
    and copy_strings(  ) blithely  copies zero  bytes to  the argument
    table  of  the  programme  to  be  execve(  )'d,  thus effectively
    removing any bad pointers from argv.  The problem is that argc  is
    not  updated,  so  the  missing  arguments  are  taken  from   the
    environment  string  table,  and  the  missing environment strings
    from whatever happens to be at the top of memory after the  string
    table.   When  that  is  exhausted,  the  rest  of the environment
    pointers  point  to  the  end  of  memory, which causes the SEGV's
    people have  been observing.   There's no  possible way  this  bug
    could affect security, however.

SOLUTION

    2.2.13 is however  now out officially  and including the  fix.  It
    fixes several security holes.