卸载自身的 Linux 共享库

Linux shared library that unloads itself

本文关键字:共享 Linux 卸载      更新时间:2023-10-16

我的目标是将几个glibc函数挂接到位于特定路径的一组进程中。有多种方法可以做到这一点(gdb,strace等)。但我需要在最早的舞台上自动可靠地制作它,这样我就不会错过任何一个电话。所以我决定采用LD_PRELOAD方法。而且我需要在没有任何用户干预的情况下自动完成它,因此将LD_PRELOAD注入环境有点脆弱,可能会被用户覆盖。所以我决定在/etc/ld.so.preload中指定我的库 - 这很好用。

在我的库 ctor 代码中,我检查我所在的进程是否是我需要的进程并执行必要的钩子,否则它是无操作的,库只是一个自重。

__attribute__((constructor)) void my_lib_ctor()
{
if (is_relevant_process())
{
do_the_wiring();
}
}

该库不导出任何符号,并且默认情况下隐藏了其中的所有内容(-fvisibility=hidden编译器标志),因此任何进程都对我的库没有任何真正的依赖关系。因此,在注入不相关的过程中,可以安全地卸载。

更新过程需要卸载 - 如果要更新库,则不应将其加载到长时间运行的进程中 - 否则它们将在库替换时崩溃(这是预期的)。感兴趣的流程是短暂的,并且由用户启动,因此对它们的影响可以忽略不计。

问题是 - 我不知道如何安全地卸载它。我在考虑dlclose,但是从库本身调用它将导致它从回调返回已经卸载的库代码。

如果还有其他方法可以在早期阶段(应用程序main()执行之前)自动可靠地挂钩 glibc 调用,而无需接触感兴趣的应用程序本身,如果您让我知道它们,我会很高兴(操作系统配置的轻微修改,例如预加载,是可以的)。谢谢!

我想你有一些误解,你所要求的只是没有意义:

在我的库 ctor 代码中,我检查我所在的进程是否是我需要的进程并执行必要的钩子,否则它是无操作的,库只是一个自重。

卸载它的工作,而不是让它无所事事,它重。

更新过程需要卸载 - 如果要更新库,则不应将其加载到长时间运行的进程中 - 否则它们将在库替换时崩溃(这是预期的)。

仅当您错误地覆盖库文件而不是替换文件时,才会发生这种情况。后者可以通过将临时文件安装到同一目录并以旧文件为目标执行rename功能(等效于mv命令)来执行。

如果还有其他方法可以在早期阶段自动可靠地钩住 glibc 调用

您对"可靠"的关注听起来可疑地接近于想要使用此机制以潜在恶意应用程序无法绕过的方式实施策略/访问控制。这在库级别基本上是不可能的。您需要在某种真正的沙箱中运行它们才能实现这一点(例如,通过将文件替换为在适当的沙箱中调用它们的包装脚本)。