标题: 动态链接器符号链接被破坏后的灾难恢复
创建: 2018-09-19 12:02 更新: 2018-09-19 14:11 链接: https://scz.617.cn/unix/201809191202.txt
干了一件蠢事,本意是
$ ln -sf /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3
但我把src、dst写反了,灾难大片上演。在/sbin、/usr/sbin下疯狂找静态链接的可 用工具,没有。幸亏此时还有一个WinSCP挂在线上。事后吐槽,为啥不把ln这种命令 弄成静态链接的?
Debian有个sln(8)的man手册,这是静态版本的ln,不知道sln属于哪个包,没找着。
参看:
16.24 ld.so(8) 16.27 ldconfig(8) 16.28 在Debian上手工升级GLIBC
多年以前手工在线热升级GLIBC时,仔细研究过本质上同一类型的灾难恢复,事隔多 年再次相遇时,居然没能想起从前的文档,真心有点慌了。
很多人碰上过这个问题,今天回顾一下,看有什么可能的应急方案。
$ file -b which ls
ELF 32-bit LSB pie executable ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=a225fea0f89c5d18c8f0f9c03d7979175f54b7db, stripped
$ ldd which ls
$ LD_TRACE_LOADED_OBJECTS=1 which ls
$ /lib/ld-linux-armhf.so.3 --list which ls
linux-vdso.so.1 (0xb6ffd000)
libselinux.so.1 => /lib/arm-linux-gnueabihf/libselinux.so.1 (0xb6f79000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6e81000)
/lib/ld-linux-armhf.so.3 (0xb6fd6000)
libpcre.so.3 => /lib/arm-linux-gnueabihf/libpcre.so.3 (0xb6e22000)
libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb6e0f000)
libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6dea000)
这三个方案不等价,第二种更普适。
$ ls -l /lib/ld-linux-armhf.so.3 /lib/arm-linux-gnueabihf/ld-2.27.so -rwxr-xr-x 1 root root 105832 Mar 30 03:47 /lib/arm-linux-gnueabihf/ld-2.27.so lrwxrwxrwx 1 root root 35 Sep 18 16:38 /lib/ld-linux-armhf.so.3 -> /lib/arm-linux-gnueabihf/ld-2.27.so
这是正常状态。有个在x86上交叉编译得来的ARM版binary用了/lib/ld-linux.so.3, 当前系统中没有/lib/ld-linux.so.3,我想创建同名符号链接,使之指向 /lib/ld-linux-armhf.so.3,但我写错了ln命令:
$ ln -sf /lib/ld-linux.so.3 /lib/ld-linux-armhf.so.3
此时ln的src、dst写反了,理解src、dst顺序的最好办法是将ln想像成cp命令。如果 上述命令没有指定-f,情况就会得到控制:
$ ln -s /lib/ld-linux.so.3 /lib/ld-linux-armhf.so.3 ln: failed to create symbolic link '/lib/ld-linux-armhf.so.3': File exists
但我不知从什么年代开始养成的坏习惯,习惯性地"ln -sf",这种盲目而过度的自信 属于找抽。现在假设"ln -sf"已经完成,灾难大片上演:
$ ls -la /lib -bash: /bin/ls: No such file or directory $ which ls -bash: /usr/bin/which: /bin/sh: bad interpreter: No such file or directory
那些动态链接的binary全歇菜。
如果此时有一个静态链接版busybox在场,可以看到:
$ /sbin/busybox-armv8l ls -l /lib/ld-linux-armhf.so.3 lrwxrwxrwx 1 root root 18 Sep 19 11:05 ld-linux-armhf.so.3 -> /lib/ld-linux.so.3
此处不考虑静态链接版busybox在场,不考虑WinSCP在线,不考虑关机离线修复,看 看如何在线热修复。
来,看哥的奇技淫巧:
$ LD_LIBRARY_PATH=/lib/arm-linux-gnueabihf LD_HWCAP_MASK=0 /lib/arm-linux-gnueabihf/ld-2.27.so /bin/ls -l /lib/ld-linux-armhf.so.3 lrwxrwxrwx 1 root root 18 Sep 19 11:05 /lib/ld-linux-armhf.so.3 -> /lib/ld-linux.so.3
$ LD_LIBRARY_PATH=/lib/arm-linux-gnueabihf LD_HWCAP_MASK=0 /lib/arm-linux-gnueabihf/ld-2.27.so /bin/ln -sf /lib/arm-linux-gnueabihf/ld-2.27.so /lib/ld-linux-armhf.so.3
$ ls -l /lib/ld-linux-armhf.so.3 lrwxrwxrwx 1 root root 35 Sep 19 11:28 /lib/ld-linux-armhf.so.3 -> /lib/arm-linux-gnueabihf/ld-2.27.so*
很多时候不需要这么复杂的组合,这里只是给了一个较完备的示例。
$ LD_LIBRARY_PATH=/
就动态链接器定位异常而言,一般情况下直接指定一个可用动态链接器即可:
$ /lib/arm-linux-gnueabihf/ld-2.27.so /bin/ln -sf /lib/arm-linux-gnueabihf/ld-2.27.so /lib/ld-linux-armhf.so.3
如果只是libc定位异常,除了LD_LIBRARY_PATH,还可以试LD_PRELOAD。
或许下面这个命令也能恢复动态链接器符号链接:
$ /sbin/ldconfig -n /lib
$ file -b /sbin/ldconfig ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=7e0b38911f6023db649b971470f6f382caa8f8f3, stripped
ldconfig是静态链接的。但我觉得这个办法用于此处过于重型,未实测。不过我测了 下面这种办法,没戏:
$ /sbin/ldconfig -l /lib/arm-linux-gnueabihf/ld-2.27.so
话说回来,还是在系统中放一个全功能静态链接版busybox靠谱,比如不是符号链接 出幺蛾子,而是动态链接器的实体文件被删,此时可以用busybox的nc传文件进去。