ptrace: fix ptrace_unfreeze_traced() race with rt-lock

The patch "ptrace: fix ptrace vs tasklist_lock race" changed
ptrace_freeze_traced() to take task->saved_state into account, but
ptrace_unfreeze_traced() has the same problem and needs a similar fix:
it should check/update both ->state and ->saved_state.

Reported-by: Luis Claudio R. Goncalves <lgoncalv@redhat.com>
Fixes: "ptrace: fix ptrace vs tasklist_lock race"
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: stable-rt@vger.kernel.org
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
This commit is contained in:
Oleg Nesterov 2020-11-03 12:39:01 +01:00 committed by Alibek Omarov
parent bc0a27b923
commit 6bd4eef1d8
1 changed files with 15 additions and 8 deletions

View File

@ -213,8 +213,8 @@ static bool ptrace_freeze_traced(struct task_struct *task)
static void ptrace_unfreeze_traced(struct task_struct *task)
{
if (task->state != __TASK_TRACED)
return;
unsigned long flags;
bool frozen = true;
WARN_ON(!task->ptrace || task->parent != current);
@ -223,12 +223,19 @@ static void ptrace_unfreeze_traced(struct task_struct *task)
* Recheck state under the lock to close this race.
*/
spin_lock_irq(&task->sighand->siglock);
if (task->state == __TASK_TRACED) {
if (__fatal_signal_pending(task))
wake_up_state(task, __TASK_TRACED);
else
task->state = TASK_TRACED;
}
raw_spin_lock_irqsave(&task->pi_lock, flags);
if (task->state == __TASK_TRACED)
task->state = TASK_TRACED;
else if (task->saved_state == __TASK_TRACED)
task->saved_state = TASK_TRACED;
else
frozen = false;
raw_spin_unlock_irqrestore(&task->pi_lock, flags);
if (frozen && __fatal_signal_pending(task))
wake_up_state(task, __TASK_TRACED);
spin_unlock_irq(&task->sighand->siglock);
}