Stopping ptraced processes

From: Victor Zandy (zandy@cs.wisc.edu)
Date: Fri Mar 17 2000 - 19:00:06 EST


    On x86 Linux 2.2.12, I can't figure out a reliable way to keep a
process stopped after ptrace operations.

For example, after this sequence

     ptrace(PTRACE_ATTACH, pid, 0, 0);
     waitpid(pid, NULL, 0);
     ptrace(PTRACE_DETACH, pid, 0, SIGSTOP);

the process (pid) is not stopped. So this does not help me.

After this sequence

     ptrace(PTRACE_ATTACH, pid, 0, 0); (Sequence 1)
     waitpid(pid, NULL, 0);
     kill(pid, SIGSTOP);
     ptrace(PTRACE_DETACH, pid, 0, 0);

the process is stopped. However, following it with this sequence

     ptrace(PTRACE_ATTACH, pid, 0, 0);
     waitpid(pid, NULL, 0);
     ptrace(PTRACE_DETACH, pid, 0, 0);

causes it to run again. On the other hand, following Sequence 1 with
this sequence (prefacing the above sequence with a sleep)

     sleep(1);
     ptrace(PTRACE_ATTACH, pid, 0, 0);
     waitpid(pid, NULL, 0);
     ptrace(PTRACE_DETACH, pid, 0, 0);

causes the process to remain stopped.

    I've been trying to understand this behavior from kernel sources,
but I can't figure it out -- can anyone help me?

    The program copied below demonstrates the behavior I describe. My
questions in terms of this program are

- why does the child stop for arg==2, but not arg==1?
- why does the child stop for arg==4, but not arg==3?

    My real problem is I need a way to keep a process stopped across
multiple ptrace attach/detach operations. Does anyone have a reliable
technique?

Thanks,
Vic Zandy

#include <sys/ptrace.h>
#include <signal.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
     int arg, pid;

     arg = atoi(argv[1]);

     pid = fork();
     if (pid == 0)
          while (1) {
               sleep(1);
               printf("I'm running\n");
          }

     if (arg == 1) {
          ptrace(PTRACE_ATTACH, pid, 0, 0);
          waitpid(pid, NULL, 0);
          ptrace(PTRACE_DETACH, pid, 0, SIGSTOP);
          /* child is left RUNNING */
     } else if (arg == 2) {
          ptrace(PTRACE_ATTACH, pid, 0, 0);
          waitpid(pid, NULL, 0);
          kill(pid, SIGSTOP);
          ptrace(PTRACE_DETACH, pid, 0, 0);
          /* child is left STOPPED */
     } else if (arg == 3) {
          ptrace(PTRACE_ATTACH, pid, 0, 0);
          waitpid(pid, NULL, 0);
          kill(pid, SIGSTOP);
          ptrace(PTRACE_DETACH, pid, 0, 0);

          ptrace(PTRACE_ATTACH, pid, 0, 0);
          waitpid(pid, NULL, 0);
          ptrace(PTRACE_DETACH, pid, 0, 0);
          /* child is left RUNNING */
     } else if (arg == 4) {
          ptrace(PTRACE_ATTACH, pid, 0, 0);
          waitpid(pid, NULL, 0);
          kill(pid, SIGSTOP);
          ptrace(PTRACE_DETACH, pid, 0, 0);
          sleep(1);
          ptrace(PTRACE_ATTACH, pid, 0, 0);
          waitpid(pid, NULL, 0);
          ptrace(PTRACE_DETACH, pid, 0, 0);
          /* child is left STOPPED */
     }

     while (1)
          ;
     return 0;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Mar 23 2000 - 21:00:23 EST