LD_ preLOAD即使影响新的子unsetenv(QUOT; LD_ preLOAD") [英] LD_PRELOAD affects new child even after unsetenv("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)。
更多信息
- 此问题涉及在某种程度上打坏;无论是作为命令,将用户运行,或在bash器一起执行。
- 额外的主要因素:1)执行从pre装库器一起,2)可能需要做的popen库的初始化部分 。
-
如果您使用的:
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
- This problem relate to bash in some way; either as the command that the user run, or as the bash the popen execute.
- 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.
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屋!