2011-10-08 68 views
4

我想拦截在dlopen()中发生的所有文件系统访问。起初,这看起来就LD_PRELOAD-Wl,-wrap,将是可行的解决方案,但我有麻烦做他们的工作,由于一些技术原因:如何拦截dlopen()内的文件系统访问?

  • ld.so已经由时间LD_PRELOAD映射自己的符号是处理。拦截初始加载对我来说并不重要,但此时解决了工作人员功能,以便将来的呼叫通过它们。我认为LD_PRELOAD为时已晚。

  • 不知何故malloc避开了这个问题,因为上面的ld.so内malloc()不具有的功能free(),它只是调用memset()

  • 文件系统工作者功能,例如, __libc_read(),包含在ld.so中是静态的,所以我不能用-Wl,-wrap,__libc_read来拦截它们。

这可能都意味着我需要建立直接从源我自己ld.so而不是链接成一个包装。存在的挑战是,libcrtld-libc都是从相同的来源构建的。我知道在构建rtld-libc时定义了宏IS_IN_rtld,但是如何确保在仍然导出公共接口函数的同时只有一个静态数据结构副本? (这是一个glibc构建系统的问题,但我还没有找到这些细节的文档。)

有没有更好的方法进入dlopen()

注意:我不能使用特定于Linux的解决方案,如FUSE,因为这适用于不支持此类操作的最小“计算节点”内核。

+0

这不是你的问题的答案,所以我没有把它作为一个发布,但总的来说你不能做到这一点可靠:它可以通过直接调用系统调用而不通过动态库接口。如果您没有完全控制您要加载的库的编译方式,那么您可能会失败。像fakeroot这样的程序在大多数情况下都能正常工作,并且在某些情况下会出现可怕的情况。 –

+0

也就是说,你可以通过在自己的进程中运行动态库代码并使用'ptrace'来截获系统调用本身来完成这项工作。我已经取得了巨大的成功,它完全避免了所有的共享库废话。但它确实需要你完全重新设计你的逻辑,以便拥有一个完成ptrace内容的主进程和一个执行动态库内容的从进程。 –

+0

嗯,我需要'dlopen' /'dlsym'才能正常工作,但要以不同的方式访问文件系统。特别是在诸如Blue Gene等HPC环境中,涉及内核文件描述符的所有操作都是从计算节点IO节点提供的。这会导致高节点并发严重的争用问题。例如,加载引用大量编译共享库的Python应用程序在65k内核上需要大约4个小时。毋庸置疑,人们对于耗费25万个核心小时来加载他们的节目并不感到兴奋。 – Jed

回答

3

它似乎像LD_PRELOAD或轮候册,-wrap,将是可行的解决方案

--wrap解决方案不可能是可行的:它只能在(静态)链接时,你的ld.so并且libc.so.6libdl.so.2已经全部被链接,所以现在使用--wrap已经太迟了。

LD_PRELOAD可以工作,只是...... ld.so认为的事实,dlopen()电话open()内部实现细节。因此,它只是调用内部__open函数,绕过PLT,并且您可以插入open

莫名其妙的malloc规避问题

这是因为libc支持谁实现自己的malloc(例如用于调试)的用户。因此,呼叫例如callocdlopen确实经过PLT,并通过LD_PRELOAD插入。

这可能意味着我需要直接从源代码构建自己的ld.so,而不是将其链接到包装器中。

重建的ld.so会做什么?我想你想要它叫__llibc_open(在libc.so.6),但这不可能的原因很明显:它是ld.soopen s libc.so.6(在进程启动时)。

你可以重建ld.so与以open调用替换调用__open。这将导致ld.so经过PLT,并将其暴露给LD_PRELOAD中介。

如果你走这条路线,我建议你不要用你的新副本覆盖系统ld.so(犯错的可能性和渲染系统无法启动太好了)。而是将其安装到例如/usr/local/my-ld.so,然后将您的二进制文件链接到-Wl,--dynamic-linker=/usr/local/my-ld.so

另一种选择:运行时修补。这有点破解,但是你可以(一旦你获得了主控权)只需扫描.textld.so,然后查找CALL __open指令。如果没有剥离ld.so,则可以找到内部__open以及要修补的功能(例如open_verifydl-load.c中)。一旦你发现有趣的CALL,mprotect包含它的页面是可写的,并在你自己的中介层的地址(如果需要的话可以调用__libc_open)修补它,然后mprotect它回来。任何未来的dlopen()现在都会通过您的插入器。

+0

第一个想法很有用,但是在'dlopen()'中切换到'PLT'调用导致了段错误,所以我们将考虑第二个选项... –