Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a5d3023 authored by Oren Laadan's avatar Oren Laadan Committed by Linus Torvalds
Browse files

[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: default avatarOren Laadan <orenl@cs.columbia.edu>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent fb86a35b
Loading
Loading
Loading
Loading
+3 −6
Original line number Original line Diff line number Diff line
@@ -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_expires = cputime_zero;
	sig->it_prof_incr = 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->leader = 0;	/* session leadership doesn't inherit */
	sig->tty_old_pgrp = 0;
	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_PID, p->pid);
	attach_pid(p, PIDTYPE_TGID, p->tgid);
	attach_pid(p, PIDTYPE_TGID, p->tgid);
	if (thread_group_leader(p)) {
	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_PGID, process_group(p));
		attach_pid(p, PIDTYPE_SID, p->signal->session);
		attach_pid(p, PIDTYPE_SID, p->signal->session);
		if (p->pid)
		if (p->pid)
			__get_cpu_var(process_counts)++;
			__get_cpu_var(process_counts)++;
	}
	}


	if (!current->signal->tty && p->signal->tty)
		p->signal->tty = NULL;

	nr_threads++;
	nr_threads++;
	total_forks++;
	total_forks++;
	write_unlock_irq(&tasklist_lock);
	write_unlock_irq(&tasklist_lock);