即使在unsetenv("LD_PRELOAD")之后,LD_PRELOAD也会影响新的孩子

avn*_*ner 7 c linux bash shared-libraries popen

我的代码如下:preload.c,具有以下内容:

#include <stdio.h>
#include <stdlib.h>

int  __attribute__((constructor))  main_init(void)
{
    printf("Unsetting LD_PRELOAD: %x\n",unsetenv("LD_PRELOAD"));
    FILE *fp = popen("ls", "r");
    pclose(fp);
}
Run Code Online (Sandbox Code Playgroud)

然后在shell中(小心做第二个命令!!):

    gcc preload.c -shared -Wl,-soname,mylib -o mylib.so -fPIC
    LD_PRELOAD=./mylib.so bash
Run Code Online (Sandbox Code Playgroud)

!小心最后一个命令,它将导致无限循环的分叉"sh -c ls".用^ C后2秒钟停止它(或者更好^ Z然后看ps).

更多信息

  1. 这个问题在某种程度上与bash有关; 或者作为用户运行的命令,或者作为popen执行的bash.
  2. 其他关键因素:1)从预加载的库中执行popen,2)可能需要在库的初始化部分中执行popen.
  3. 如果您使用:

    LD_DEBUG=all LD_DEBUG_OUTPUT=/tmp/ld-debug LD_PRELOAD=./mylib.so bash
    
    Run Code Online (Sandbox Code Playgroud)

    而不是最后一个命令,您将获得许多ld-debug文件,名为/tmp/ld-debug.*.每个分叉过程一个.在所有这些文件中,您将看到首先在mylib中搜索符号.即使LD_PRELOAD已从环境中删除.

mvd*_*vds 8

编辑:所以问题/问题实际上是:如果LD_PRELOAD使用main_init()从内部预加载的话,你不能可靠地解决问题bash.

原因是,execve在您之后调用popen,从(可能)获取环境

extern char **environ;
Run Code Online (Sandbox Code Playgroud)

这是一个指向您的环境的全局状态变量.unsetenv()通常会修改您的环境,因此会影响您的内容**environ.

如果bash尝试对环境做一些特别的事情(好吧......它会成为一个shell吗?)那么你可能会遇到麻烦.

出乎意料的是,甚至在此之前bash过载.将示例代码更改为:unsetenv()main_init()

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);
}
Run Code Online (Sandbox Code Playgroud)

显示问题.在正常运行(运行cat,ls等等),我得到这个版本的unsetenv:

unsetenv: 7f4c78fd5290
unsetenv: 7f1127317290
unsetenv: 7f1ab63a2290
Run Code Online (Sandbox Code Playgroud)

但是,跑步bashsh:

unsetenv: 46d170
Run Code Online (Sandbox Code Playgroud)

所以你有它.bash让你上当了;-)

因此,只要使用自己修改环境到位unsetenv,作用于**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';
    }
}
Run Code Online (Sandbox Code Playgroud)

可以看出工作在strace:

execve("/bin/sh", ["sh", "-c", "ls"], [... "DD_PRELOAD=mylib.so" ...]) = 0
Run Code Online (Sandbox Code Playgroud)

QED