Someone added “ptrace” to the Wikipedia article , which states that on Linux, the ptraced process cannot execute another process itself. I am trying to determine if (and if so, why) this is the case. Below is a simple program that I tried to test. My program does not work (the sub-process does not work properly), but I am pretty sure that this is my mistake, and not something fundamental.
Essentially, the initial process A processes process B , which in turn forks C. A ptraces its child B , B ptraces its child C. After they are configured, all three processes are only written to print A , B or C in stdout once per second.
In practice, what happens is that A and B work fine, but C prints only once and then gets stuck. When checking with ps -eo pid,cmd,wchan , C is displayed, stuck in the ptrace_stop kernel ptrace_stop , and the rest are in hrtimer_nanosleep , where I expect all three to be.
Very often, all three work (therefore, the program prints Cs, as well as As and Bs), which makes me believe in some conditions of the race in the initial setup.
My guesses about what might be wrong are as follows:
- do something with A , seeing <<26> associated with B , seeing <<26> on signal C and wait (2), saying that they are like from B (but the hacker call PTRACE_CONT for both pids does not fix things) ?
- C must be bound to B - has C inherit ptrace instead of A (and B call ptrace neither an error nor a rewrite)?
Can anyone understand what I'm doing wrong? Thanks.
#include <stdio.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <sys/ptrace.h> #include <sys/wait.h> static void a(){ while(1){ printf ("A\n"); fflush(stdout); sleep(1); } } static void b(){ while(1){ printf ("B\n"); fflush(stdout); sleep(1); } } static void c(){ while(1){ printf ("C\n"); fflush(stdout); sleep(1); } } static void sigchld_handler(int sig){ int result; pid_t child_pid = wait(NULL); // find who send us this SIGCHLD printf("SIGCHLD on %d\n", child_pid); result=ptrace(PTRACE_CONT, child_pid, sig, NULL); if(result) { perror("continuing after SIGCHLD"); } } int main(int argc, char **argv){ pid_t mychild_pid; int result; printf("pidA = %d\n", getpid()); signal(SIGCHLD, sigchld_handler); mychild_pid = fork(); if (mychild_pid) { printf("pidB = %d\n", mychild_pid); result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL); if(result==-1){ perror("outer ptrace"); } a(); } else { mychild_pid = fork(); if (mychild_pid) { printf("pidC = %d\n", mychild_pid); result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL); if(result==-1){ perror("inner ptrace"); } b(); } else { c(); } } return 0; }