From: David van Moolenbroek Date: Mon, 9 Nov 2009 08:12:25 +0000 (+0000) Subject: Fix ptrace bug when reattaching to a detached process X-Git-Tag: v3.1.6~216 X-Git-Url: http://zhaoyanbai.com/repos/Bv9ARM.ch06.html?a=commitdiff_plain;h=a07f8d7646f6f8bee7078636574fbc04e9324f18;p=minix.git Fix ptrace bug when reattaching to a detached process --- diff --git a/kernel/system/do_trace.c b/kernel/system/do_trace.c index 9511c0f99..9344c2a2f 100644 --- a/kernel/system/do_trace.c +++ b/kernel/system/do_trace.c @@ -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; diff --git a/servers/pm/trace.c b/servers/pm/trace.c index 4652e639c..8b833bd75 100644 --- a/servers/pm/trace.c +++ b/servers/pm/trace.c @@ -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); diff --git a/test/test42.c b/test/test42.c index 35e371cb3..83828eafb 100644 --- a/test/test42.c +++ b/test/test42.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #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; {