Commit f358166a9405e4f1d8e50d8f415c26d95505b6de
1 parent
0e44dc3837
Exists in
master
and in
7 other branches
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>
Showing 1 changed file with 19 additions and 1 deletions Side-by-side Diff
kernel/ptrace.c
... | ... | @@ -155,8 +155,26 @@ |
155 | 155 | if (task->tgid == current->tgid) |
156 | 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 | 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 | 179 | /* the same process cannot be attached many times */ |
162 | 180 | if (task->ptrace & PT_PTRACED) |