Linux中拦截文件打开事件

时间:2017-07-23 14:42:15

标签: android linux unix posix inotify

假设我们有一个可能dlopen()某个第三方库的流程。此库可能会对某些用户只具有写访问权限的文件执行open("write_only_logfile", O_WRONLY)。如果此库尝试打开文件,我们需要能够得到通知,因此稍后我们可能dup()返回描述符并重定向输出。 几乎没有什么限制可以使拦截变得更难:

  • LD_PRELOAD被禁止 - 无法挂钩open()
  • inotify(7)无法提供帮助,因为用户对"write_only_logfile"没有读取权限且由管理员拥有
  • 我们无权访问图书馆资源,因此无法对其进行修改
  • "write_only_logfile"在库中被硬编码,因此我们无法传递其他名称来执行重定向

我想知道Linux是否有一种有效的方式来帮助解决这种情况。 特别考虑到流程可能open()经常出现杂项文件这一事实。

P.S。为了避免混淆和更好地理解 - 它是一个带有加载JVM的常规Android应用程序。如果app挂起(所谓的ANR) - 系统会向其发送SIGQUIT。通过open() s /data/anr/traces.txt的专用线程接收信号,并将JVM状态写入其中。这些数据对于调试非常有用。但是由于安全原因,app无法直接读取该文件(所有应用程序都写入,因此可能有些敏感)。无论如何,我认为拦截我的流程会写入的内容是绝对公平的。

P.S.S。在最坏的情况下,可以找到JVM库映像(libart.so)并手动修补open()的跳转槽。但它听起来不太好。

3 个答案:

答案 0 :(得分:1)

如果这只是将写入(和读取)重定向到单个文件,则可以在mount命名空间中运行该应用程序,并为该特定文件提供合适的绑定装入。以这种方式进行设置可能需要一个小的SUID二进制文件。

更通用的解决方案可以快速接近联合文件系统,并且正确解决这个问题非常困难。即使是内核联合文件系统overlayfs,也无法提供完整的POSIX语义。

答案 1 :(得分:1)

听起来你处境很麻烦。下面简要提到的大多数解决方案都保证会干扰SELinux,所以不要接受我的任何一个。

使用strace调试您自己的进程以拦截open是普通Linux上常用的解决方案之一。我不确定它是否适用于Android;对于从一些新版本开始的非可调试应用程序(如果还没有被禁止),它肯定可能会成为禁止限制。

seccomp-bpf是另一种可能性。可能不适用于较旧的Android版本,但因为Android O seccomp将成为Android安全性启动的保证部分。在仅警告模式下拦截open,并在发生有趣事情时(通过调试或信号)将控制权交还给自己。

如果按需打开/data/anr/traces.txt,您应该能够通过使用inotify或通过轮询观看/proc/self/fd/的内容来观察。你可以通过设置开放线程的优点来减少比赛的影响......

以上所有内容只是部分解决方案,您仍然可能需要解码发生的实际open系统调用(strace源代码可能对strace / seccomp解决方案有帮助,/proc/self/fd/的readlink)和行为在它上面(dup2,如你所说)。

  

" write_only_logfile"在库内硬编码

是否可以修改库/可执行文件数据段的内存? Afaik mprotectPROTECT_EXEC特别受到严格限制,但至少允许使用mmap(以支持JIT编译器等)。有可能做一些事情来编辑字符串常量(只要这样做是可能的并且允许的话,我不确定自己的意思。)

答案 2 :(得分:0)

您需要LD_PRELOAD来挂钩应用程序。要挂钩第三方库,只需在库之前正常加载挂钩(或将它放在可执行文件中)。

假设库从libc调用open而不是直接调用相应的系统调用,并且它以正常方式链接,那么您的代码中只有一个名为open的函数。从libc(open或其他)调用RTLD_NEXT。第三方库(当然还有所有其他库)将解析其open符号到您的函数。