diff options
author | Oren Laadan <orenl@cs.columbia.edu> | 2006-01-08 01:03:51 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 20:14:00 -0800 |
commit | 9a5d3023e626a0baf86ac6b892c983b3db13f22b (patch) | |
tree | 41d1be6513fc3a5367414654eeaf11bbb12d4814 | |
parent | fb86a35b9ded8a7e53a432cbf28df603cdd4849c (diff) |
[PATCH] fork: fix race in setting child's pgrp and tty
In fork, child should recopy parent's pgrp/tty after it has tasklist_lock.
Otherwise following a setpgid() on the parent, *after* copy_signal(), the
child will own a stale pgrp (which may be reused); (eg. if copy_mm()
sleeps a long while due to memory pressure). Similar issue for the tty.
Signed-off-by: Oren Laadan <orenl@cs.columbia.edu>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | kernel/fork.c | 9 |
1 files changed, 3 insertions, 6 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 7992ee759d8..4bc0bd8ef17 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -811,9 +811,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts sig->it_prof_expires = cputime_zero; sig->it_prof_incr = cputime_zero; - sig->tty = current->signal->tty; - sig->pgrp = process_group(current); - sig->session = current->signal->session; sig->leader = 0; /* session leadership doesn't inherit */ sig->tty_old_pgrp = 0; @@ -1136,15 +1133,15 @@ static task_t *copy_process(unsigned long clone_flags, attach_pid(p, PIDTYPE_PID, p->pid); attach_pid(p, PIDTYPE_TGID, p->tgid); if (thread_group_leader(p)) { + p->signal->tty = current->signal->tty; + p->signal->pgrp = process_group(current); + p->signal->session = current->signal->session; attach_pid(p, PIDTYPE_PGID, process_group(p)); attach_pid(p, PIDTYPE_SID, p->signal->session); if (p->pid) __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); |