gpt4 book ai didi

Linux 用户空间 ELF 加载器在 fork 后出现极其奇怪的行为

转载 作者:太空宇宙 更新时间:2023-11-04 05:45:18 25 4
gpt4 key购买 nike

考虑以下代码(由于公众需求而重新编译:):

#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, &regs);
/* 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, &regs);
/* 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() 由 parent fopen("log") 调用打开的文件。您将通过失败的断言看到这一点。

我进一步研究,发现这种情况发生在子进程加载期间。

这很奇怪,有两个原因:

  1. child 根本不应该知道 fopen() 调用,因为它发生在 fork() 之后
  2. 为什么加载程序会尝试 mmap 这个文件?它甚至不是可执行文件。

我在 glibc 中查看了 dl-load.c,但没有看到任何应该调用这种行为的内容。

有什么想法吗?

谢谢

最佳答案

这是一个有错误的代码,问题在于我在父上下文下解释了子文件描述符。正确的做法是跟踪子 open() 调用并保留文件名到子 fd 的映射。

感谢 nneonneo 帮助我解决这个问题。

关于Linux 用户空间 ELF 加载器在 fork 后出现极其奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12741031/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com