假设我们有一个可能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()
的跳转槽。但它听起来不太好。
答案 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 mprotect
和PROTECT_EXEC
特别受到严格限制,但至少允许使用mmap(以支持JIT编译器等)。有可能做一些事情来编辑字符串常量(只要这样做是可能的并且允许的话,我不确定自己的意思。)
答案 2 :(得分:0)
您需要LD_PRELOAD来挂钩应用程序。要挂钩第三方库,只需在库之前正常加载挂钩(或将它放在可执行文件中)。
假设库从libc调用open
而不是直接调用相应的系统调用,并且它以正常方式链接,那么您的代码中只有一个名为open
的函数。从libc(open
或其他)调用RTLD_NEXT
。第三方库(当然还有所有其他库)将解析其open
符号到您的函数。