0

“在调用进程映像中由 atexit() 注册的任何函数都未在新进程映像中注册”。

这是代码:

pid = fork();
if (pid == 0) {
    atexit(check_mem);
    return execv(...);
}

check_mem 函数在 execv() 之后没有被调用。因为上面的“线”。在 execv 调用后注册函数的任何技巧?

在此先感谢您的帮助。

4

4 回答 4

7

当你 exec* 某些东西时,atexit 处理程序不会执行。

execv 替换了当前的进程映像,包括您注册的任何 atexit 处理程序,因此您实际上无能为力 - 您的代码已经消失。

于 2011-10-15T14:07:31.390 回答
3

有点棘手但可行 - 创建一个共享库(我们称之为 check_mem.so),其 aa 函数如下所示:

__attribute__((constructor)) void runs_first(void) {
  atexit(check_mem);
};

请注意,check_mem 需要在库中定义,而不是在您的程序中。

现在在 execve 中,将 LD_PRELOAD=/path/to/check_mem.so 放入传递给程序的环境变量(execve 的最后一个参数)。

将会发生的是,当新程序运行时,它将加载您的 check_mem 库并在(几乎)所有其他代码之前运行 runs_first 函数。

只有当您正在执行的程序是动态链接时,它才会起作用,但 AFAIK 这是唯一的限制。

编辑:正如评论正确指出的那样,它也不适用于 setuid 程序。我仍然认为它很有可能会涵盖您的用例。

于 2011-10-15T15:51:58.860 回答
1

完美的解决方案是使用 ptrace() 如下:

pid = fork();
if (pid == 0) {
    ptrace(PTRACE_TRACEME, 0, 0, 0);
    return execve(...);
}

wait(NULL);
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEEXIT);
ptrace(PTRACE_CONT, pid, 0, (void*)0);

    while(1){
    waitpid(pid, &status, 0);
    if((WSTOPSIG(status) == SIGTRAP) && (status & (PTRACE_EVENT_EXIT << 8)))
        break;

    ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status));
}

check_mem();

ptrace(PTRACE_CONT, pid, 0, 0);

致谢:www.wienand.org/junkcode/linux/stopper.c

于 2011-10-17T10:41:10.637 回答
1

就像没有说的那样, exec 替换了您的流程。您可以尝试使用 <stdlib.h> 的int system (char *s)函数来启动带有 args 的程序。与 execve 不同,系统在衍生进程退出时返回,例如

pid = fork();
if (pid == 0) {
    atexit(check_mem);
    system ("program arg1 arg2 ...");
    exit (0); /* Calls atexit handlers. */
}
于 2011-10-15T14:12:08.360 回答