父进程的跟踪

发布于 2024-08-20 17:03:26 字数 424 浏览 11 评论 0原文

子进程可以使用 ptrace 系统调用来跟踪其父进程吗?

操作系统是linux 2.6

谢谢。

更新1: 我想从“自身”追踪process1。这是不可能的,所以我 fork 并尝试从子进程执行 ptrace(process1_pid, PTRACE_ATTACH) 。但我不能,有一个奇怪的错误,比如内核禁止子进程跟踪其父进程

UPD2:安全策略可以禁止这种跟踪。哪些警察这样做?内核中的检查代码在哪里?

UPD3:在我的嵌入式 Linux 上,PEEKDATA 没有错误,但 GETREGS 没有错误:

child: getregs parent: -1
errno is 1, strerror is Operation not permitted 

errno = EPERM

Can child process use the ptrace system call to trace its parent?

Os is linux 2.6

Thanks.

upd1:
I want to trace process1 from "itself". It is impossible, so I do fork and try to do ptrace(process1_pid, PTRACE_ATTACH) from child process. But I can't, there is a strange error, like kernel prohibits child from tracing their parent processes

UPD2: such tracing can be prohibited by security policies. Which polices do this? Where is the checking code in the kernel?

UPD3: on my embedded linux I have no errors with PEEKDATA, but not with GETREGS:

child: getregs parent: -1
errno is 1, strerror is Operation not permitted 

errno = EPERM

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷爱 2024-08-27 17:03:26

这个问题让我很感兴趣。所以我写了一些代码来尝试一下。

首先请记住,在跟踪进程时,除了名称(即 getppid())之外,跟踪进程在大多数情况下都会成为父进程。首先,手册的 PTRACE_ATTACH 部分的片段很有帮助:

   PTRACE_ATTACH
          Attaches to the process specified in pid,  making  it  a  traced
          "child"  of the calling process; the behavior of the child is as
          if it had done a PTRACE_TRACEME.  The calling  process  actually
          becomes the parent of the child process for most purposes (e.g.,
          it will receive notification of  child  events  and  appears  in
          ps(1)  output  as  the  child's parent), but a getppid(2) by the
          child will still return the PID of  the  original  parent.   The
          child  is  sent a SIGSTOP, but will not necessarily have stopped
          by the completion of this call; use  wait(2)  to  wait  for  the
          child to stop.  (addr and data are ignored.)

现在这是我编写的代码,用于测试和验证您实际上可以 ptrace() 您的父级 (您可以通过将其转储到名为 blah.c 的文件中并运行 make blah 来构建它:

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>

int main()
{
    pid_t pid = fork();
    assert(pid != -1);
    int status;
    long readme = 0;
    if (pid)
    {
        readme = 42;
        printf("parent: child pid is %d\n", pid);
        assert(pid == wait(&status));
        printf("parent: child terminated?\n");
        assert(0 == status);
    }
    else
    {
        pid_t tracee = getppid();
        printf("child: parent pid is %d\n", tracee);
        sleep(1); // give parent time to set readme
        assert(0 == ptrace(PTRACE_ATTACH, tracee));
        assert(tracee == waitpid(tracee, &status, 0));
        printf("child: parent should be stopped\n");
        printf("child: peeking at parent: %ld\n", ptrace(PTRACE_PEEKDATA, tracee, &readme));
    }
    return 0;
}

请注意,我正在利用父级虚拟地址空间的复制来了解位置另请注意,当子进程终止时,我怀疑存在隐式分离,必须允许父进程继续,我没有进一步调查。

This question really interested me. So I wrote some code to try it out.

Firstly keep in mind, that when tracing a process, the tracing process becomes a parent for most purposes, except in name (i.e. getppid()). Firstly, a snippet of the PTRACE_ATTACH section of the manual is helpful:

   PTRACE_ATTACH
          Attaches to the process specified in pid,  making  it  a  traced
          "child"  of the calling process; the behavior of the child is as
          if it had done a PTRACE_TRACEME.  The calling  process  actually
          becomes the parent of the child process for most purposes (e.g.,
          it will receive notification of  child  events  and  appears  in
          ps(1)  output  as  the  child's parent), but a getppid(2) by the
          child will still return the PID of  the  original  parent.   The
          child  is  sent a SIGSTOP, but will not necessarily have stopped
          by the completion of this call; use  wait(2)  to  wait  for  the
          child to stop.  (addr and data are ignored.)

Now here is the code I wrote to test and verify that you can in fact ptrace() your parent (you can build this by dumping it in a file named blah.c and running make blah:

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>

int main()
{
    pid_t pid = fork();
    assert(pid != -1);
    int status;
    long readme = 0;
    if (pid)
    {
        readme = 42;
        printf("parent: child pid is %d\n", pid);
        assert(pid == wait(&status));
        printf("parent: child terminated?\n");
        assert(0 == status);
    }
    else
    {
        pid_t tracee = getppid();
        printf("child: parent pid is %d\n", tracee);
        sleep(1); // give parent time to set readme
        assert(0 == ptrace(PTRACE_ATTACH, tracee));
        assert(tracee == waitpid(tracee, &status, 0));
        printf("child: parent should be stopped\n");
        printf("child: peeking at parent: %ld\n", ptrace(PTRACE_PEEKDATA, tracee, &readme));
    }
    return 0;
}

Note that I'm exploiting the replication of the parent's virtual address space to know where to look. Also note that when the child then terminates, I suspect there's an implicit detach which must allow the parent to continue, I didn't investigate further.

向日葵 2024-08-27 17:03:26

是的,有可能...
甚至 GETREGS 也能工作。
在 x86 上检查
(基于 Matt Joiner 代码,谢谢他)

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>

int main()
{
    pid_t pid = fork();
//    assert(pid != -1);
    int status;
    long readme = 0;
    struct user_regs_struct regs;
    if (pid)
    {
        readme = 42;
        printf("parent: child pid is %d\n", pid);
        assert(pid == wait(&status));
        printf("parent: child terminated?\n");
        assert(0 == status);
    }
    else
    {
        pid_t tracee = getppid();
        printf("child: parent pid is %d\n", tracee);
        sleep(1); // give parent time to set readme
        assert(0 == ptrace(PTRACE_ATTACH, tracee));
        assert(tracee == waitpid(tracee, &status, 0));
        printf("child: parent should be stopped\n");
        printf("child: peeking at parent: %ld\n", ptrace(PTRACE_PEEKDATA, tracee, &readme, NULL));
        printf("Regs was %p, %p, %p, %p; &status is %p \n", regs.eax, regs.ebx, regs.ecx, regs.edx, &status);
        printf("child: getregs parent: %ld\n", ptrace(PTRACE_GETREGS, tracee, NULL, ®s));
        printf("Regs is %p, %p, %p, %p; &status is %p \n", regs.eax, regs.ebx, regs.ecx, regs.edx, &status);
    }
    return 0;
}

结果:

child: parent pid is 1188
parent: child pid is 1189
child: parent should be stopped
child: peeking at parent: 42
Regs was (nil), (nil), (nil), (nil); &status is 0xbfffea50
child: getregs parent: 0
Regs is 0xfffffe00, 0xffffffff, 0xbfffea50, (nil); &status is 0xbfffea50
parent: child terminated?

Yes it is possible...
Even GETREGS works.
Checked on x86
(based on Matt Joiner code, thanks him)

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>

int main()
{
    pid_t pid = fork();
//    assert(pid != -1);
    int status;
    long readme = 0;
    struct user_regs_struct regs;
    if (pid)
    {
        readme = 42;
        printf("parent: child pid is %d\n", pid);
        assert(pid == wait(&status));
        printf("parent: child terminated?\n");
        assert(0 == status);
    }
    else
    {
        pid_t tracee = getppid();
        printf("child: parent pid is %d\n", tracee);
        sleep(1); // give parent time to set readme
        assert(0 == ptrace(PTRACE_ATTACH, tracee));
        assert(tracee == waitpid(tracee, &status, 0));
        printf("child: parent should be stopped\n");
        printf("child: peeking at parent: %ld\n", ptrace(PTRACE_PEEKDATA, tracee, &readme, NULL));
        printf("Regs was %p, %p, %p, %p; &status is %p \n", regs.eax, regs.ebx, regs.ecx, regs.edx, &status);
        printf("child: getregs parent: %ld\n", ptrace(PTRACE_GETREGS, tracee, NULL, ®s));
        printf("Regs is %p, %p, %p, %p; &status is %p \n", regs.eax, regs.ebx, regs.ecx, regs.edx, &status);
    }
    return 0;
}

result:

child: parent pid is 1188
parent: child pid is 1189
child: parent should be stopped
child: peeking at parent: 42
Regs was (nil), (nil), (nil), (nil); &status is 0xbfffea50
child: getregs parent: 0
Regs is 0xfffffe00, 0xffffffff, 0xbfffea50, (nil); &status is 0xbfffea50
parent: child terminated?
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文