diff options
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 64 |
1 files changed, 41 insertions, 23 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 0eeb7e66722c..921c22ad16e4 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -56,10 +56,6 @@ void ptrace_untrace(task_t *child) | |||
56 | signal_wake_up(child, 1); | 56 | signal_wake_up(child, 1); |
57 | } | 57 | } |
58 | } | 58 | } |
59 | if (child->signal->flags & SIGNAL_GROUP_EXIT) { | ||
60 | sigaddset(&child->pending.signal, SIGKILL); | ||
61 | signal_wake_up(child, 1); | ||
62 | } | ||
63 | spin_unlock(&child->sighand->siglock); | 59 | spin_unlock(&child->sighand->siglock); |
64 | } | 60 | } |
65 | 61 | ||
@@ -81,7 +77,8 @@ void __ptrace_unlink(task_t *child) | |||
81 | add_parent(child); | 77 | add_parent(child); |
82 | } | 78 | } |
83 | 79 | ||
84 | ptrace_untrace(child); | 80 | if (child->state == TASK_TRACED) |
81 | ptrace_untrace(child); | ||
85 | } | 82 | } |
86 | 83 | ||
87 | /* | 84 | /* |
@@ -151,12 +148,34 @@ int ptrace_may_attach(struct task_struct *task) | |||
151 | int ptrace_attach(struct task_struct *task) | 148 | int ptrace_attach(struct task_struct *task) |
152 | { | 149 | { |
153 | int retval; | 150 | int retval; |
154 | task_lock(task); | 151 | |
155 | retval = -EPERM; | 152 | retval = -EPERM; |
156 | if (task->pid <= 1) | 153 | if (task->pid <= 1) |
157 | goto bad; | 154 | goto out; |
158 | if (task->tgid == current->tgid) | 155 | if (task->tgid == current->tgid) |
159 | goto bad; | 156 | goto out; |
157 | |||
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 | */ | ||
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 | } | ||
178 | |||
160 | /* the same process cannot be attached many times */ | 179 | /* the same process cannot be attached many times */ |
161 | if (task->ptrace & PT_PTRACED) | 180 | if (task->ptrace & PT_PTRACED) |
162 | goto bad; | 181 | goto bad; |
@@ -169,17 +188,15 @@ int ptrace_attach(struct task_struct *task) | |||
169 | ? PT_ATTACHED : 0); | 188 | ? PT_ATTACHED : 0); |
170 | if (capable(CAP_SYS_PTRACE)) | 189 | if (capable(CAP_SYS_PTRACE)) |
171 | task->ptrace |= PT_PTRACE_CAP; | 190 | task->ptrace |= PT_PTRACE_CAP; |
172 | task_unlock(task); | ||
173 | 191 | ||
174 | write_lock_irq(&tasklist_lock); | ||
175 | __ptrace_link(task, current); | 192 | __ptrace_link(task, current); |
176 | write_unlock_irq(&tasklist_lock); | ||
177 | 193 | ||
178 | force_sig_specific(SIGSTOP, task); | 194 | force_sig_specific(SIGSTOP, task); |
179 | return 0; | ||
180 | 195 | ||
181 | bad: | 196 | bad: |
197 | write_unlock_irq(&tasklist_lock); | ||
182 | task_unlock(task); | 198 | task_unlock(task); |
199 | out: | ||
183 | return retval; | 200 | return retval; |
184 | } | 201 | } |
185 | 202 | ||
@@ -420,21 +437,22 @@ int ptrace_request(struct task_struct *child, long request, | |||
420 | */ | 437 | */ |
421 | int ptrace_traceme(void) | 438 | int ptrace_traceme(void) |
422 | { | 439 | { |
423 | int ret; | 440 | int ret = -EPERM; |
424 | 441 | ||
425 | /* | 442 | /* |
426 | * Are we already being traced? | 443 | * Are we already being traced? |
427 | */ | 444 | */ |
428 | if (current->ptrace & PT_PTRACED) | 445 | task_lock(current); |
429 | return -EPERM; | 446 | if (!(current->ptrace & PT_PTRACED)) { |
430 | ret = security_ptrace(current->parent, current); | 447 | ret = security_ptrace(current->parent, current); |
431 | if (ret) | 448 | /* |
432 | return -EPERM; | 449 | * Set the ptrace bit in the process ptrace flags. |
433 | /* | 450 | */ |
434 | * Set the ptrace bit in the process ptrace flags. | 451 | if (!ret) |
435 | */ | 452 | current->ptrace |= PT_PTRACED; |
436 | current->ptrace |= PT_PTRACED; | 453 | } |
437 | return 0; | 454 | task_unlock(current); |
455 | return ret; | ||
438 | } | 456 | } |
439 | 457 | ||
440 | /** | 458 | /** |