X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fptrace.c;h=b14b4a4677296a2e9fc2c4c961b314ffd64e623d;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=8b2856aaf6410310d83751e1af1bef61bf447115;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 8b2856aaf..b14b4a467 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -55,6 +55,15 @@ void __ptrace_unlink(task_t *child) REMOVE_LINKS(child); child->parent = child->real_parent; SET_LINKS(child); + + if (child->state == TASK_TRACED) { + /* + * Turn a tracing stop into a normal stop now, + * since with no tracer there would be no way + * to wake it up with SIGCONT or SIGKILL. + */ + child->state = TASK_STOPPED; + } } /* @@ -62,20 +71,35 @@ void __ptrace_unlink(task_t *child) */ int ptrace_check_attach(struct task_struct *child, int kill) { - if (!(child->ptrace & PT_PTRACED)) - return -ESRCH; + int ret = -ESRCH; - if (child->parent != current) - return -ESRCH; + /* + * We take the read lock around doing both checks to close a + * possible race where someone else was tracing our child and + * detached between these two checks. After this locked check, + * we are sure that this is our traced child and that can only + * be changed by us so it's not changing right after this. + */ + read_lock(&tasklist_lock); + if ((child->ptrace & PT_PTRACED) && child->parent == current && + child->signal != NULL) { + ret = 0; + spin_lock_irq(&child->sighand->siglock); + if (child->state == TASK_STOPPED) { + child->state = TASK_TRACED; + } else if (child->state != TASK_TRACED && !kill) { + ret = -ESRCH; + } + spin_unlock_irq(&child->sighand->siglock); + } + read_unlock(&tasklist_lock); - if (!kill) { - if (child->state != TASK_STOPPED) - return -ESRCH; + if (!ret && !kill) { wait_task_inactive(child); } /* All systems go.. */ - return 0; + return ret; } int ptrace_attach(struct task_struct *task) @@ -178,8 +202,6 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in if (bytes > PAGE_SIZE-offset) bytes = PAGE_SIZE-offset; - flush_cache_page(vma, addr); - maddr = kmap(page); if (write) { copy_to_user_page(vma, page, addr, @@ -322,24 +344,3 @@ int ptrace_request(struct task_struct *child, long request, return ret; } - -void ptrace_notify(int exit_code) -{ - BUG_ON (!(current->ptrace & PT_PTRACED)); - - /* Let the debugger run. */ - current->exit_code = exit_code; - set_current_state(TASK_STOPPED); - notify_parent(current, SIGCHLD); - schedule(); - - /* - * Signals sent while we were stopped might set TIF_SIGPENDING. - */ - - spin_lock_irq(¤t->sighand->siglock); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); -} - -EXPORT_SYMBOL(ptrace_notify);