Merge "tty: Fix ->session locking"

This commit is contained in:
qctecmdr 2021-10-18 13:18:35 -07:00 committed by Gerrit - the friendly Code Review server
commit ca9eeb47db
3 changed files with 41 additions and 14 deletions

View file

@ -2751,10 +2751,14 @@ void __do_SAK(struct tty_struct *tty)
struct task_struct *g, *p;
struct pid *session;
int i;
unsigned long flags;
if (!tty)
return;
session = tty->session;
spin_lock_irqsave(&tty->ctrl_lock, flags);
session = get_pid(tty->session);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
tty_ldisc_flush(tty);
@ -2786,6 +2790,7 @@ void __do_SAK(struct tty_struct *tty)
task_unlock(p);
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
put_pid(session);
#endif
}

View file

@ -103,8 +103,8 @@ static void __proc_set_tty(struct tty_struct *tty)
put_pid(tty->session);
put_pid(tty->pgrp);
tty->pgrp = get_pid(task_pgrp(current));
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
tty->session = get_pid(task_session(current));
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (current->signal->tty) {
tty_debug(tty, "current tty %s not NULL!!\n",
current->signal->tty->name);
@ -293,20 +293,23 @@ void disassociate_ctty(int on_exit)
spin_lock_irq(&current->sighand->siglock);
put_pid(current->signal->tty_old_pgrp);
current->signal->tty_old_pgrp = NULL;
tty = tty_kref_get(current->signal->tty);
spin_unlock_irq(&current->sighand->siglock);
if (tty) {
unsigned long flags;
tty_lock(tty);
spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(tty->session);
put_pid(tty->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
tty_unlock(tty);
tty_kref_put(tty);
}
spin_unlock_irq(&current->sighand->siglock);
/* Now clear signal->tty under the lock */
read_lock(&tasklist_lock);
session_clear_tty(task_session(current));
@ -477,14 +480,19 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
return -ENOTTY;
if (retval)
return retval;
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
(real_tty->session != task_session(current)))
return -ENOTTY;
if (get_user(pgrp_nr, p))
return -EFAULT;
if (pgrp_nr < 0)
return -EINVAL;
spin_lock_irq(&real_tty->ctrl_lock);
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
(real_tty->session != task_session(current))) {
retval = -ENOTTY;
goto out_unlock_ctrl;
}
rcu_read_lock();
pgrp = find_vpid(pgrp_nr);
retval = -ESRCH;
@ -494,12 +502,12 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
if (session_of_pgrp(pgrp) != task_session(current))
goto out_unlock;
retval = 0;
spin_lock_irq(&real_tty->ctrl_lock);
put_pid(real_tty->pgrp);
real_tty->pgrp = get_pid(pgrp);
spin_unlock_irq(&real_tty->ctrl_lock);
out_unlock:
rcu_read_unlock();
out_unlock_ctrl:
spin_unlock_irq(&real_tty->ctrl_lock);
return retval;
}
@ -511,20 +519,30 @@ out_unlock:
*
* Obtain the session id of the tty. If there is no session
* return an error.
*
* Locking: none. Reference to current->signal->tty is safe.
*/
static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
unsigned long flags;
pid_t sid;
/*
* (tty == real_tty) is a cheap way of
* testing if the tty is NOT a master pty.
*/
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
spin_lock_irqsave(&real_tty->ctrl_lock, flags);
if (!real_tty->session)
return -ENOTTY;
return put_user(pid_vnr(real_tty->session), p);
goto err;
sid = pid_vnr(real_tty->session);
spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
return put_user(sid, p);
err:
spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
return -ENOTTY;
}
/*

View file

@ -306,6 +306,10 @@ struct tty_struct {
struct termiox *termiox; /* May be NULL for unsupported */
char name[64];
struct pid *pgrp; /* Protected by ctrl lock */
/*
* Writes protected by both ctrl lock and legacy mutex, readers must use
* at least one of them.
*/
struct pid *session;
unsigned long flags;
int count;