一个指定LD_PRELOAD的进程创建的子进程是否受LD_PRELOAD的影响?

1.

fork()后在子进程中执行函数。

main.c

#include <unistd.h>
#include <stdio.h>

extern char** environ;
void foo();
int main()
{
        for(char **current = environ; *current; current++) {
            puts(*current);
        }
        if(0 == fork()){
                foo();
        }else{
                sleep(1);
        }
        return 0;
}

foo.c

#include <stdio.h>
void foo()
{
        printf("real foo\n");
}

wfoo.c

#include <stdio.h>

void foo()
{
        printf("wrap foo\n");
}

将以上代码编译成执行文件和动态库

  • gcc -fPIC -shared foo.c -o libfoo.so
  • gcc -fPIC -shared wfoo.c -o libwfoo.so
  • gcc main.c -L./ -lfoo

执行LD_PRELOAD=./libwfoo.so ./a.out,其输出如下

[root@localhost ~]# LD_LIBRARY_PATH=./ LD_PRELOAD=./libwfoo.so ./a.out
LD_PRELOAD=./libwfoo.so
....
其他环境变量
...
wrap foo

也就是说fork()后的子进程其函数地址是和父进程一样的。

先执行了export LD_LIBRARY_PATH=./

仔细想了一想,fork()创建子进程,子进程仍使用父进程的代码段,这和LD_PRELOAD并没有关系。

2.

创建子进程后执行exec簇函数
exec.c

#include <unistd.h>

int main()
{
        if(0 == fork()){
                execl("./a.out", "./a.out", NULL);
        }
        return 0;
}

gcc exec.c -o exec

[root@localhost ~]# LD_PRELOAD=./libwfoo.so ./exec
LD_PRELOAD=./libwfoo.so
....
其他环境变量
...
wrap foo

如果将excel()替换为excele(),则情况发生变化

[root@localhost ~]# ./exec
./a.out: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory

这意味着LD_LIBRARY_PATH环境变量失效了。

仔细阅读man 3 exec后,恍然大悟。exec函数簇可分为两类,一类将当前进程的char** environ指向的环境变量传递给新程序镜像,如execl(),另一类则只使用函数参数指定的环境变量,如execle()

综上,当使用execle()这类函数时,如果没有手动将当前进程的环境变量通过参数传递下去,那么就会使得LD_PRELOAD失效,无法实现函数拦截的功能了。

3.

使用system()创建的子进程同样继承环境变量
exec.c

#include <unistd.h>

int main()
{
        if(0 == fork()){
                system("./a.out");
        }
        return 0;
}

gcc exec.c -o exec

[root@localhost ~]# LD_LIBRARY_PATH=./ LD_PRELOAD=./libwfoo.so ./exec
LD_PRELOAD=./libwfoo.so
....
其他环境变量
...
wrap foo

4.

结合以上情况,只有在特意指定子进程环境变量的情况(使用execle()等函数),原先指定的环境变量才会失效,否则环境变量都会传递到子进程。

最新文章

  1. 【前端性能】高性能滚动 scroll 及页面渲染优化
  2. (实用篇)php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
  3. mysql A表部分记录复制到B表
  4. 对WEB标准以及W3C的理解与认识
  5. json深度详解及org.json库
  6. Kruskal vs Borůvka
  7. DOM基础总结
  8. [Bootstrap] 1. container &amp; container-fluid
  9. 文件I/O之/dev/fd
  10. AFNetworking自带的解析图片的方法
  11. leetCode 48.Rotate Image (旋转图像) 解题思路和方法
  12. C#&nbsp;字符串加密解密函数
  13. html基础及心得
  14. Android学习笔记-TextView(文本框)(一)
  15. Spring之Enterprise JavaBeans (EJB) integration
  16. (七) UVC框架分析
  17. pycharm 中的 全局搜索(ctrl+shift+f) 功能无法使用的原因
  18. u-boot移植(十二)---代码修改---支持DM9000网卡
  19. nullpointerxception——处理思路
  20. luoguP4503 [CTSC2014]企鹅QQ hash

热门文章

  1. Linux命令及作用
  2. CFD-Post中截取任意面的数据
  3. Java-JUC(十二):有3个线程。线程A和线程B并行执行,线程C需要A和B执行完成后才能执行。可以怎么实现?
  4. winrunner 测试工具
  5. 【mybatis源码学习】mybatis的sql语句映射
  6. 源码包的三个参数make-configure-make install解释
  7. Spring cloud微服务安全实战-7-9自定义日志采集的格式和内容
  8. Qt开发经验小技巧11-20
  9. SVN限制普通用户删除文件及提交时必须填写log日志
  10. Centos7安装图形界面桌面