Messages in this thread Patch in this message | | | Date | Wed, 10 Feb 2010 10:38:05 -0800 | Subject | Re: Race in ptrace. | From | Salman Qazi <> |
| |
[+tavis]
Sorry for the delayed response. I was out sick yesterday. I have made a simpler version of tavis's test case:
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <signal.h> #include <sched.h> #include <errno.h> #include <sys/ptrace.h> #include <assert.h> #include <sys/types.h> #include <sys/wait.h>
int child_pid; int ant_pid;
void child(void) { ptrace(PTRACE_TRACEME, 0, NULL, NULL); asm("int3"); while(1); }
void antagonist(void) { while (1) { kill(child_pid, SIGSTOP); usleep(2); kill(child_pid, SIGCONT); usleep(2); } }
int do_fork(void (*callback)(void)) { int pid; pid = fork(); if (pid) return pid; callback();
exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { int status; assert((child_pid = do_fork(child)) > 0); assert((ant_pid = do_fork(antagonist)) > 0); waitpid(child_pid, &status, 0); ptrace(PTRACE_SYSCALL, child_pid, NULL, NULL); while(1) { if (waitpid(child_pid, &status, 0) <= 0) { printf("Errno %d\n", errno); exit(EXIT_FAILURE); } if (WIFSTOPPED(status)) { printf("stopped: %d\n", WSTOPSIG(status));
/* This should work, but sometimes it doesn't */ if (ptrace(PTRACE_SYSCALL, child_pid, NULL, WSTOPSIG(status)) < 0) { /* Oddly it works the second time! */ assert (ptrace(PTRACE_SYSCALL, child_pid, NULL, WSTOPSIG(status)) < 0); } } } }
On Wed, Feb 10, 2010 at 5:35 AM, Oleg Nesterov <oleg@redhat.com> wrote: > On 02/09, Oleg Nesterov wrote: >> >> Salman Qazi wrote: >> > >> > A race in ptrace was pointed to us by a fellow Google engineer, Tavis >> > Ormandy. The race involves interaction between a tracer, a tracee and >> > an antagonist. The tracer is tracing the tracee with PTRACE_SYSCALL and >> > waits on the tracee. In the mean time, an antagonist blasts the tracee >> > with SIGCONTs. >> >> Could you please explain how did observe this race? Do you have a >> test-case, or could you explain how we can reproduce it? >> >> Because, >> >> > It turns out that a SIGCONT wakes up the >> > tracee in kernel mode, >> >> SIGCONT must not wake up a TASK_TRACED task. > > In case I wasn't clear... > > --- a/kernel/signal.c > +++ b/kernel/signal.c > @@ -697,6 +697,10 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) > * and wake all threads. > */ > rm_from_queue(SIG_KERNEL_STOP_MASK, &signal->shared_pending); > + if (p->ptrace & PT_PTRACED) { > + p->ptrace |= PT_WAKING; > + mb(); > + } > > Please note that we are going to do wake_up_state(state), and > this state can never have __TASK_TRACED bit set. > > And we can't change ->ptrace here, we can race with the tracer. > > There are other problems with this patch, but the main problem > is that I can't understand what this patch tries to fix. > > IOW, please provide more info ;) > > Oleg. > > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |