diff options
| -rw-r--r-- | include/linux/init_task.h | 4 | ||||
| -rw-r--r-- | include/linux/sched.h | 26 | ||||
| -rw-r--r-- | kernel/exit.c | 226 | ||||
| -rw-r--r-- | kernel/fork.c | 6 | ||||
| -rw-r--r-- | kernel/ptrace.c | 37 |
5 files changed, 160 insertions, 139 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 9927a88674a3..93c45acf249a 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
| @@ -140,8 +140,8 @@ extern struct group_info init_groups; | |||
| 140 | .nr_cpus_allowed = NR_CPUS, \ | 140 | .nr_cpus_allowed = NR_CPUS, \ |
| 141 | }, \ | 141 | }, \ |
| 142 | .tasks = LIST_HEAD_INIT(tsk.tasks), \ | 142 | .tasks = LIST_HEAD_INIT(tsk.tasks), \ |
| 143 | .ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children), \ | 143 | .ptraced = LIST_HEAD_INIT(tsk.ptraced), \ |
| 144 | .ptrace_list = LIST_HEAD_INIT(tsk.ptrace_list), \ | 144 | .ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \ |
| 145 | .real_parent = &tsk, \ | 145 | .real_parent = &tsk, \ |
| 146 | .parent = &tsk, \ | 146 | .parent = &tsk, \ |
| 147 | .children = LIST_HEAD_INIT(tsk.children), \ | 147 | .children = LIST_HEAD_INIT(tsk.children), \ |
diff --git a/include/linux/sched.h b/include/linux/sched.h index ba2f859c6e4f..1941d8b5cf11 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1062,12 +1062,6 @@ struct task_struct { | |||
| 1062 | #endif | 1062 | #endif |
| 1063 | 1063 | ||
| 1064 | struct list_head tasks; | 1064 | struct list_head tasks; |
| 1065 | /* | ||
| 1066 | * ptrace_list/ptrace_children forms the list of my children | ||
| 1067 | * that were stolen by a ptracer. | ||
| 1068 | */ | ||
| 1069 | struct list_head ptrace_children; | ||
| 1070 | struct list_head ptrace_list; | ||
| 1071 | 1065 | ||
| 1072 | struct mm_struct *mm, *active_mm; | 1066 | struct mm_struct *mm, *active_mm; |
| 1073 | 1067 | ||
| @@ -1089,18 +1083,25 @@ struct task_struct { | |||
| 1089 | /* | 1083 | /* |
| 1090 | * pointers to (original) parent process, youngest child, younger sibling, | 1084 | * pointers to (original) parent process, youngest child, younger sibling, |
| 1091 | * older sibling, respectively. (p->father can be replaced with | 1085 | * older sibling, respectively. (p->father can be replaced with |
| 1092 | * p->parent->pid) | 1086 | * p->real_parent->pid) |
| 1093 | */ | 1087 | */ |
| 1094 | struct task_struct *real_parent; /* real parent process (when being debugged) */ | 1088 | struct task_struct *real_parent; /* real parent process */ |
| 1095 | struct task_struct *parent; /* parent process */ | 1089 | struct task_struct *parent; /* recipient of SIGCHLD, wait4() reports */ |
| 1096 | /* | 1090 | /* |
| 1097 | * children/sibling forms the list of my children plus the | 1091 | * children/sibling forms the list of my natural children |
| 1098 | * tasks I'm ptracing. | ||
| 1099 | */ | 1092 | */ |
| 1100 | struct list_head children; /* list of my children */ | 1093 | struct list_head children; /* list of my children */ |
| 1101 | struct list_head sibling; /* linkage in my parent's children list */ | 1094 | struct list_head sibling; /* linkage in my parent's children list */ |
| 1102 | struct task_struct *group_leader; /* threadgroup leader */ | 1095 | struct task_struct *group_leader; /* threadgroup leader */ |
| 1103 | 1096 | ||
| 1097 | /* | ||
| 1098 | * ptraced is the list of tasks this task is using ptrace on. | ||
| 1099 | * This includes both natural children and PTRACE_ATTACH targets. | ||
| 1100 | * p->ptrace_entry is p's link on the p->parent->ptraced list. | ||
| 1101 | */ | ||
| 1102 | struct list_head ptraced; | ||
| 1103 | struct list_head ptrace_entry; | ||
| 1104 | |||
| 1104 | /* PID/PID hash table linkage. */ | 1105 | /* PID/PID hash table linkage. */ |
| 1105 | struct pid_link pids[PIDTYPE_MAX]; | 1106 | struct pid_link pids[PIDTYPE_MAX]; |
| 1106 | struct list_head thread_group; | 1107 | struct list_head thread_group; |
| @@ -1876,9 +1877,6 @@ extern void wait_task_inactive(struct task_struct * p); | |||
| 1876 | #define wait_task_inactive(p) do { } while (0) | 1877 | #define wait_task_inactive(p) do { } while (0) |
| 1877 | #endif | 1878 | #endif |
| 1878 | 1879 | ||
| 1879 | #define remove_parent(p) list_del_init(&(p)->sibling) | ||
| 1880 | #define add_parent(p) list_add_tail(&(p)->sibling,&(p)->parent->children) | ||
| 1881 | |||
| 1882 | #define next_task(p) list_entry(rcu_dereference((p)->tasks.next), struct task_struct, tasks) | 1880 | #define next_task(p) list_entry(rcu_dereference((p)->tasks.next), struct task_struct, tasks) |
| 1883 | 1881 | ||
| 1884 | #define for_each_process(p) \ | 1882 | #define for_each_process(p) \ |
diff --git a/kernel/exit.c b/kernel/exit.c index 7453356a961f..1e909826a804 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -71,7 +71,7 @@ static void __unhash_process(struct task_struct *p) | |||
| 71 | __get_cpu_var(process_counts)--; | 71 | __get_cpu_var(process_counts)--; |
| 72 | } | 72 | } |
| 73 | list_del_rcu(&p->thread_group); | 73 | list_del_rcu(&p->thread_group); |
| 74 | remove_parent(p); | 74 | list_del_init(&p->sibling); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /* | 77 | /* |
| @@ -152,6 +152,18 @@ static void delayed_put_task_struct(struct rcu_head *rhp) | |||
| 152 | put_task_struct(container_of(rhp, struct task_struct, rcu)); | 152 | put_task_struct(container_of(rhp, struct task_struct, rcu)); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | /* | ||
| 156 | * Do final ptrace-related cleanup of a zombie being reaped. | ||
| 157 | * | ||
| 158 | * Called with write_lock(&tasklist_lock) held. | ||
| 159 | */ | ||
| 160 | static void ptrace_release_task(struct task_struct *p) | ||
| 161 | { | ||
| 162 | BUG_ON(!list_empty(&p->ptraced)); | ||
| 163 | ptrace_unlink(p); | ||
| 164 | BUG_ON(!list_empty(&p->ptrace_entry)); | ||
| 165 | } | ||
| 166 | |||
| 155 | void release_task(struct task_struct * p) | 167 | void release_task(struct task_struct * p) |
| 156 | { | 168 | { |
| 157 | struct task_struct *leader; | 169 | struct task_struct *leader; |
| @@ -160,8 +172,7 @@ repeat: | |||
| 160 | atomic_dec(&p->user->processes); | 172 | atomic_dec(&p->user->processes); |
| 161 | proc_flush_task(p); | 173 | proc_flush_task(p); |
| 162 | write_lock_irq(&tasklist_lock); | 174 | write_lock_irq(&tasklist_lock); |
| 163 | ptrace_unlink(p); | 175 | ptrace_release_task(p); |
| 164 | BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children)); | ||
| 165 | __exit_signal(p); | 176 | __exit_signal(p); |
| 166 | 177 | ||
| 167 | /* | 178 | /* |
| @@ -315,9 +326,8 @@ static void reparent_to_kthreadd(void) | |||
| 315 | 326 | ||
| 316 | ptrace_unlink(current); | 327 | ptrace_unlink(current); |
| 317 | /* Reparent to init */ | 328 | /* Reparent to init */ |
| 318 | remove_parent(current); | ||
| 319 | current->real_parent = current->parent = kthreadd_task; | 329 | current->real_parent = current->parent = kthreadd_task; |
| 320 | add_parent(current); | 330 | list_move_tail(¤t->sibling, ¤t->real_parent->children); |
| 321 | 331 | ||
| 322 | /* Set the exit signal to SIGCHLD so we signal init on exit */ | 332 | /* Set the exit signal to SIGCHLD so we signal init on exit */ |
| 323 | current->exit_signal = SIGCHLD; | 333 | current->exit_signal = SIGCHLD; |
| @@ -692,37 +702,71 @@ static void exit_mm(struct task_struct * tsk) | |||
| 692 | mmput(mm); | 702 | mmput(mm); |
| 693 | } | 703 | } |
| 694 | 704 | ||
| 695 | static void | 705 | /* |
| 696 | reparent_thread(struct task_struct *p, struct task_struct *father, int traced) | 706 | * Detach all tasks we were using ptrace on. |
| 707 | * Any that need to be release_task'd are put on the @dead list. | ||
| 708 | * | ||
| 709 | * Called with write_lock(&tasklist_lock) held. | ||
| 710 | */ | ||
| 711 | static void ptrace_exit(struct task_struct *parent, struct list_head *dead) | ||
| 697 | { | 712 | { |
| 698 | if (p->pdeath_signal) | 713 | struct task_struct *p, *n; |
| 699 | /* We already hold the tasklist_lock here. */ | ||
| 700 | group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p); | ||
| 701 | 714 | ||
| 702 | /* Move the child from its dying parent to the new one. */ | 715 | list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) { |
| 703 | if (unlikely(traced)) { | 716 | __ptrace_unlink(p); |
| 704 | /* Preserve ptrace links if someone else is tracing this child. */ | 717 | |
| 705 | list_del_init(&p->ptrace_list); | 718 | if (p->exit_state != EXIT_ZOMBIE) |
| 706 | if (ptrace_reparented(p)) | 719 | continue; |
| 707 | list_add(&p->ptrace_list, &p->real_parent->ptrace_children); | 720 | |
| 708 | } else { | 721 | /* |
| 709 | /* If this child is being traced, then we're the one tracing it | 722 | * If it's a zombie, our attachedness prevented normal |
| 710 | * anyway, so let go of it. | 723 | * parent notification or self-reaping. Do notification |
| 724 | * now if it would have happened earlier. If it should | ||
| 725 | * reap itself, add it to the @dead list. We can't call | ||
| 726 | * release_task() here because we already hold tasklist_lock. | ||
| 727 | * | ||
| 728 | * If it's our own child, there is no notification to do. | ||
| 711 | */ | 729 | */ |
| 712 | p->ptrace = 0; | 730 | if (!task_detached(p) && thread_group_empty(p)) { |
| 713 | remove_parent(p); | 731 | if (!same_thread_group(p->real_parent, parent)) |
| 714 | p->parent = p->real_parent; | 732 | do_notify_parent(p, p->exit_signal); |
| 715 | add_parent(p); | 733 | } |
| 716 | 734 | ||
| 717 | if (task_is_traced(p)) { | 735 | if (task_detached(p)) { |
| 718 | /* | 736 | /* |
| 719 | * If it was at a trace stop, turn it into | 737 | * Mark it as in the process of being reaped. |
| 720 | * a normal stop since it's no longer being | ||
| 721 | * traced. | ||
| 722 | */ | 738 | */ |
| 723 | ptrace_untrace(p); | 739 | p->exit_state = EXIT_DEAD; |
| 740 | list_add(&p->ptrace_entry, dead); | ||
| 724 | } | 741 | } |
| 725 | } | 742 | } |
| 743 | } | ||
| 744 | |||
| 745 | /* | ||
| 746 | * Finish up exit-time ptrace cleanup. | ||
| 747 | * | ||
| 748 | * Called without locks. | ||
| 749 | */ | ||
| 750 | static void ptrace_exit_finish(struct task_struct *parent, | ||
| 751 | struct list_head *dead) | ||
| 752 | { | ||
| 753 | struct task_struct *p, *n; | ||
| 754 | |||
| 755 | BUG_ON(!list_empty(&parent->ptraced)); | ||
| 756 | |||
| 757 | list_for_each_entry_safe(p, n, dead, ptrace_entry) { | ||
| 758 | list_del_init(&p->ptrace_entry); | ||
| 759 | release_task(p); | ||
| 760 | } | ||
| 761 | } | ||
| 762 | |||
| 763 | static void reparent_thread(struct task_struct *p, struct task_struct *father) | ||
| 764 | { | ||
| 765 | if (p->pdeath_signal) | ||
| 766 | /* We already hold the tasklist_lock here. */ | ||
| 767 | group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p); | ||
| 768 | |||
| 769 | list_move_tail(&p->sibling, &p->real_parent->children); | ||
| 726 | 770 | ||
| 727 | /* If this is a threaded reparent there is no need to | 771 | /* If this is a threaded reparent there is no need to |
| 728 | * notify anyone anything has happened. | 772 | * notify anyone anything has happened. |
| @@ -737,7 +781,8 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) | |||
| 737 | /* If we'd notified the old parent about this child's death, | 781 | /* If we'd notified the old parent about this child's death, |
| 738 | * also notify the new parent. | 782 | * also notify the new parent. |
| 739 | */ | 783 | */ |
| 740 | if (!traced && p->exit_state == EXIT_ZOMBIE && | 784 | if (!ptrace_reparented(p) && |
| 785 | p->exit_state == EXIT_ZOMBIE && | ||
| 741 | !task_detached(p) && thread_group_empty(p)) | 786 | !task_detached(p) && thread_group_empty(p)) |
| 742 | do_notify_parent(p, p->exit_signal); | 787 | do_notify_parent(p, p->exit_signal); |
| 743 | 788 | ||
| @@ -754,12 +799,15 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) | |||
| 754 | static void forget_original_parent(struct task_struct *father) | 799 | static void forget_original_parent(struct task_struct *father) |
| 755 | { | 800 | { |
| 756 | struct task_struct *p, *n, *reaper = father; | 801 | struct task_struct *p, *n, *reaper = father; |
| 757 | struct list_head ptrace_dead; | 802 | LIST_HEAD(ptrace_dead); |
| 758 | |||
| 759 | INIT_LIST_HEAD(&ptrace_dead); | ||
| 760 | 803 | ||
| 761 | write_lock_irq(&tasklist_lock); | 804 | write_lock_irq(&tasklist_lock); |
| 762 | 805 | ||
| 806 | /* | ||
| 807 | * First clean up ptrace if we were using it. | ||
| 808 | */ | ||
| 809 | ptrace_exit(father, &ptrace_dead); | ||
| 810 | |||
| 763 | do { | 811 | do { |
| 764 | reaper = next_thread(reaper); | 812 | reaper = next_thread(reaper); |
| 765 | if (reaper == father) { | 813 | if (reaper == father) { |
| @@ -768,58 +816,19 @@ static void forget_original_parent(struct task_struct *father) | |||
| 768 | } | 816 | } |
| 769 | } while (reaper->flags & PF_EXITING); | 817 | } while (reaper->flags & PF_EXITING); |
| 770 | 818 | ||
| 771 | /* | ||
| 772 | * There are only two places where our children can be: | ||
| 773 | * | ||
| 774 | * - in our child list | ||
| 775 | * - in our ptraced child list | ||
| 776 | * | ||
| 777 | * Search them and reparent children. | ||
| 778 | */ | ||
| 779 | list_for_each_entry_safe(p, n, &father->children, sibling) { | 819 | list_for_each_entry_safe(p, n, &father->children, sibling) { |
| 780 | int ptrace; | ||
| 781 | |||
| 782 | ptrace = p->ptrace; | ||
| 783 | |||
| 784 | /* if father isn't the real parent, then ptrace must be enabled */ | ||
| 785 | BUG_ON(father != p->real_parent && !ptrace); | ||
| 786 | |||
| 787 | if (father == p->real_parent) { | ||
| 788 | /* reparent with a reaper, real father it's us */ | ||
| 789 | p->real_parent = reaper; | ||
| 790 | reparent_thread(p, father, 0); | ||
| 791 | } else { | ||
| 792 | /* reparent ptraced task to its real parent */ | ||
| 793 | __ptrace_unlink (p); | ||
| 794 | if (p->exit_state == EXIT_ZOMBIE && !task_detached(p) && | ||
| 795 | thread_group_empty(p)) | ||
| 796 | do_notify_parent(p, p->exit_signal); | ||
| 797 | } | ||
| 798 | |||
| 799 | /* | ||
| 800 | * if the ptraced child is a detached zombie we must collect | ||
| 801 | * it before we exit, or it will remain zombie forever since | ||
| 802 | * we prevented it from self-reap itself while it was being | ||
| 803 | * traced by us, to be able to see it in wait4. | ||
| 804 | */ | ||
| 805 | if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && task_detached(p))) | ||
| 806 | list_add(&p->ptrace_list, &ptrace_dead); | ||
| 807 | } | ||
| 808 | |||
| 809 | list_for_each_entry_safe(p, n, &father->ptrace_children, ptrace_list) { | ||
| 810 | p->real_parent = reaper; | 820 | p->real_parent = reaper; |
| 811 | reparent_thread(p, father, 1); | 821 | if (p->parent == father) { |
| 822 | BUG_ON(p->ptrace); | ||
| 823 | p->parent = p->real_parent; | ||
| 824 | } | ||
| 825 | reparent_thread(p, father); | ||
| 812 | } | 826 | } |
| 813 | 827 | ||
| 814 | write_unlock_irq(&tasklist_lock); | 828 | write_unlock_irq(&tasklist_lock); |
| 815 | BUG_ON(!list_empty(&father->children)); | 829 | BUG_ON(!list_empty(&father->children)); |
| 816 | BUG_ON(!list_empty(&father->ptrace_children)); | ||
| 817 | |||
| 818 | list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_list) { | ||
| 819 | list_del_init(&p->ptrace_list); | ||
| 820 | release_task(p); | ||
| 821 | } | ||
| 822 | 830 | ||
| 831 | ptrace_exit_finish(father, &ptrace_dead); | ||
| 823 | } | 832 | } |
| 824 | 833 | ||
| 825 | /* | 834 | /* |
| @@ -1180,13 +1189,6 @@ static int eligible_child(enum pid_type type, struct pid *pid, int options, | |||
| 1180 | return 0; | 1189 | return 0; |
| 1181 | } | 1190 | } |
| 1182 | 1191 | ||
| 1183 | /* | ||
| 1184 | * Do not consider detached threads that are | ||
| 1185 | * not ptraced: | ||
| 1186 | */ | ||
| 1187 | if (task_detached(p) && !p->ptrace) | ||
| 1188 | return 0; | ||
| 1189 | |||
| 1190 | /* Wait for all children (clone and not) if __WALL is set; | 1192 | /* Wait for all children (clone and not) if __WALL is set; |
| 1191 | * otherwise, wait for clone children *only* if __WCLONE is | 1193 | * otherwise, wait for clone children *only* if __WCLONE is |
| 1192 | * set; otherwise, wait for non-clone children *only*. (Note: | 1194 | * set; otherwise, wait for non-clone children *only*. (Note: |
| @@ -1399,7 +1401,7 @@ static int wait_task_zombie(struct task_struct *p, int options, | |||
| 1399 | * the lock and this task is uninteresting. If we return nonzero, we have | 1401 | * the lock and this task is uninteresting. If we return nonzero, we have |
| 1400 | * released the lock and the system call should return. | 1402 | * released the lock and the system call should return. |
| 1401 | */ | 1403 | */ |
| 1402 | static int wait_task_stopped(struct task_struct *p, | 1404 | static int wait_task_stopped(int ptrace, struct task_struct *p, |
| 1403 | int options, struct siginfo __user *infop, | 1405 | int options, struct siginfo __user *infop, |
| 1404 | int __user *stat_addr, struct rusage __user *ru) | 1406 | int __user *stat_addr, struct rusage __user *ru) |
| 1405 | { | 1407 | { |
| @@ -1407,7 +1409,7 @@ static int wait_task_stopped(struct task_struct *p, | |||
| 1407 | uid_t uid = 0; /* unneeded, required by compiler */ | 1409 | uid_t uid = 0; /* unneeded, required by compiler */ |
| 1408 | pid_t pid; | 1410 | pid_t pid; |
| 1409 | 1411 | ||
| 1410 | if (!(p->ptrace & PT_PTRACED) && !(options & WUNTRACED)) | 1412 | if (!(options & WUNTRACED)) |
| 1411 | return 0; | 1413 | return 0; |
| 1412 | 1414 | ||
| 1413 | exit_code = 0; | 1415 | exit_code = 0; |
| @@ -1416,7 +1418,7 @@ static int wait_task_stopped(struct task_struct *p, | |||
| 1416 | if (unlikely(!task_is_stopped_or_traced(p))) | 1418 | if (unlikely(!task_is_stopped_or_traced(p))) |
| 1417 | goto unlock_sig; | 1419 | goto unlock_sig; |
| 1418 | 1420 | ||
| 1419 | if (!(p->ptrace & PT_PTRACED) && p->signal->group_stop_count > 0) | 1421 | if (!ptrace && p->signal->group_stop_count > 0) |
| 1420 | /* | 1422 | /* |
| 1421 | * A group stop is in progress and this is the group leader. | 1423 | * A group stop is in progress and this is the group leader. |
| 1422 | * We won't report until all threads have stopped. | 1424 | * We won't report until all threads have stopped. |
| @@ -1445,7 +1447,7 @@ unlock_sig: | |||
| 1445 | */ | 1447 | */ |
| 1446 | get_task_struct(p); | 1448 | get_task_struct(p); |
| 1447 | pid = task_pid_vnr(p); | 1449 | pid = task_pid_vnr(p); |
| 1448 | why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED; | 1450 | why = ptrace ? CLD_TRAPPED : CLD_STOPPED; |
| 1449 | read_unlock(&tasklist_lock); | 1451 | read_unlock(&tasklist_lock); |
| 1450 | 1452 | ||
| 1451 | if (unlikely(options & WNOWAIT)) | 1453 | if (unlikely(options & WNOWAIT)) |
| @@ -1536,7 +1538,7 @@ static int wait_task_continued(struct task_struct *p, int options, | |||
| 1536 | * Returns zero if the search for a child should continue; | 1538 | * Returns zero if the search for a child should continue; |
| 1537 | * then *@notask_error is 0 if @p is an eligible child, or still -ECHILD. | 1539 | * then *@notask_error is 0 if @p is an eligible child, or still -ECHILD. |
| 1538 | */ | 1540 | */ |
| 1539 | static int wait_consider_task(struct task_struct *parent, | 1541 | static int wait_consider_task(struct task_struct *parent, int ptrace, |
| 1540 | struct task_struct *p, int *notask_error, | 1542 | struct task_struct *p, int *notask_error, |
| 1541 | enum pid_type type, struct pid *pid, int options, | 1543 | enum pid_type type, struct pid *pid, int options, |
| 1542 | struct siginfo __user *infop, | 1544 | struct siginfo __user *infop, |
| @@ -1546,6 +1548,15 @@ static int wait_consider_task(struct task_struct *parent, | |||
| 1546 | if (ret <= 0) | 1548 | if (ret <= 0) |
| 1547 | return ret; | 1549 | return ret; |
| 1548 | 1550 | ||
| 1551 | if (likely(!ptrace) && unlikely(p->ptrace)) { | ||
| 1552 | /* | ||
| 1553 | * This child is hidden by ptrace. | ||
| 1554 | * We aren't allowed to see it now, but eventually we will. | ||
| 1555 | */ | ||
| 1556 | *notask_error = 0; | ||
| 1557 | return 0; | ||
| 1558 | } | ||
| 1559 | |||
| 1549 | if (p->exit_state == EXIT_DEAD) | 1560 | if (p->exit_state == EXIT_DEAD) |
| 1550 | return 0; | 1561 | return 0; |
| 1551 | 1562 | ||
| @@ -1562,7 +1573,8 @@ static int wait_consider_task(struct task_struct *parent, | |||
| 1562 | *notask_error = 0; | 1573 | *notask_error = 0; |
| 1563 | 1574 | ||
| 1564 | if (task_is_stopped_or_traced(p)) | 1575 | if (task_is_stopped_or_traced(p)) |
| 1565 | return wait_task_stopped(p, options, infop, stat_addr, ru); | 1576 | return wait_task_stopped(ptrace, p, options, |
| 1577 | infop, stat_addr, ru); | ||
| 1566 | 1578 | ||
| 1567 | return wait_task_continued(p, options, infop, stat_addr, ru); | 1579 | return wait_task_continued(p, options, infop, stat_addr, ru); |
| 1568 | } | 1580 | } |
| @@ -1583,11 +1595,16 @@ static int do_wait_thread(struct task_struct *tsk, int *notask_error, | |||
| 1583 | struct task_struct *p; | 1595 | struct task_struct *p; |
| 1584 | 1596 | ||
| 1585 | list_for_each_entry(p, &tsk->children, sibling) { | 1597 | list_for_each_entry(p, &tsk->children, sibling) { |
| 1586 | int ret = wait_consider_task(tsk, p, notask_error, | 1598 | /* |
| 1587 | type, pid, options, | 1599 | * Do not consider detached threads. |
| 1588 | infop, stat_addr, ru); | 1600 | */ |
| 1589 | if (ret) | 1601 | if (!task_detached(p)) { |
| 1590 | return ret; | 1602 | int ret = wait_consider_task(tsk, 0, p, notask_error, |
| 1603 | type, pid, options, | ||
| 1604 | infop, stat_addr, ru); | ||
| 1605 | if (ret) | ||
| 1606 | return ret; | ||
| 1607 | } | ||
| 1591 | } | 1608 | } |
| 1592 | 1609 | ||
| 1593 | return 0; | 1610 | return 0; |
| @@ -1601,21 +1618,16 @@ static int ptrace_do_wait(struct task_struct *tsk, int *notask_error, | |||
| 1601 | struct task_struct *p; | 1618 | struct task_struct *p; |
| 1602 | 1619 | ||
| 1603 | /* | 1620 | /* |
| 1604 | * If we never saw an eligile child, check for children stolen by | 1621 | * Traditionally we see ptrace'd stopped tasks regardless of options. |
| 1605 | * ptrace. We don't leave -ECHILD in *@notask_error if there are any, | ||
| 1606 | * because we will eventually be allowed to wait for them again. | ||
| 1607 | */ | 1622 | */ |
| 1608 | if (!*notask_error) | 1623 | options |= WUNTRACED; |
| 1609 | return 0; | ||
| 1610 | 1624 | ||
| 1611 | list_for_each_entry(p, &tsk->ptrace_children, ptrace_list) { | 1625 | list_for_each_entry(p, &tsk->ptraced, ptrace_entry) { |
| 1612 | int ret = eligible_child(type, pid, options, p); | 1626 | int ret = wait_consider_task(tsk, 1, p, notask_error, |
| 1613 | if (unlikely(ret < 0)) | 1627 | type, pid, options, |
| 1628 | infop, stat_addr, ru); | ||
| 1629 | if (ret) | ||
| 1614 | return ret; | 1630 | return ret; |
| 1615 | if (ret) { | ||
| 1616 | *notask_error = 0; | ||
| 1617 | return 0; | ||
| 1618 | } | ||
| 1619 | } | 1631 | } |
| 1620 | 1632 | ||
| 1621 | return 0; | 1633 | return 0; |
diff --git a/kernel/fork.c b/kernel/fork.c index 4bd2f516401f..adefc1131f27 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -1125,8 +1125,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1125 | */ | 1125 | */ |
| 1126 | p->group_leader = p; | 1126 | p->group_leader = p; |
| 1127 | INIT_LIST_HEAD(&p->thread_group); | 1127 | INIT_LIST_HEAD(&p->thread_group); |
| 1128 | INIT_LIST_HEAD(&p->ptrace_children); | 1128 | INIT_LIST_HEAD(&p->ptrace_entry); |
| 1129 | INIT_LIST_HEAD(&p->ptrace_list); | 1129 | INIT_LIST_HEAD(&p->ptraced); |
| 1130 | 1130 | ||
| 1131 | /* Now that the task is set up, run cgroup callbacks if | 1131 | /* Now that the task is set up, run cgroup callbacks if |
| 1132 | * necessary. We need to run them before the task is visible | 1132 | * necessary. We need to run them before the task is visible |
| @@ -1198,7 +1198,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1198 | } | 1198 | } |
| 1199 | 1199 | ||
| 1200 | if (likely(p->pid)) { | 1200 | if (likely(p->pid)) { |
| 1201 | add_parent(p); | 1201 | list_add_tail(&p->sibling, &p->real_parent->children); |
| 1202 | if (unlikely(p->ptrace & PT_PTRACED)) | 1202 | if (unlikely(p->ptrace & PT_PTRACED)) |
| 1203 | __ptrace_link(p, current->parent); | 1203 | __ptrace_link(p, current->parent); |
| 1204 | 1204 | ||
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; |
