LD_PRELOAD affects new child even after unsetenv("LD_PRELOAD") LD_PRELOAD affects new child even after unsetenv("LD_PRELOAD") bash bash

LD_PRELOAD affects new child even after unsetenv("LD_PRELOAD")


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: 7f4c78fd5290unsetenv: 7f1127317290unsetenv: 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.


(The answer is a pure speculation, and may be is incorrect).

Perhaps, when you fork your process, the context of the loaded libraries persists. So, mylib.so was loaded when you invoked the main program via LD_PRELOAD. When you unset the variable and forked, it wasn't loaded again; however it already has been loaded by the parent process. Maybe, you should explicitly unload it after forking.

You may also try to "demote" symbols in mylib.so. To do this, reopen it via dlopen with flags that place it to the end of the symbol resolution queue:

dlopen("mylib.so", RTLD_NOLOAD | RTLD_LOCAL);


the answer from mvds is incorrect!

popen() will spawn child process which inherit the preloaded .so lied in parent process. this child process don't care LD_PRELOAD environment.