diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-07-03 18:08:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 19:08:03 -0400 |
commit | 8190773985141f063e1d6dc10200527c655abfb5 (patch) | |
tree | 5c148834f047748dfa2ce3500236b89656976567 | |
parent | 80628ca06c5d42929de6bc22c0a41589a834d151 (diff) |
kernel/fork.c:copy_process(): don't add the uninitialized child to thread/task/pid lists
copy_process() adds the new child to thread_group/init_task.tasks list and
then does attach_pid(child, PIDTYPE_PID). This means that the lockless
next_thread() or next_task() can see this thread with the wrong pid. Say,
"ls /proc/pid/task" can list the same inode twice.
We could move attach_pid(child, PIDTYPE_PID) up, but in this case
find_task_by_vpid() can find the new thread before it was fully
initialized.
And this is already true for PIDTYPE_PGID/PIDTYPE_SID, With this patch
copy_process() initializes child->pids[*].pid first, then calls
attach_pid() to insert the task into the pid->tasks list.
attach_pid() no longer need the "struct pid*" argument, it is always
called after pid_link->pid was already set.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Sergey Dyasly <dserrg@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/pid.h | 6 | ||||
-rw-r--r-- | kernel/fork.c | 16 | ||||
-rw-r--r-- | kernel/pid.c | 12 |
3 files changed, 19 insertions, 15 deletions
diff --git a/include/linux/pid.h b/include/linux/pid.h index a089a3c447fc..23705a53abba 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h | |||
@@ -86,11 +86,9 @@ extern struct task_struct *get_pid_task(struct pid *pid, enum pid_type); | |||
86 | extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); | 86 | extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); |
87 | 87 | ||
88 | /* | 88 | /* |
89 | * attach_pid() and detach_pid() must be called with the tasklist_lock | 89 | * these helpers must be called with the tasklist_lock write-held. |
90 | * write-held. | ||
91 | */ | 90 | */ |
92 | extern void attach_pid(struct task_struct *task, enum pid_type type, | 91 | extern void attach_pid(struct task_struct *task, enum pid_type); |
93 | struct pid *pid); | ||
94 | extern void detach_pid(struct task_struct *task, enum pid_type); | 92 | extern void detach_pid(struct task_struct *task, enum pid_type); |
95 | extern void change_pid(struct task_struct *task, enum pid_type, | 93 | extern void change_pid(struct task_struct *task, enum pid_type, |
96 | struct pid *pid); | 94 | struct pid *pid); |
diff --git a/kernel/fork.c b/kernel/fork.c index 417cb864e20c..7d6962fb6156 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1121,6 +1121,12 @@ static void posix_cpu_timers_init(struct task_struct *tsk) | |||
1121 | INIT_LIST_HEAD(&tsk->cpu_timers[2]); | 1121 | INIT_LIST_HEAD(&tsk->cpu_timers[2]); |
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | static inline void | ||
1125 | init_task_pid(struct task_struct *task, enum pid_type type, struct pid *pid) | ||
1126 | { | ||
1127 | task->pids[type].pid = pid; | ||
1128 | } | ||
1129 | |||
1124 | /* | 1130 | /* |
1125 | * This creates a new process as a copy of the old one, | 1131 | * This creates a new process as a copy of the old one, |
1126 | * but does not actually start it yet. | 1132 | * but does not actually start it yet. |
@@ -1449,7 +1455,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1449 | if (likely(p->pid)) { | 1455 | if (likely(p->pid)) { |
1450 | ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace); | 1456 | ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace); |
1451 | 1457 | ||
1458 | init_task_pid(p, PIDTYPE_PID, pid); | ||
1452 | if (thread_group_leader(p)) { | 1459 | if (thread_group_leader(p)) { |
1460 | init_task_pid(p, PIDTYPE_PGID, task_pgrp(current)); | ||
1461 | init_task_pid(p, PIDTYPE_SID, task_session(current)); | ||
1462 | |||
1453 | if (is_child_reaper(pid)) { | 1463 | if (is_child_reaper(pid)) { |
1454 | ns_of_pid(pid)->child_reaper = p; | 1464 | ns_of_pid(pid)->child_reaper = p; |
1455 | p->signal->flags |= SIGNAL_UNKILLABLE; | 1465 | p->signal->flags |= SIGNAL_UNKILLABLE; |
@@ -1457,10 +1467,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1457 | 1467 | ||
1458 | p->signal->leader_pid = pid; | 1468 | p->signal->leader_pid = pid; |
1459 | p->signal->tty = tty_kref_get(current->signal->tty); | 1469 | p->signal->tty = tty_kref_get(current->signal->tty); |
1460 | attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); | ||
1461 | attach_pid(p, PIDTYPE_SID, task_session(current)); | ||
1462 | list_add_tail(&p->sibling, &p->real_parent->children); | 1470 | list_add_tail(&p->sibling, &p->real_parent->children); |
1463 | list_add_tail_rcu(&p->tasks, &init_task.tasks); | 1471 | list_add_tail_rcu(&p->tasks, &init_task.tasks); |
1472 | attach_pid(p, PIDTYPE_PGID); | ||
1473 | attach_pid(p, PIDTYPE_SID); | ||
1464 | __this_cpu_inc(process_counts); | 1474 | __this_cpu_inc(process_counts); |
1465 | } else { | 1475 | } else { |
1466 | current->signal->nr_threads++; | 1476 | current->signal->nr_threads++; |
@@ -1470,7 +1480,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1470 | list_add_tail_rcu(&p->thread_group, | 1480 | list_add_tail_rcu(&p->thread_group, |
1471 | &p->group_leader->thread_group); | 1481 | &p->group_leader->thread_group); |
1472 | } | 1482 | } |
1473 | attach_pid(p, PIDTYPE_PID, pid); | 1483 | attach_pid(p, PIDTYPE_PID); |
1474 | nr_threads++; | 1484 | nr_threads++; |
1475 | } | 1485 | } |
1476 | 1486 | ||
diff --git a/kernel/pid.c b/kernel/pid.c index 0db3e791a06d..61980cefb1f5 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -373,14 +373,10 @@ EXPORT_SYMBOL_GPL(find_vpid); | |||
373 | /* | 373 | /* |
374 | * attach_pid() must be called with the tasklist_lock write-held. | 374 | * attach_pid() must be called with the tasklist_lock write-held. |
375 | */ | 375 | */ |
376 | void attach_pid(struct task_struct *task, enum pid_type type, | 376 | void attach_pid(struct task_struct *task, enum pid_type type) |
377 | struct pid *pid) | ||
378 | { | 377 | { |
379 | struct pid_link *link; | 378 | struct pid_link *link = &task->pids[type]; |
380 | 379 | hlist_add_head_rcu(&link->node, &link->pid->tasks[type]); | |
381 | link = &task->pids[type]; | ||
382 | link->pid = pid; | ||
383 | hlist_add_head_rcu(&link->node, &pid->tasks[type]); | ||
384 | } | 380 | } |
385 | 381 | ||
386 | static void __change_pid(struct task_struct *task, enum pid_type type, | 382 | static void __change_pid(struct task_struct *task, enum pid_type type, |
@@ -412,7 +408,7 @@ void change_pid(struct task_struct *task, enum pid_type type, | |||
412 | struct pid *pid) | 408 | struct pid *pid) |
413 | { | 409 | { |
414 | __change_pid(task, type, pid); | 410 | __change_pid(task, type, pid); |
415 | attach_pid(task, type, pid); | 411 | attach_pid(task, type); |
416 | } | 412 | } |
417 | 413 | ||
418 | /* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */ | 414 | /* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */ |