11

子プロセスはptraceシステムコールを使用してその親をトレースできますか?

OsはLinux2.6です

ありがとう。

upd1:「それ自体」からprocess1をトレースしたい。ptrace(process1_pid, PTRACE_ATTACH)不可能なので、子プロセスからフォークしてやってみます。しかし、私にはできません。カーネルが子の親プロセスのトレースを禁止しているなど、奇妙なエラーがあります

UPD2:このようなトレースはセキュリティポリシーによって禁止できます。どのポリシーがこれを行いますか?カーネルのチェックコードはどこにありますか?

UPD3:組み込みLinuxでは、PEEKDATAでエラーは発生しませんが、GETREGSではエラーが発生しません:

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

errno = EPERM

4

2 に答える 2

10

この質問は本当に興味がありました。それで私はそれを試すためにいくつかのコードを書きました。

まず、プロセスをトレースする場合、名前(つまり)を除いて、ほとんどの目的でトレースプロセスが親になることに注意して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.cmake 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;
}

親の仮想アドレス空間の複製を利用して、どこを見ればよいかを知っていることに注意してください。また、子が終了したときに、親が続行できるようにする必要がある暗黙のデタッチがあると思われることにも注意してください。これ以上調査しませんでした。

于 2010-02-07T06:35:03.283 に答える
1

はい、可能です...GETREGSでも機能します。x86でチェック(マットジョイナーコードに基づく、彼に感謝)

#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, &regs));
        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?
于 2010-02-08T14:54:20.177 に答える