【发布时间】:2018-03-01 11:18:11
【问题描述】:
我们有一个产品可以加载一个共享对象,该对象使用“dll 注入”和“检测”技术监控随机进程(我们称之为 myDb)中的内部函数调用。
目前,我们的共享对象有一个内部线程,用于接收来自我们主进程的消息,该主进程是一个外部实体。
在 myDb fork() 之前一切正常,并创建了一个不以 execve() 结尾的相同子进程。这个相同的子进程主线程在调用 fork() 的父线程的上下文中启动,并且所有其他父线程都不再存在于子线程中。这可能会破坏我们的共享对象内部状态,因为我们的内部线程可能会在任何执行点消失(请参阅http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them 中有关混合线程与分叉的更多信息)。
MyDb 可以在不询问我们的情况下使用 fork,因此,如果我错了,请纠正我,看来我们别无选择,只能让我们的代码在没有内部线程的情况下工作。
我能想到的唯一选择是异步 i/o。 根据http://man7.org/linux/man-pages/man7/aio.7.html,来自异步例程的通知是使用 sigevent 完成的。 sigevent 可以使用 SIGEV_SIGNAL 来使用信号或使用 SIGEV_THREAD 接收通知,根据手册页,它使用下面的实际线程。 因此,在我看来,我们唯一的选择是使用带有 SIGEV_SIGNAL 选项的异步 i/o。但这也有很多限制,因为在信号处理程序中处理消息是危险的,因为只能调用异步信号安全函数。
我很乐意在这里对我的问题提出任何建议。
谢谢。
【问题讨论】:
-
MyDb 可以在不询问我们的情况下使用 fork,因此,如果我错了,请纠正我,看来我们别无选择,只能让我们的代码在没有内部线程的情况下工作。 但是如果你这样做,你的代码如何知道它是原始父进程还是分叉子进程?无论您处于何种状态,都将在子节点中进行快照和复制,如果您处于事务中间,则可能处于不一致的状态。异步 IO 不会解决这个问题,甚至可能让事情变得更糟 - 子进程将如何处理看似已调度但真正属于父进程的 IO 操作?
-
你是对的。这就是为什么我们还要拦截 fork() 调用。我还遇到了 pthread_atfork(),理论上它可以帮助我同步 fork() 并避免损坏,但如果可能的话,我更喜欢另一种方法。
-
我可以提供替代解决方案吗?不要在随机的其他进程中注入代码。当另一个“有用的”进程将自己注入到包括我们在内的随机其他进程中时,我不得不花费相当多的时间来调试“我们的”软件。所以不是我们的代码崩溃了,尽管我们认为它是“我们的”进程。只有当注入器和受害者是由同一个组织编写时,注入才是可行的,最好是由同一个团队编写,这样它们就可以一起进行测试。
-
我们这样做显然不是为了好玩——它是一种安全产品。别担心,当供应商看到我们的代码映射到内存空间时,他们做的第一件事就是禁用我们的产品。
-
您可以使用执行
ptrace(PTRACE_O_TRACEFORK, ...)的ptracer 进程(在您自己注入的线程允许跟踪该进程之后)捕获所有fork()调用,以便您可以让新的孩子“执行" 一个同样注入的函数来重新创建观察者线程(通过寄存器操作;需要一个预先准备好的一次性“堆栈”)。低开销,高复杂度;可以确保安全(尽管大多数开发人员,包括对安全敏感的软件开发人员,都不会打扰)。
标签: c linux unix asynchronous shared-libraries