summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2004-09-07 17:49:13 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-09-07 17:49:13 -0700
commitfad0738bb26cfbdab6952e3cf480622881760276 (patch)
tree28afb036fc547c368287d6a7b61db5cbd85cd5a1 /kernel
parentcece79ae3a396b6c311a20380904be376c1d9273 (diff)
[PATCH] ptrace userspace API preservation
This makes any ptrace operation that finds the target in TASK_STOPPED state morph it into TASK_TRACED state before doing anything. This necessitates reverting the last_siginfo accesses to check instead of assume last_siginfo is set, since it's no longer impossible to be in TASK_TRACED without being stopped in ptrace_stop (though there are no associated races to worry about). Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/ptrace.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index a38087f5c6cb..6b1b8ae06c28 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -81,13 +81,20 @@ int ptrace_check_attach(struct task_struct *child, int kill)
* be changed by us so it's not changing right after this.
*/
read_lock(&tasklist_lock);
- if ((child->ptrace & PT_PTRACED) && child->parent == current)
+ 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 (!ret && !kill) {
- if (child->state != TASK_TRACED)
- return -ESRCH;
wait_task_inactive(child);
}
@@ -298,13 +305,15 @@ static int ptrace_setoptions(struct task_struct *child, long data)
static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data)
{
- BUG_ON(child->last_siginfo == NULL);
+ if (child->last_siginfo == NULL)
+ return -EINVAL;
return copy_siginfo_to_user(data, child->last_siginfo);
}
static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
{
- BUG_ON(child->last_siginfo == NULL);
+ if (child->last_siginfo == NULL)
+ return -EINVAL;
if (copy_from_user(child->last_siginfo, data, sizeof (siginfo_t)) != 0)
return -EFAULT;
return 0;