我想做的是进行系统调用,让内核表现得好像是另一个进程在进行调用。您可以将其视为模拟另一个进程。我知道我可能会使用 ptrace 弄乱程序的代码,但这不是很优雅,可能需要进行调整才能与我正在做的任何过程一起工作。另外,我所要求的对于内核应该是可能的,而不必触及其他进程的内存或执行进程,当然除非我正在执行的系统调用的影响会导致这种情况。
我认为它的工作方式是有一个(特权)系统调用(我们称它为 setepid
,表示“设置有效的 PID”),它接受 PID 作为参数。在 setepid
之后,该进程(或可能仅该线程)进行的任何 future 系统调用都将表现得好像是指定的进程进行系统调用一样。异常(exception)是 setepid
调用本身,它可用于恢复原始上下文或以其他方式定位不同的进程。
例如,以下代码可用于将已运行进程(本例中的 PID 1234)的标准输出重定向到文件 output.txt
,该文件位于进程 1234 的当前工作中目录:
setepid(1234); /* perform following system calls on process 1234 */
int fd = open("output.txt", O_WRONLY|O_CREAT|O_TRUNC);
if (fd > 0) {
dup2(fd, 1);
close(fd);
}
setepid(0); /* done acting as 1234, restore original context */
这可能存在的一个问题是 "output.txt"
字符串常量,它作为指针传递。根据 setepid
的实现方式,也许出于必要,它可能将该指针视为进程 1234 内存中的地址。由于在编译时在另一个进程中静态分配内存(包括常量)甚至没有意义,因此绕过它需要像这样丑陋的东西:
setepid(1234);
char *buf = mmap(NULL, 12, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
setepid(0);
const char *str = "output.txt\0"; /* extra byte to make it a multiple of 4 */
/* Disclaimer: I'm not sure if I'm using ptrace correctly, but you get the idea. */
ptrace(PTRACE_ATTACH, 1234, NULL, NULL);
ptrace(PTRACE_POKEDATA, 1234, buf, *(void**)str);
ptrace(PTRACE_POKEDATA, 1234, buf+4, *(void**)(str+4));
ptrace(PTRACE_POKEDATA, 1234, buf+8, *(void**)(str+8));
ptrace(PTRACE_DETACH, 1234, NULL, NULL);
setepid(1234);
int fd = open(buf, O_WRONLY|O_CREAT|O_TRUNC);
if (fd > 0) {
dup2(fd, 1);
close(fd);
}
setepid(0);
我假设这样的机制不存在,但我希望我是错的。如果我的假设是正确的,是否有任何问题会阻止将其添加到 future 版本的 Linux 中?在内核模块中实现它会很简单(甚至可能)吗?这听起来像是一个危险但功能强大且可能有用的工具。
最佳答案
如果不有效地将代码注入(inject)目标线程,您所提议的内容将无法工作,而您已经可以使用 ptrace 完成这些工作。
其中一个问题是存在仅由当前线程修改的数据。由于没有其他人修改它,因此可以在没有锁的情况下轻松读取它。但是用你的方法,不变量会被打破。一个简单的例子是凭据。
这也不适用于提供的玩具 fd 更换盒。当以 fd 作为参数进行任何系统调用时,必须找到目标文件指针。如果 fd 表是共享的,则必须引用该文件,因为其他人可以同时关闭(fd)。内核对单线程进程进行了微优化——因为表不是共享的,所以没有人关闭 fd,所以以后不需要引用(和取消引用)它。再一次,当您关闭线程使用的 fd 时,fd 表的突然修改很容易导致释放后使用。
等等。
简而言之,这是不可能飞起来的。您可以做的最接近的事情是使用 ptrace 注入(inject)系统调用。
关于linux - 是否有 Linux 系统调用可以让我在另一个进程的上下文中进行系统调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41253216/