diff options
Diffstat (limited to 'kernel/ptrace.c')
| -rw-r--r-- | kernel/ptrace.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index e337390fce01..8392a9da6450 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -33,13 +33,9 @@ | |||
| 33 | */ | 33 | */ |
| 34 | void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) | 34 | void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) |
| 35 | { | 35 | { |
| 36 | BUG_ON(!list_empty(&child->ptrace_list)); | 36 | BUG_ON(!list_empty(&child->ptrace_entry)); |
| 37 | if (child->parent == new_parent) | 37 | list_add(&child->ptrace_entry, &new_parent->ptraced); |
| 38 | return; | ||
| 39 | list_add(&child->ptrace_list, &child->parent->ptrace_children); | ||
| 40 | remove_parent(child); | ||
| 41 | child->parent = new_parent; | 38 | child->parent = new_parent; |
| 42 | add_parent(child); | ||
| 43 | } | 39 | } |
| 44 | 40 | ||
| 45 | /* | 41 | /* |
| @@ -73,12 +69,8 @@ void __ptrace_unlink(struct task_struct *child) | |||
| 73 | BUG_ON(!child->ptrace); | 69 | BUG_ON(!child->ptrace); |
| 74 | 70 | ||
| 75 | child->ptrace = 0; | 71 | child->ptrace = 0; |
| 76 | if (ptrace_reparented(child)) { | 72 | child->parent = child->real_parent; |
| 77 | list_del_init(&child->ptrace_list); | 73 | list_del_init(&child->ptrace_entry); |
| 78 | remove_parent(child); | ||
| 79 | child->parent = child->real_parent; | ||
| 80 | add_parent(child); | ||
| 81 | } | ||
| 82 | 74 | ||
| 83 | if (task_is_traced(child)) | 75 | if (task_is_traced(child)) |
| 84 | ptrace_untrace(child); | 76 | ptrace_untrace(child); |
| @@ -492,15 +484,34 @@ int ptrace_traceme(void) | |||
| 492 | /* | 484 | /* |
| 493 | * Are we already being traced? | 485 | * Are we already being traced? |
| 494 | */ | 486 | */ |
| 487 | repeat: | ||
| 495 | task_lock(current); | 488 | task_lock(current); |
| 496 | if (!(current->ptrace & PT_PTRACED)) { | 489 | if (!(current->ptrace & PT_PTRACED)) { |
| 490 | /* | ||
| 491 | * See ptrace_attach() comments about the locking here. | ||
| 492 | */ | ||
| 493 | unsigned long flags; | ||
| 494 | if (!write_trylock_irqsave(&tasklist_lock, flags)) { | ||
| 495 | task_unlock(current); | ||
| 496 | do { | ||
| 497 | cpu_relax(); | ||
| 498 | } while (!write_can_lock(&tasklist_lock)); | ||
| 499 | goto repeat; | ||
| 500 | } | ||
| 501 | |||
| 497 | ret = security_ptrace(current->parent, current, | 502 | ret = security_ptrace(current->parent, current, |
| 498 | PTRACE_MODE_ATTACH); | 503 | PTRACE_MODE_ATTACH); |
| 504 | |||
| 499 | /* | 505 | /* |
| 500 | * Set the ptrace bit in the process ptrace flags. | 506 | * Set the ptrace bit in the process ptrace flags. |
| 507 | * Then link us on our parent's ptraced list. | ||
| 501 | */ | 508 | */ |
| 502 | if (!ret) | 509 | if (!ret) { |
| 503 | current->ptrace |= PT_PTRACED; | 510 | current->ptrace |= PT_PTRACED; |
| 511 | __ptrace_link(current, current->real_parent); | ||
| 512 | } | ||
| 513 | |||
| 514 | write_unlock_irqrestore(&tasklist_lock, flags); | ||
| 504 | } | 515 | } |
| 505 | task_unlock(current); | 516 | task_unlock(current); |
| 506 | return ret; | 517 | return ret; |
