Search code examples
linuxptraceld-preload

How to set the LD_PRELOAD environment variable for a ptrace child


I'm trying to load a pre-load library to the ptrace child process using environment variables. But somehow I got an error when creating the child process:

int main(int argc, char **argv)
{
    char *env[] = {"LD_PRELOAD=/<path-to-the-preload-library>/preload.so"};
    pid_t pid = fork();
    switch (pid) {
        case -1: /* error */
            log_fatal("%s. pid -1", strerror(errno));
            break;
        case 0:  /* child, executing the tracee */
            ptrace(PTRACE_TRACEME, 0, 0, 0);
            execve(argv[1], argv + 1, env); // Fail to launch ptrace child!
            //execvp(argv[1], argv + 1);    // It works fine!
            log_fatal("%s. child", strerror(errno));
    }

    waitpid(pid, 0, 0); // sync with PTRACE_TRACEME
    ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL);

The simple preloaded library code:

$ cat preload.c
#include <stdio.h>

static void _init() __attribute__((constructor));
void _init() {
    printf("I'm a constructor\n");
}

Any idea why it fails?


Solution

  • It'd be nice if you told us what the error message was, but I think I can guess: "Bad address"?

    The env vector passed to execve needs to be terminated with a NULL pointer, just like the argv vector. So you want

    char *env[] = {"LD_PRELOAD=/<path-to-the-preload-library>/preload.so", NULL};