LD_PRELOAD affects new child even after unsetenv(“LD_PRELOAD”)

前端 未结 3 849
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-05 00:39

my code is as follows: preload.c, with the following content:

#include 
#include 

int  __attribute__((constructor))  main_ini         


        
3条回答
  •  野趣味
    野趣味 (楼主)
    2021-01-05 01:19

    edit: so the problem/question actually was: howcome can't you unset LD_PRELOAD reliably using a preloaded main_init() from within bash.

    The reason is that execve, which is called after you popen, takes the environment from (probably)

    extern char **environ;
    

    which is some global state variable that points to your environment. unsetenv() normally modifies your environment and will therefore have an effect on the contents of **environ.

    If bash tries to do something special with the environment (well... would it? being a shell?) then you may be in trouble.

    Appearantly, bash overloads unsetenv() even before main_init(). Changing the example code to:

    extern char**environ;
    
    int  __attribute__((constructor))  main_init(void)
    {
    int i;
    printf("Unsetting LD_PRELOAD: %x\n",unsetenv("LD_PRELOAD"));
    printf("LD_PRELOAD: \"%s\"\n",getenv("LD_PRELOAD"));
    printf("Environ: %lx\n",environ);
    printf("unsetenv: %lx\n",unsetenv);
    for (i=0;environ[i];i++ ) printf("env: %s\n",environ[i]);
    fflush(stdout);
    FILE *fp = popen("ls", "r");
    pclose(fp);
    }
    

    shows the problem. In normal runs (running cat, ls, etc) I get this version of unsetenv:

    unsetenv: 7f4c78fd5290
    unsetenv: 7f1127317290
    unsetenv: 7f1ab63a2290
    

    however, running bash or sh:

    unsetenv: 46d170
    

    So, there you have it. bash has got you fooled ;-)

    So just modify the environment in place using your own unsetenv, acting on **environ:

    for (i=0;environ[i];i++ )
    {
        if ( strstr(environ[i],"LD_PRELOAD=") )
        {
             printf("hacking out LD_PRELOAD from environ[%d]\n",i);
             environ[i][0] = 'D';
        }
    }
    

    which can be seen to work in the strace:

    execve("/bin/sh", ["sh", "-c", "ls"], [... "DD_PRELOAD=mylib.so" ...]) = 0
    

    Q.E.D.

提交回复
热议问题