如何让exec启动的子进程的/proc/self/exe指向父进程路径?
解决子进程
readlink("/proc/self/exe")返回父进程路径的可行方案 针对你遇到的问题——想让通过exec启动的子进程,在调用readlink("/proc/self/exe")时返回父进程的可执行路径而非自身实际路径——这里有几个实用的解决方案,从内核级到用户态都有,你可以根据权限和场景选择:
1. 挂载命名空间 + 绑定挂载(内核级无代码修改方案)
如果你的父进程拥有CAP_SYS_ADMIN权限(比如以root运行),这是最直接的无侵入方案,不需要修改任何代码或注入库:
- 第一步,父进程先获取自身的可执行路径:用
readlink("/proc/self/exe", ...)拿到/path/to/parent - 第二步,调用
clone()创建子进程时带上CLONE_NEWNS标志,创建独立的挂载命名空间 - 第三步,在子进程的初始化逻辑里:
- 先重新挂载
/proc(新命名空间的/proc默认未正确初始化):mount("proc", "/proc", "proc", 0, NULL) - 将父进程的可执行文件绑定挂载到子进程的实际路径:
mount(parent_path, child_path, NULL, MS_BIND, NULL),这里child_path是子进程的真实可执行文件路径(比如/path/to/child) - 最后调用
execve(child_path, argv, envp)启动子进程
这样一来,子进程在自己的挂载命名空间里,其可执行文件路径被替换成了父进程的路径,/proc/self/exe自然就会返回父进程的路径了。
- 先重新挂载
2. LD_PRELOAD拦截(用户态简便方案,无需特殊权限)
其实你想到的LD_PRELOAD已经是用户态下最简便的方案了,不需要root权限,实现起来也很简单:
步骤1:编写拦截共享库
创建一个C文件(比如fake_exe_link.c):
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dlfcn.h> ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) { static ssize_t (*orig_readlink)(const char *, char *, size_t) = NULL; if (!orig_readlink) { orig_readlink = dlsym(RTLD_NEXT, "readlink"); } // 拦截对/proc/self/exe的读取 if (strcmp(pathname, "/proc/self/exe") == 0) { const char *parent_exe = getenv("PARENT_EXE_PATH"); if (parent_exe) { size_t len = strlen(parent_exe); len = len >= bufsiz ? bufsiz - 1 : len; memcpy(buf, parent_exe, len); buf[len] = '\0'; return len; } } // 其他调用转发给原始readlink return orig_readlink(pathname, buf, bufsiz); }
步骤2:编译成共享库
gcc -shared -fPIC -o libfakeexe.so fake_exe_link.c -ldl
步骤3:启动子进程
父进程先设置环境变量,再通过LD_PRELOAD加载共享库启动子进程:
# 先获取父进程自身路径 export PARENT_EXE_PATH=$(readlink -f /proc/self/exe) # 启动子进程 LD_PRELOAD=./libfakeexe.so /path/to/your/child_executable
这个方案完全在用户态操作,不需要任何特殊权限,适合大多数场景。
3. ptrace跟踪修改系统调用(复杂,不推荐)
你也可以用ptrace跟踪子进程的readlink系统调用,当检测到子进程读取/proc/self/exe时,修改返回值为父进程的路径。但这个方案需要处理系统调用的进入、退出逻辑,代码复杂度高,容易出现兼容性问题,除非特殊需求,否则不推荐使用。
内容的提问来源于stack exchange,提问作者Ivanna
相关产品推荐
相关产品推荐

