Commit f91e2590 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman

tty: Signal foreground group processes in hangup

When the session leader is exiting, signal the foreground group
processes as part of the hangup sequence, instead of after the
hangup is complete. This prepares for hanging up the
line discipline _after_ signalling processes which
may be blocking on ldisc i/o.

Parameterize __tty_hangup() to distinguish between when the
session leader is exiting and all other hangups; signal the
foreground group after signalling the session leader and its
process group, which preserves the original signal order.
Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Acked-by: default avatarJiri Slaby <jslaby@suse.cz>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent bc30c3b2
...@@ -534,18 +534,21 @@ EXPORT_SYMBOL_GPL(tty_wakeup); ...@@ -534,18 +534,21 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
/** /**
* tty_signal_session_leader - sends SIGHUP to session leader * tty_signal_session_leader - sends SIGHUP to session leader
* @tty controlling tty
* @exit_session if non-zero, signal all foreground group processes
* *
* Send SIGHUP and SIGCONT to the session leader and its * Send SIGHUP and SIGCONT to the session leader and its process group.
* process group. * Optionally, signal all processes in the foreground process group.
* *
* Returns the number of processes in the session with this tty * Returns the number of processes in the session with this tty
* as their controlling terminal. This value is used to drop * as their controlling terminal. This value is used to drop
* tty references for those processes. * tty references for those processes.
*/ */
static int tty_signal_session_leader(struct tty_struct *tty) static int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
{ {
struct task_struct *p; struct task_struct *p;
int refs = 0; int refs = 0;
struct pid *tty_pgrp = NULL;
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
if (tty->session) { if (tty->session) {
...@@ -565,6 +568,7 @@ static int tty_signal_session_leader(struct tty_struct *tty) ...@@ -565,6 +568,7 @@ static int tty_signal_session_leader(struct tty_struct *tty)
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
put_pid(p->signal->tty_old_pgrp); /* A noop */ put_pid(p->signal->tty_old_pgrp); /* A noop */
spin_lock(&tty->ctrl_lock); spin_lock(&tty->ctrl_lock);
tty_pgrp = get_pid(tty->pgrp);
if (tty->pgrp) if (tty->pgrp)
p->signal->tty_old_pgrp = get_pid(tty->pgrp); p->signal->tty_old_pgrp = get_pid(tty->pgrp);
spin_unlock(&tty->ctrl_lock); spin_unlock(&tty->ctrl_lock);
...@@ -573,6 +577,12 @@ static int tty_signal_session_leader(struct tty_struct *tty) ...@@ -573,6 +577,12 @@ static int tty_signal_session_leader(struct tty_struct *tty)
} }
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
if (tty_pgrp) {
if (exit_session)
kill_pgrp(tty_pgrp, SIGHUP, exit_session);
put_pid(tty_pgrp);
}
return refs; return refs;
} }
...@@ -598,7 +608,7 @@ static int tty_signal_session_leader(struct tty_struct *tty) ...@@ -598,7 +608,7 @@ static int tty_signal_session_leader(struct tty_struct *tty)
* tasklist_lock to walk task list for hangup event * tasklist_lock to walk task list for hangup event
* ->siglock to protect ->signal/->sighand * ->siglock to protect ->signal/->sighand
*/ */
static void __tty_hangup(struct tty_struct *tty) static void __tty_hangup(struct tty_struct *tty, int exit_session)
{ {
struct file *cons_filp = NULL; struct file *cons_filp = NULL;
struct file *filp, *f = NULL; struct file *filp, *f = NULL;
...@@ -647,7 +657,7 @@ static void __tty_hangup(struct tty_struct *tty) ...@@ -647,7 +657,7 @@ static void __tty_hangup(struct tty_struct *tty)
*/ */
tty_ldisc_hangup(tty); tty_ldisc_hangup(tty);
refs = tty_signal_session_leader(tty); refs = tty_signal_session_leader(tty, exit_session);
/* Account for the p->signal references we killed */ /* Account for the p->signal references we killed */
while (refs--) while (refs--)
tty_kref_put(tty); tty_kref_put(tty);
...@@ -696,7 +706,7 @@ static void do_tty_hangup(struct work_struct *work) ...@@ -696,7 +706,7 @@ static void do_tty_hangup(struct work_struct *work)
struct tty_struct *tty = struct tty_struct *tty =
container_of(work, struct tty_struct, hangup_work); container_of(work, struct tty_struct, hangup_work);
__tty_hangup(tty); __tty_hangup(tty, 0);
} }
/** /**
...@@ -734,7 +744,7 @@ void tty_vhangup(struct tty_struct *tty) ...@@ -734,7 +744,7 @@ void tty_vhangup(struct tty_struct *tty)
printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
#endif #endif
__tty_hangup(tty); __tty_hangup(tty, 0);
} }
EXPORT_SYMBOL(tty_vhangup); EXPORT_SYMBOL(tty_vhangup);
...@@ -757,6 +767,27 @@ void tty_vhangup_self(void) ...@@ -757,6 +767,27 @@ void tty_vhangup_self(void)
} }
} }
/**
* tty_vhangup_session - hangup session leader exit
* @tty: tty to hangup
*
* The session leader is exiting and hanging up its controlling terminal.
* Every process in the foreground process group is signalled SIGHUP.
*
* We do this synchronously so that when the syscall returns the process
* is complete. That guarantee is necessary for security reasons.
*/
void tty_vhangup_session(struct tty_struct *tty)
{
#ifdef TTY_DEBUG_HANGUP
char buf[64];
printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf));
#endif
__tty_hangup(tty, 1);
}
/** /**
* tty_hung_up_p - was tty hung up * tty_hung_up_p - was tty hung up
* @filp: file pointer of tty * @filp: file pointer of tty
...@@ -814,18 +845,18 @@ void disassociate_ctty(int on_exit) ...@@ -814,18 +845,18 @@ void disassociate_ctty(int on_exit)
tty = get_current_tty(); tty = get_current_tty();
if (tty) { if (tty) {
struct pid *tty_pgrp = get_pid(tty->pgrp); if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) {
if (on_exit) { tty_vhangup_session(tty);
if (tty->driver->type != TTY_DRIVER_TYPE_PTY) } else {
tty_vhangup(tty); struct pid *tty_pgrp = tty_get_pgrp(tty);
}
tty_kref_put(tty);
if (tty_pgrp) { if (tty_pgrp) {
kill_pgrp(tty_pgrp, SIGHUP, on_exit); kill_pgrp(tty_pgrp, SIGHUP, on_exit);
if (!on_exit)
kill_pgrp(tty_pgrp, SIGCONT, on_exit); kill_pgrp(tty_pgrp, SIGCONT, on_exit);
put_pid(tty_pgrp); put_pid(tty_pgrp);
} }
}
tty_kref_put(tty);
} else if (on_exit) { } else if (on_exit) {
struct pid *old_pgrp; struct pid *old_pgrp;
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment