ptrace: fix ptrace_unfreeze_traced() race with rt-lock

[ Upstream commit 0fdc91971b ]

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: Tom Zanussi <zanussi@kernel.org>
This commit is contained in:
Oleg Nesterov
2020-11-03 12:39:01 +01:00
committed by jianlong.wang
parent b4623989a8
commit e2ef23f859

View File

@@ -207,8 +207,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);
@@ -217,12 +217,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);
}