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.