[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Strange stack & execve() behavior



Hello,

Something strange is going on when passing very long arguments to
execve() on Linux sparc. Instead of complaining because of a too long
argument list like on Linux i386, execve() successfully starts the new
program, but some arguments passed to the program are overwritten, and
some environment variables are lost, but without any notification.

The following program, foo, calls a second program, bar, via execve(),
and together they demonstrate the problem:

/tmp% cat foo.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main( int argc, char * argv[] )
{
    unsigned long ul = strtoul( argv[1], NULL, 0 );
    char foobar[ ul + 1 ];
    char * execve_argv[] = { "/tmp/bar", foobar, NULL };
    char * execve_envp[] = { "FOO=BAR", NULL };

    memset( foobar, 0x42, ul );
    foobar[ ul ] = 0;

    printf( "strlen(execve_argv[1]) = %i;\n", strlen(execve_argv[1]) );
    printf( "%s;\n", execve_envp[0] );

    execve( execve_argv[0], execve_argv, execve_envp );

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

/tmp% cat bar.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main( int argc, char * argv[] )
{
    printf( "strlen(argv[1]) = %i;\n", strlen(argv[1]) );
    printf( "FOO=%s;\n", getenv("FOO") );
    return( 0 );
}

First, when passing a not too long argument to /tmp/bar:

% uname -sm
Linux i686

% /tmp/foo 4242
strlen(execve_argv[1]) = 4242;
FOO=BAR;
strlen(argv[1]) = 4242;
FOO=BAR;

% uname -sm
Linux sparc64

% /tmp/foo 4242
strlen(execve_argv[1]) = 4242;
FOO=BAR;
strlen(argv[1]) = 4242;
FOO=BAR;

On both architectures everything works well. Now, when passing a long
argument to /tmp/bar:

% uname -sm
Linux i686

% /tmp/foo 424242
strlen(execve_argv[1]) = 424242;
FOO=BAR;
strerror(errno) = Argument list too long;

% uname -sm
Linux sparc64

% /tmp/foo 424242
strlen(execve_argv[1]) = 424242;
FOO=BAR;
strlen(argv[1]) = 32775;
FOO=(null);

Here, on Linux sparc, the argument passed to /tmp/bar was truncated and
the FOO environment variable disappeared, although execve() started
without any error. The last argument length working is 32767 (how
strange :-):

% uname -sm
Linux sparc64

% /tmp/foo 32767
strlen(execve_argv[1]) = 32767;
FOO=BAR;
strlen(argv[1]) = 32767;
FOO=BAR;

% /tmp/foo 32768
strlen(execve_argv[1]) = 32768;
FOO=BAR;
strlen(argv[1]) = 32775;
FOO=(null);

Is it a known bug, is it a libc bug, a kernel bug? I do not have enough
time to work on the problem, and I am clearly not the best qualified
person... Any ideas, comments? Please do not forget to CC me your
answers, as I am not subscribed to the debian-sparc mailing list. Thank
you very much, and best regards,

-- 
MaXX



Reply to: