diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-11 14:08:49 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-11 14:08:49 -0400 |
| commit | f358166a9405e4f1d8e50d8f415c26d95505b6de (patch) | |
| tree | 7f5349d9e8b59633b9f8a7bd9bcd45ace1d21a41 /kernel | |
| parent | 0e44dc383787b472a7f13564c6bd8a44cc07d408 (diff) | |
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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/ptrace.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index b0f8da80d7d4..921c22ad16e4 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -155,8 +155,26 @@ int ptrace_attach(struct task_struct *task) | |||
| 155 | if (task->tgid == current->tgid) | 155 | if (task->tgid == current->tgid) |
| 156 | goto out; | 156 | goto out; |
| 157 | 157 | ||
| 158 | write_lock_irq(&tasklist_lock); | 158 | repeat: |
| 159 | /* | ||
| 160 | * Nasty, nasty. | ||
| 161 | * | ||
| 162 | * We want to hold both the task-lock and the | ||
| 163 | * tasklist_lock for writing at the same time. | ||
| 164 | * But that's against the rules (tasklist_lock | ||
| 165 | * is taken for reading by interrupts on other | ||
| 166 | * cpu's that may have task_lock). | ||
| 167 | */ | ||
| 159 | task_lock(task); | 168 | task_lock(task); |
| 169 | local_irq_disable(); | ||
| 170 | if (!write_trylock(&tasklist_lock)) { | ||
| 171 | local_irq_enable(); | ||
| 172 | task_unlock(task); | ||
| 173 | do { | ||
| 174 | cpu_relax(); | ||
| 175 | } while (!write_can_lock(&tasklist_lock)); | ||
| 176 | goto repeat; | ||
| 177 | } | ||
| 160 | 178 | ||
| 161 | /* the same process cannot be attached many times */ | 179 | /* the same process cannot be attached many times */ |
| 162 | if (task->ptrace & PT_PTRACED) | 180 | if (task->ptrace & PT_PTRACED) |
