diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-02-15 14:13:26 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-15 13:21:24 -0500 |
commit | dadac81b1b86196fcc48fb87620403c4a7174f06 (patch) | |
tree | fc19d44716915e55b237af3fb01a09f5be6d91c3 | |
parent | 3f17da699431ec48540beabc55c54d4b5e66c8e7 (diff) |
[PATCH] fix kill_proc_info() vs fork() theoretical race
copy_process:
attach_pid(p, PIDTYPE_PID, p->pid);
attach_pid(p, PIDTYPE_TGID, p->tgid);
What if kill_proc_info(p->pid) happens in between?
copy_process() holds current->sighand.siglock, so we are safe
in CLONE_THREAD case, because current->sighand == p->sighand.
Otherwise, p->sighand is unlocked, the new process is already
visible to the find_task_by_pid(), but have a copy of parent's
'struct pid' in ->pids[PIDTYPE_TGID].
This means that __group_complete_signal() may hang while doing
do ... while (next_thread() != p)
We can solve this problem if we reverse these 2 attach_pid()s:
attach_pid() does wmb()
group_send_sig_info() calls spin_lock(), which
provides a read barrier. // Yes ?
I don't think we can hit this race in practice, but still.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | kernel/fork.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 3683ce10f4a9..fbea12d7a943 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1173,8 +1173,6 @@ static task_t *copy_process(unsigned long clone_flags, | |||
1173 | if (unlikely(p->ptrace & PT_PTRACED)) | 1173 | if (unlikely(p->ptrace & PT_PTRACED)) |
1174 | __ptrace_link(p, current->parent); | 1174 | __ptrace_link(p, current->parent); |
1175 | 1175 | ||
1176 | attach_pid(p, PIDTYPE_PID, p->pid); | ||
1177 | attach_pid(p, PIDTYPE_TGID, p->tgid); | ||
1178 | if (thread_group_leader(p)) { | 1176 | if (thread_group_leader(p)) { |
1179 | p->signal->tty = current->signal->tty; | 1177 | p->signal->tty = current->signal->tty; |
1180 | p->signal->pgrp = process_group(current); | 1178 | p->signal->pgrp = process_group(current); |
@@ -1184,6 +1182,8 @@ static task_t *copy_process(unsigned long clone_flags, | |||
1184 | if (p->pid) | 1182 | if (p->pid) |
1185 | __get_cpu_var(process_counts)++; | 1183 | __get_cpu_var(process_counts)++; |
1186 | } | 1184 | } |
1185 | attach_pid(p, PIDTYPE_TGID, p->tgid); | ||
1186 | attach_pid(p, PIDTYPE_PID, p->pid); | ||
1187 | 1187 | ||
1188 | nr_threads++; | 1188 | nr_threads++; |
1189 | total_forks++; | 1189 | total_forks++; |