考虑以下代码(由于公众需求重新编译:):
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <syscall.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <sys/user.h>
#include <sys/wait.h>
static FILE* logfile = 0;
int main(int argc, char * argv[], char * envp[]) {
pid_t pid = fork();
if (pid == 0) { /* child */
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1)
assert(0 && "ptrace traceme failed");
/* signal the parent that the child is ready */
kill(getpid(), SIGSTOP);
execve("a.out", argv, envp);
} else { /* parent */
int status = 0, ret = 0;
if ((logfile = fopen("log","a+")) == 0)
assert(0 && "failed to open logfile");
struct stat logfile_stat_buf;
if (stat("log", &logfile_stat_buf) != 0)
assert(0 && "failed to stat logfile");
/* sync the parent and the child */
if (waitpid(pid, &status, __WALL | __WCLONE) < 0)
assert(0 && "waiting on child failed");
ptrace(PTRACE_SYSCALL, pid, 0, 0);
while (waitpid(pid, &status, __WALL | __WCLONE) > 0) {
/* syscall entry */
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
/* check to see if it's a mmap call
* void *mmap2(void *addr, size_t length, int prot,int flags, int fd, off_t pgoffset);
*/
printf("Child entereing a syscall %d\n", regs.orig_eax);
if (regs.orig_eax == SYS_mmap2) {
/* stat the file for the inode */
int fd = regs.edi;
struct stat stat_buf;
if ((fstat(fd, &stat_buf) == 0) && (stat_buf.st_ino == logfile_stat_buf.st_ino))
assert(0 && "child trying to mmap parent inode");
}
ptrace(PTRACE_SYSCALL, pid, 0, 0);
waitpid(pid, &status, __WALL | __WCLONE);
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
/* syscall exit */
printf("Child exiting a syscall %d\n", regs.orig_eax);
ptrace(PTRACE_SYSCALL, pid, 0, 0);
}
if (fclose(logfile) != 0)
assert(0 && "failed to close logfile");
}
return 0;
}
a.out 程序是一个简单的 main() { return 0; } 程序。
如果您编译并运行此代码,您将看到子进程尝试 mmap()父fopen("log") 调用打开的文件。您将通过失败的断言看到这一点。
我进一步研究并发现这发生在加载子进程期间。
这很奇怪,原因有两个:
- 孩子根本不应该知道 fopen() 调用,因为它发生在 fork() 之后
- 为什么加载程序会尝试映射此文件?它甚至不是可执行文件。
我在 glibc 中查看了 dl-load.c ,但没有看到任何应该调用这种行为的东西。
有任何想法吗?
谢谢