Bugtraq mailing list archives

Re: execve bug linux-2.2.12


From: security () XIRR COM (security () XIRR COM)
Date: Sat, 16 Oct 1999 22:13:19 -0000


Caveat: I am running linux-2.2.12ow6 which contains
many security fixes, yet I believe my comments are still
valid. Also I am not a kernel guru.

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. 

The kernel copies each argv[i] into a contiguous chunk
of the (soon to be) stack. Thus it must dereference each
argv[i]. Check out linux/fs/exec.c line 261 for an almost
explicit dereference of argv[i] (memcpy(str,argv+i) except
kernel to user space version).

This is confirmed by a small test program:

#include "nolibc.h"
main(int argc, char** argv,char **envp) {       
        int i;
        char buf[32];

        argv[1]=2;
        i=execve("/bin/sh",argv,envp);

        /* we should never reach this point, but print
                out errno in hexadecimal */
        i=htonl(i);
        i=itoh(&i,buf);
        buf[i]='\n';
        write(1,buf,i+1);
}

This program does not run /bin/sh but istead prints out the
message 0000000e representing errno=14, EFAULT.

This means the kernel got a segfault while copying the
argv[i]'s to the stack, and thus failed the syscall.

This program is linked with 
'gcc -O -fno-builtin -nostdlib test.c'

nolibc.h is ugly but available by request under GPL. It
defines ntohl,itoh,write,execve, and _start.

Note execve, htonl, itoh, and write are macros. Execve/write
are direct system calls. (itoh converts 4 bytes to 8byte
hex representation and returns 8, htonl byte swaps so
the bytes come out in the right order).

The thing that tipped me off to the problem was that a 
program that I exec'd was getting killed with SIGSEGV
in __libc_start_main before my
main function began running.

I'm not really sure if this is a widespread problem, but
ANYTIME libc gets hosed (malloc(-1) for example) gdb reports
the problem occuring in a function called from 
__libc_start_main and does not ever mention main.

I'll study this a wee bit more, since the references I'm
using for the startup state don't seem to jive with my 
experience. (Namely I never see an array of pointers
being setup in the docs, and my programs definately
do not do so, yet they function and dereference argv
as if it were an array of pointers).

Another remark: If I misunderstood the bug (like argv[1]=2
obviously is not valid, and is not what you meant) please 
let me know.


Current thread: