diff options
| author | Roland McGrath <roland@redhat.com> | 2004-09-07 17:49:13 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-09-07 17:49:13 -0700 |
| commit | fad0738bb26cfbdab6952e3cf480622881760276 (patch) | |
| tree | 28afb036fc547c368287d6a7b61db5cbd85cd5a1 /kernel | |
| parent | cece79ae3a396b6c311a20380904be376c1d9273 (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.c | 19 |
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; |
