Linux 上的跨进程复制

pts*_*pts 5 linux file-descriptors socket

我想复制一个在 Linux 上无关进程中运行的文件描述符。我知道sendmsg(2)SCM_RIGHTS(例如/sf/ask/314260341/),但只有在另一个进程是合作。我需要一个不需要其他进程积极合作的解决方案。我也知道我可以先创建文件描述符,保留一个副本,然后创建另一个进程,但我需要一个解决方案,其中另一个进程创建自己的文件描述符。

我可以看到文件描述符:

$ ls -l /proc/13115/fd/3
lrwx------ 1 pts pts 64 2013-05-04 13:15 /proc/13115/fd/3 -> socket:[19445454]
Run Code Online (Sandbox Code Playgroud)

但是,open("/proc/13115/fd/3", O_RDWR)在另一个进程中执行返回错误No such device or address。还有其他可行的方法吗?可能与ptrace

gol*_*cks 5

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

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

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

  • @pts goldilocks 是正确的:一个进程无法访问另一个进程的内存。进程可以使用“ptrace”让内核代表其访问另一个进程的内存。访问另一个进程的“/proc/$pid/mem”需要首先使用“ptrace”进行设置。 (4认同)

Gil*_*il' 4

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

像往常一样,如果您有权跟踪进程,您可以做任何您喜欢的事情,包括调用它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);
}
Run Code Online (Sandbox Code Playgroud)

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

call pts_gift_fd("%s", %d)
detach
quit
Run Code Online (Sandbox Code Playgroud)