LD_ preLOAD即使影响新的子unsetenv(QUOT; LD_ preLOAD") [英] LD_PRELOAD affects new child even after unsetenv("LD_PRELOAD")

查看:382
本文介绍了LD_ preLOAD即使影响新的子unsetenv(QUOT; LD_ preLOAD")的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;INT __attribute __((构造函数))main_init(无效)
{
    的printf(注销LD_ preLOAD:%X \\ n,unsetenv(LD_ preLOAD));
    FILE *计划生育=的popen(LS,R);
    pclose函数(FP);
}

然后在外壳(做小心!第二个命令):

  GCC preload.c -shared -Wl,-soname,MYLIB -o mylib.so -fPIC
    LD_ preLOAD = / bash的mylib.so

!要小心用最后的命令,它会导致与派生嘘-c LS的死循环。 2秒后停止^ C(或更好^ Z再看看PS)。

更多信息


  1. 此问题涉及在某种程度上打坏;无论是作为命令,将用户运行,或在bash器一起执行。

  2. 额外的主要因素:1)执行从pre装库器一起,2)可能需要做的popen库的初始化部分

  3. 如果您使用的:

      LD_DEBUG =所有LD_DEBUG_OUTPUT =的/ tmp / LD-调试LD_ preLOAD = / bash的mylib.so

    而不是最后一个命令,你会得到很多LD-调试文件,命名为/tmp/ld-debug.*。一个用于每个分叉处理。在所有这些文件,你会看到符号首先在mylib.so搜查即使LD_ preLOAD从环境中移除。



解决方案

编辑:,所以这个问题/问题实际上是:howcome不了你没有设置 LD_ preLOAD 可靠地使用preloaded main_init()从内部庆典

原因是,的execve ,这是后您的popen 调用,从(可能)主罚环境

 的extern字符** ENVIRON;

这是一些全局状态变量指向您的环境。 unsetenv()通常会修改你的环境,因此对内容的影响 ** ENVIRON

如果庆典试图做一些特殊的环境(嗯......不是吗?作为一个壳呢?),那么你可能会遇到麻烦。

Appearantly,庆典重载 unsetenv()甚至在 main_init()。更改例如code为:

 的extern字符** ENVIRON;INT __attribute __((构造函数))main_init(无效)
{
INT I;
的printf(注销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);
对于(i = 0; ENVIRON [I];我++)的printf(ENV:%S \\ n,ENVIRON [I]);
fflush(标准输出);
FILE *计划生育=的popen(LS,R);
pclose函数(FP);
}

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

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

但是,运行庆典 SH

  unsetenv:46d170

所以,你有它。 庆典已经得到了你上当; - )

所以只用修改环境代替你自己的 unsetenv ,作用于 ** ENVIRON

 为(i = 0; ENVIRON [I];我++)
{
    如果(的strstr(ENVIRON [I]中,LD_ preLOAD =))
    {
         的printf(黑客从出LD_ ENVIRON preLOAD [%D]。\\ n,I);
         ENVIRON [I] [0] ='D';
    }
}

这可以看出,在上班 strace的

 的execve(/ bin / sh的,[嘘,-c,LS],[......DD_ preLOAD = mylib.so ...])= 0

Q.E.D。

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

#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);
}

then in the shell (do the 2nd command with care!!):

    gcc preload.c -shared -Wl,-soname,mylib -o mylib.so -fPIC
    LD_PRELOAD=./mylib.so bash

!!! be carefull with the last command it will result with endless loop of forking "sh -c ls". Stop it after 2 seconds with ^C, (or better ^Z and then see ps).

More info

  1. This problem relate to bash in some way; either as the command that the user run, or as the bash the popen execute.
  2. additional Key factors: 1) perform the popen from the pre-loaded library, 2) probably need to do the popen in the initialization section of the library.
  3. if you use:

    LD_DEBUG=all LD_DEBUG_OUTPUT=/tmp/ld-debug LD_PRELOAD=./mylib.so bash
    

    instead of the last command, you will get many ld-debug files, named /tmp/ld-debug.*. One for each forked process. IN ALL THESE FILES you'll see that symbols are first searched in mylib.so even though LD_PRELOAD was removed from the environment.

解决方案

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.

这篇关于LD_ preLOAD即使影响新的子unsetenv(QUOT; LD_ preLOAD&QUOT;)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆