ptrace_attach: fix possible deadlock schenario with irqs
Eric Biederman points out that we can't take the task_lock while holding tasklist_lock for writing, because another CPU that holds the task lock might take an interrupt that then tries to take tasklist_lock for writing. Which would be a nasty deadlock, with one CPU spinning forever in an interrupt handler (although admittedly you need to really work at triggering it ;) Since the ptrace_attach() code is special and very unusual, just make it be extra careful, and use trylock+repeat to avoid the possible deadlock. Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: Eric W. Biederman <ebiederm@xmission.com> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
0e44dc3837
commit
f358166a94
1 changed files with 19 additions and 1 deletions
|
@ -155,8 +155,26 @@ int ptrace_attach(struct task_struct *task)
|
||||||
if (task->tgid == current->tgid)
|
if (task->tgid == current->tgid)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
write_lock_irq(&tasklist_lock);
|
repeat:
|
||||||
|
/*
|
||||||
|
* Nasty, nasty.
|
||||||
|
*
|
||||||
|
* We want to hold both the task-lock and the
|
||||||
|
* tasklist_lock for writing at the same time.
|
||||||
|
* But that's against the rules (tasklist_lock
|
||||||
|
* is taken for reading by interrupts on other
|
||||||
|
* cpu's that may have task_lock).
|
||||||
|
*/
|
||||||
task_lock(task);
|
task_lock(task);
|
||||||
|
local_irq_disable();
|
||||||
|
if (!write_trylock(&tasklist_lock)) {
|
||||||
|
local_irq_enable();
|
||||||
|
task_unlock(task);
|
||||||
|
do {
|
||||||
|
cpu_relax();
|
||||||
|
} while (!write_can_lock(&tasklist_lock));
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
|
|
||||||
/* the same process cannot be attached many times */
|
/* the same process cannot be attached many times */
|
||||||
if (task->ptrace & PT_PTRACED)
|
if (task->ptrace & PT_PTRACED)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue