views:

172

answers:

3

Why it doesn't work :( I want to simply invoke a shell in C program by execve:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

main()
{
        char* path = "/bin/sh";
        int err = execve(path, &path, NULL);
        printf("%d\n", err);
        printf("%s\n", strerror(errno));
        printf("%x, %x\n", path, &path);
}

However the output is:

-1
Bad address
80485c0, bf816f4c

Please help!

+4  A: 

Because you aren't sending a NULL terminated list of arguments. You need:

char* path[2];
path[0] = "/bin/sh";
path[1] = NULL;
int err = execve(path[0], path, NULL);
Richard Pennington
Thanks a lot :)
l245c4l
+1  A: 

Try this instead:

execl(path, path, NULL)

The exec family of functions will automatically execute a shell if the program is a script rather than a process image file. So you might be able to replace "path" with the pathname of the script.

Steve Emmerson
+3  A: 

The second argument to execve is defined as being a NULL-terminated list of strings, so you can't simply pass the address of path. It expects an array like this, with the final entry being NULL:

arg[0] = "/bin/ls"
arg[1] = "-l"
arg[2] = "/usr/include/std*"
arg[3] = NULL

The reason it was failing with a bad pointer is that execve would have been looking at each word following path to find the arguments, and treating each word as a pointer until it got to the first 0 word. Since path was alone on the stack, it would have been trying to interpret whatever garbage happened to be in memory after the stack beyond path as a string pointer.

The solution is simple: you need to construct an array of parameters and add a NULL terminator (since it is of variable length). The fixed example is below (with a few warnings taken care of):

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

int main()
{
    char* path[] = { "/bin/sh", NULL };

    int err = execve(path[0], path, NULL);

    printf("%d\n", err);
    printf("%s\n", strerror(errno));
    printf("%p, %p\n", path, &path);

    return 0;
}
gavinb