[置顶] 泰晓 RISC-V 实验箱,配套 30+ 讲嵌入式 Linux 系统开发公开课
[置顶] Linux Lab v1.4 升级部分内核到 v6.10,新增泰晓 RISC-V 实验箱支持,新增最小化内核配置支持大幅提升内核编译速度,在单终端内新增多窗口调试功能等Linux Lab 发布 v1.4 正式版,升级部分内核到 v6.10,新增泰晓实验箱支持
[置顶] 泰晓社区近日发布了一款儿童益智版 Linux 系统盘,集成了数十个教育类与益智游戏类开源软件国内首个儿童 Linux 系统来了,既可打字编程学习数理化,还能下棋研究数独提升智力
一起看看那些经典的 LD_PRELOAD 用法
By Falcon of TinyLab.org Jun 14, 2019
简介
一次偶然的机会,刚编译完 buildroot,里头用到 fakeroot ,又看到自己早期写的 segment fault,里头有个 catchsegv,两者都有共性,那就是都用到了 LD_PRELOAD
。
从 fakeroot 和 catchsegv,都看到了 ‘LD_PRELOAD’ 的强大功能:
fakeroot
run a command in an environment faking root privileges for file manipulation
catchsegv
Catch segmentation faults in programs
fakeroot 允许执行 mknod 这样需要 root 权限的程序而不会失败(虽然没有真正创建设备文件),所以被 buildroot 用于文件系统构建。而 catchsegv 能够捕捉断错误,并打印出 backtrace 从而方便辅助定位软件问题。
fakeroot 通过 libfakeroot-0.so
篡改了 getuid
相关的函数,而 catchsegv 通过 libSegFault.so
捕获 SIGSEGV 信号来获得 backtrace。
它们本质上都是“篡改”了系统共享库文件中的函数。
$ man ld.so
LD_PRELOAD
A list of additional, user-specified, ELF shared objects to be loaded before all others.
This can be used to selectively override functions in other shared objects.
LD_PRELOAD 经典应用
除了 fakeroot 和 catchsegv,还有大量工具利用了 LD_PRELOAD
特性。这篇讨论 就列举了数十种用法。比较经典的有:
- stderred: red the output to stderr
- Electric Fence: detect boundaries overruns and uses after free of malloced space
- InstallWatch: keep track of created and modified files during the installation of a new program
- libfiu: Fault injection in userspace
- libfaketime: libfaketime modifies the system time for a single application
- openonload: a high performance network stack from Solarflare that dramatically reduces latency and cpu utilisation, and increases message rate and bandwidth
- libshape: limiting the download rate of programs
- libeatmydata: disables all forms of writing data safely to disk. fsync() becomes a NO-OP, O_SYNC is removed etc.
- fakechroot: runs a command in an environment were is additional possibility to use chroot(8) command without root privileges.
- libtmperamental: intercepts filesystem writes, and causes loud failures when writes are attempted on
/tmp/*
- libsafe: protect systems against some of the more common buffer overflow attacks
LD_PRELOAD 实例
下面来一个实实在在的例子,那就是强制 ls
输出到文件的结果也带颜色信息。默认情况下,ls
输出到控制台才带颜色信息,输出到文件则不带。
先来看看 ls
输出到控制台和输出到文件的差异:
$ ltrace -o ltrace-ls-stdout.log ls
$ ltrace -o ltrace-ls-file.log ls > file.tmp
$ vimdiff ltrace-ls-stdout.log ltrace-ls-file.log
可以观察到 isatty
的区别:
$ grep isatty -ur ltrace*.log
ltrace-file.log:isatty(1) = 0
ltrace-stdout.log:isatty(1) = 1
$ man isatty
isatty - test whether a file descriptor refers to a terminal
int isatty(int fd);
根据上述结果来看,isatty 在控制台下返回了 1,在输出到文件时则返回了 0。如果强制构造一个一直返回 1 的 isatty()
就可以确保输出到文件也显示颜色了吗?
下面试试看,先创建一个共享库,然后用 LD_PRELOAD
指定,从而可以 override glibc 中的 isatty()
实现:
$ echo 'int isatty(int fd) { return 1; }' | gcc -x c -o libisatty.so -shared -
$ LD_PRELOAD=./libisatty.so ls > file.tmp
$ cat file.tmp
LD_PRELOAD 探索
LD_PRELOAD
这种特性有点像是 live patching,也就是说不用修改源代码不用重新编译应用程序,就可以在运行时调整某部分功能。
上面列举的几个经典应用已经充分利用了这种特性,它们有用来做问题诊断、错误注入测试、数据监控、日志加亮、性能优化以及异常检测等,网络上甚至还有人用来做 Android antt-RE。
或许还可以:
- 用作大型系统应用的在线更新方案,把核心功能用共享库的方式实现,升级时可以发布新的小型库通过
LD_PRELOAD
覆盖老版本中对应的功能即可。 - 也可以用于循序渐进地学习某个软件功能,一部分一部分的重写,用
LD_PRELOAD
替换,从而逐步完整实现某个软件库。可参考 overriding malloc。 - 还可以用于紧急修复某个软件漏洞,比如说,某个软件库有 Bug,等到官方发布新版本会有个漫长的周期,修改源代码重新编译也很费时,或许可以考虑做个临时的库,通过
LD_PRELOAD
即时更新覆盖掉有 Bug 的函数。
当然,还有很多值得探索的空间,欢迎到文末加作者微信进一步交流探讨。
猜你喜欢:
- 我要投稿:发表原创技术文章,收获福利、挚友与行业影响力
- 知识星球:独家 Linux 实战经验与技巧,订阅「Linux知识星球」
- 视频频道:泰晓学院,B 站,发布各类 Linux 视频课
- 开源小店:欢迎光临泰晓科技自营店,购物支持泰晓原创
- 技术交流:Linux 用户技术交流微信群,联系微信号:tinylab
支付宝打赏 ¥9.68元 | 微信打赏 ¥9.68元 | |
请作者喝杯咖啡吧 |
Read Related:
Read Latest:
- LD_PRELOAD 1
- live patching 1
- fakeroot 1
- fakechroot 2
- catchsegv 1
- stderred 1
- Electric Fence 1
- InstallWatch 1
- libfiu 1
- libfaketime 1
- openonload 1
- libshape 1
- libeatmydata 1
- fakechroot 2
- libtmperamental 1
- libsafe 1