Linux 上的跨进程 dup

Linux 上的跨进程 dup

我想复制一个在 Linux 上不相关进程中运行的文件描述符。我知道关于发送消息(2)SCM_RIGHTS(例如https://stackoverflow.com/questions/4489433/sending-file-descriptor-over-unix-domain-socket-and-select) ,但这仅在其他进程合作时才有效。我需要一个不需要其他进程积极合作的解决方案。我还知道我可以先创建文件描述符,保留副本,然后创建另一个进程,但我需要一个解决方案,让另一个进程创建自己的文件描述符。

我可以看到文件描述符:

$ ls -l /proc/13115/fd/3
lrwx------ 1 pts pts 64 2013-05-04 13:15 /proc/13115/fd/3 -> socket:[19445454]

但是,open("/proc/13115/fd/3", O_RDWR)在另一个进程中执行会返回错误没有这样的设备或地址。还有其他有效的方法吗?可能与跟踪

答案1

这是设计使然:与其他进程共享文件描述符是明确的。默认情况下,文件描述符与进程自己的内存一样私有。

像往常一样,如果您有权利跟踪在此过程中,您可以做任何您喜欢的事情,包括调用sendmsg.传统上,调用ptrace需要以相同的用户ID运行;安全限制,例如 SELinux、功能、监狱等可以使ptrace限制更加严格。例如,在默认的 Ubuntu 配置下,非 root 进程只能调用ptrace其自己的后代(通过 AppArmor)。

稳健地使用ptrace有点棘手:您必须注入正确的数据,确保不要覆盖任何内容,并自行清理。因此,我的建议是以迂回方式注入代码,并使用现有工具触发该代码。

编写一个包含代码的小型共享库sendmsg,并将LD_PRELOAD其提供给其他进程。这是一些未经测试的缺少错误检查的骨架代码。

int pts_gift_fd (char *path, int fd) {
    int sock;
    struct sockaddr_un addr = {0};
    struct msghdr msg = {0};
    struct iovec iov = {0};
    addr.sun_family = AF_UNIX;
    strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
    /* Populate msg, iov as in the code you've already found */
    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    connect(sock, (struct sockaddr*)&addr, sizeof(addr));
    sendmsg(sock, &msg, 0);
    close(sock);
}

然后,要触发代码,请运行gdb -n -pid 13115 -batch -x /dev/stdin并向popen其提供如下输入(其中%d是您想要获取的 fd,并且%s是您之前创建并正在侦听的 unix 套接字的路径):

call pts_gift_fd("%s", %d)
detach
quit

答案2

您不能这样做的原因与您无法访问不相关进程的内存的原因相同,因为文件描述符另一个进程的内存的一部分。存在有关此类内容的信息的唯一原因/proc是因为内核在那里提供了它,并且它是只读的(因此有方法可以检查复印件进程内存)。

如果它与文件相关,您当然可以尝试访问该文件。如果它是一个套接字,你可以使用它来窥探它libpcap或从中派生出的东西。

情况基本上是这样的:文件描述符(再次)是进程内存的一部分。描述符有一个存在于内核空间中的底层缓冲区;当进程从描述符读取或写入时,它正在向该缓冲区写入或从该缓冲区写入。对于数据输出,内核适当地将缓冲区刷新(到硬件);对于传入的数据,当进程清空缓冲区时,它会(从硬件)重新填充缓冲区。 AFAIK,这些缓冲区不能被其他进程访问,尽管有一些方法(例如 libpcap)阅读由特定内核接口确定的某种形式的数据,就像 proc 接口可以从进程的用户空间内存提供一些数据一样。

相关内容