my code is as follows: preload.c, with the following content:
#include
#include
int __attribute__((constructor)) main_ini
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.