diff options
| author | Jan Engelmohr <jan.engelmohr@mailbox.tu-dresden.de> | 2016-08-01 13:31:29 +0200 |
|---|---|---|
| committer | Moyster <oysterized@gmail.com> | 2016-08-26 16:15:25 +0200 |
| commit | 97ef32aefecf27ce57455ac16a2da18ac7e2c1d6 (patch) | |
| tree | 813972e3812b6a7caf1464068e8c774e7334e962 /kernel/ptrace.c | |
| parent | 1e9ab116c0933c30e51bf68071eb822a90451a6d (diff) | |
3.10.76 -> 3.10.77
Diffstat (limited to 'kernel/ptrace.c')
| -rw-r--r-- | kernel/ptrace.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index afadcf7b4..118323bc8 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -720,6 +720,8 @@ static int ptrace_peek_siginfo(struct task_struct *child, static int ptrace_resume(struct task_struct *child, long request, unsigned long data) { + bool need_siglock; + if (!valid_signal(data)) return -EIO; @@ -747,8 +749,26 @@ static int ptrace_resume(struct task_struct *child, long request, user_disable_single_step(child); } + /* + * Change ->exit_code and ->state under siglock to avoid the race + * with wait_task_stopped() in between; a non-zero ->exit_code will + * wrongly look like another report from tracee. + * + * Note that we need siglock even if ->exit_code == data and/or this + * status was not reported yet, the new status must not be cleared by + * wait_task_stopped() after resume. + * + * If data == 0 we do not care if wait_task_stopped() reports the old + * status and clears the code too; this can't race with the tracee, it + * takes siglock after resume. + */ + need_siglock = data && !thread_group_empty(current); + if (need_siglock) + spin_lock_irq(&child->sighand->siglock); child->exit_code = data; wake_up_state(child, __TASK_TRACED); + if (need_siglock) + spin_unlock_irq(&child->sighand->siglock); return 0; } |
