]> Zhao Yanbai Git Server - minix.git/commitdiff
Fix ptrace bug when reattaching to a detached process
authorDavid van Moolenbroek <david@minix3.org>
Mon, 9 Nov 2009 08:12:25 +0000 (08:12 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Mon, 9 Nov 2009 08:12:25 +0000 (08:12 +0000)
kernel/system/do_trace.c
servers/pm/trace.c
test/test42.c

index 9511c0f993315fffcfacec458dc3aaab8e67eb4d..9344c2a2f0fe7f786c7c2c59173a4d6d9083dfaf 100644 (file)
@@ -163,6 +163,10 @@ register message *m_ptr;
        m_ptr->CTL_DATA = 0;
        break;
 
+  case T_DETACH:               /* detach tracer */
+       rp->p_misc_flags &= ~MF_SC_ACTIVE;
+
+       /* fall through */
   case T_RESUME:               /* resume execution */
        RTS_LOCK_UNSET(rp, P_STOP);
        m_ptr->CTL_DATA = 0;
index 4652e639c8f6524d9716ad616d391dc24a78f402..8b833bd75ec1bb338065a6a4fe773fa8e988876e 100644 (file)
@@ -175,7 +175,6 @@ PUBLIC int do_trace()
        /* Resume the child as if nothing ever happened. */ 
        child->mp_flags &= ~STOPPED;
        child->mp_trace_flags = 0;
-       req = T_RESUME;
 
        check_pending(child);
 
index 35e371cb3b7261a90ae0a50bbe7fc64bf8410eb0..83828eafb52e027a08070996b5a8cd88f5fe72bb 100644 (file)
@@ -7,6 +7,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/wait.h>
+#include <sys/select.h>
 #include <sys/ptrace.h>
 
 #define ITERATIONS 3
@@ -56,6 +57,8 @@ _PROTOTYPE(void test_syscall_child, (void));
 _PROTOTYPE(void test_syscall, (void));
 _PROTOTYPE(void test_tracefork_child, (void));
 _PROTOTYPE(void test_tracefork, (void));
+_PROTOTYPE(void test_reattach_child, (void));
+_PROTOTYPE(void test_reattach, (void));
 _PROTOTYPE(void altexec, (int setflag, int *traps, int *stop));
 _PROTOTYPE(void test_altexec, (void));
 _PROTOTYPE(void test_noaltexec, (void));
@@ -120,6 +123,7 @@ int a;
   if (m & 0020000) test_tracefork();
   if (m & 0040000) test_altexec();
   if (m & 0100000) test_noaltexec();
+  if (m & 0200000) test_reattach();
 }
 
 pid_t traced_fork(c)
@@ -1322,6 +1326,90 @@ void test_noaltexec()
   if (stop >= 0) e(14);
 }
 
+void test_reattach_child()
+{
+  struct timeval tv;
+
+  if (READ() != 0) e(100);
+
+  tv.tv_sec = 2;
+  tv.tv_usec = 0;
+  if (select(0, NULL, NULL, NULL, &tv) != 0) e(101);
+
+  exit(42);
+}
+
+void test_reattach()
+{
+  pid_t pid;
+  int r, status, count;
+
+  subtest = 17;
+
+  pid = traced_fork(test_reattach_child);
+
+  if (kill(pid, SIGSTOP) != 0) e(1);
+
+  if (waitpid(pid, &status, 0) != pid) e(2);
+  if (!_WIFSTOPPED(status)) e(3);
+  if (WSTOPSIG(status) != SIGSTOP) e(4);
+
+  WRITE(0);
+
+  signal(SIGALRM, dummy_handler);
+  alarm(1);
+
+  /* Start tracing system calls. We don't know how many there will be until
+   * we reach the child's select(), so we have to interrupt ourselves.
+   */
+  if (ptrace(T_SYSCALL, pid, 0, 0) != 0) e(5);
+
+  for (count = 0; (r = waitpid(pid, &status, 0)) == pid; count++) {
+       if (!_WIFSTOPPED(status)) e(6);
+       if (WSTOPSIG(status) != SIGTRAP) e(7);
+
+       if (ptrace(T_SYSCALL, pid, 0, 0) != 0) e(8);
+  }
+
+  if (r != -1 || errno != EINTR) e(9);
+
+  /* We always start with syscall enter event; the last event we should have
+   * seen before the alarm was entering the select() call.
+   */
+  if (!(count % 2)) e(10);
+
+  /* Detach, and immediately attach again. */
+  detach_running(pid);
+
+  if (ptrace(T_ATTACH, pid, 0, 0) != 0) e(11);
+
+  if (waitpid(pid, &status, 0) != pid) e(12);
+  if (!_WIFSTOPPED(status)) e(13);
+  if (WSTOPSIG(status) != SIGSTOP) e(14);
+
+  if (ptrace(T_SYSCALL, pid, 0, 0) != 0) e(15);
+
+  if (waitpid(pid, &status, 0) != pid) e(16);
+
+  for (count = 0; _WIFSTOPPED(status); count++) {
+       if (WSTOPSIG(status) != SIGTRAP) e(17);
+
+       if (ptrace(T_SYSCALL, pid, 0, 0) != 0) e(18);
+
+       if (waitpid(pid, &status, 0) != pid) e(19);
+  }
+
+  if (!_WIFEXITED(status)) e(20);
+  if ((r = WEXITSTATUS(status)) != 42) e(r);
+
+  /* We must not have seen the select()'s syscall leave event, and the last
+   * event will be the syscall enter for the exec().
+   */
+  if (!(count % 2)) e(21);
+
+  traced_wait();
+}
+
 void e(n)
 int n;
 {