mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
tty: Fix multiple races when setting the controlling terminal
Claim a read lock on the tasklist_lock while setting the controlling terminal for the session leader. This fixes multiple races: 1. task_pgrp() and task_session() cannot be safely dereferenced, such as passing to get_pid(), without holding either rcu_read_lock() or tasklist_lock 2. setsid() unwisely allows any thread in the thread group to make the thread group leader the session leader; this makes the unlocked reads of ->signal->leader and signal->tty potentially unordered, stale or even have spurious values. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ae28fa7216
commit
2c411c1102
@ -502,8 +502,15 @@ void proc_clear_tty(struct task_struct *p)
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/* Called under the sighand lock */
|
||||
|
||||
/**
|
||||
* proc_set_tty - set the controlling terminal
|
||||
*
|
||||
* Only callable by the session leader and only if it does not already have
|
||||
* a controlling terminal.
|
||||
*
|
||||
* Caller must hold: a readlock on tasklist_lock
|
||||
* sighand lock
|
||||
*/
|
||||
static void __proc_set_tty(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -2150,6 +2157,7 @@ static int tty_open(struct inode *inode, struct file *filp)
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock(tty);
|
||||
read_lock(&tasklist_lock);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
if (!noctty &&
|
||||
current->signal->leader &&
|
||||
@ -2157,6 +2165,7 @@ static int tty_open(struct inode *inode, struct file *filp)
|
||||
tty->session == NULL)
|
||||
__proc_set_tty(tty);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
read_unlock(&tasklist_lock);
|
||||
tty_unlock(tty);
|
||||
mutex_unlock(&tty_mutex);
|
||||
return 0;
|
||||
@ -2447,10 +2456,13 @@ static int fionbio(struct file *file, int __user *p)
|
||||
static int tiocsctty(struct tty_struct *tty, int arg)
|
||||
{
|
||||
int ret = 0;
|
||||
if (current->signal->leader && (task_session(current) == tty->session))
|
||||
return ret;
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
read_lock(&tasklist_lock);
|
||||
|
||||
if (current->signal->leader && (task_session(current) == tty->session))
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* The process must be a session leader and
|
||||
* not have a controlling tty already.
|
||||
@ -2469,9 +2481,7 @@ static int tiocsctty(struct tty_struct *tty, int arg)
|
||||
/*
|
||||
* Steal it away
|
||||
*/
|
||||
read_lock(&tasklist_lock);
|
||||
session_clear_tty(tty->session);
|
||||
read_unlock(&tasklist_lock);
|
||||
} else {
|
||||
ret = -EPERM;
|
||||
goto unlock;
|
||||
@ -2479,6 +2489,7 @@ static int tiocsctty(struct tty_struct *tty, int arg)
|
||||
}
|
||||
proc_set_tty(tty);
|
||||
unlock:
|
||||
read_unlock(&tasklist_lock);
|
||||
mutex_unlock(&tty_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user