summaryrefslogtreecommitdiffstats
path: root/kernel/fork.c
diff options
context:
space:
mode:
authorJason Baron <jbaron@redhat.com>2005-09-09 13:02:01 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 13:57:31 -0700
commitb0d62e6d5b3318b6b722121d945afa295f7201b5 (patch)
tree9dfed36c97bcdbeaf1576b62752bfcafbfae808a /kernel/fork.c
parentf76baf9365bd66216bf0e0ebfc083e22eda6215b (diff)
downloadlinux-b0d62e6d5b3318b6b722121d945afa295f7201b5.tar.gz
linux-b0d62e6d5b3318b6b722121d945afa295f7201b5.tar.bz2
linux-b0d62e6d5b3318b6b722121d945afa295f7201b5.zip
[PATCH] fix disassociate_ctty vs. fork race
Race is as follows. Process A forks process B, both being part of the same session. Then, A calls disassociate_ctty while B forks C: A B ==== ==== fork() copy_signal() dissasociate_ctty() .... attach_pid(p, PIDTYPE_SID, p->signal->session); Now, C can have current->signal->tty pointing to a freed tty structure, as it hasn't yet been added to the session group (to have its controlling tty cleared on the diassociate_ctty() call). This has shown up as an oops but could be even more serious. I haven't tried to create a test case, but a customer has verified that the patch below resolves the issue, which was occuring quite frequently. I'll try and post the test case if i can. The patch simply checks for a NULL tty *after* it has been attached to the proper session group and clears it as necessary. Alternatively, we could simply do the tty assignment after the the process is added to the proper session group. Signed-off-by: Jason Baron <jbaron@redhat.com> Cc: Roland McGrath <roland@redhat.com> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index dfeadf466f18..b25802065031 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1116,6 +1116,9 @@ static task_t *copy_process(unsigned long clone_flags,
__get_cpu_var(process_counts)++;
}
+ if (!current->signal->tty && p->signal->tty)
+ p->signal->tty = NULL;
+
nr_threads++;
total_forks++;
write_unlock_irq(&tasklist_lock);