TTY fixes for 5.10-rc7

Here are two tty core fixes for 5.10-rc7.
 
 They resolve some reported locking issues in the tty core.  While they
 have not been in a released linux-next yet, they have passed all of the
 0-day bot testing as well as the submitter's testing.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCX8zqVA8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yn6aACgiBghNkA6SJIjM1mcPCI/Nkvs3qoAn0g+l8Z1
 zATUgLS4xqAHnYXUfHpy
 =eB5C
 -----END PGP SIGNATURE-----

Merge tag 'tty-5.10-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty fixes from Greg KH:
 "Here are two tty core fixes for 5.10-rc7.

  They resolve some reported locking issues in the tty core. While they
  have not been in a released linux-next yet, they have passed all of
  the 0-day bot testing as well as the submitter's testing"

* tag 'tty-5.10-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: Fix ->session locking
  tty: Fix ->pgrp locking in tiocspgrp()
This commit is contained in:
Linus Torvalds 2020-12-06 11:43:50 -08:00
commit d49248eb25
3 changed files with 41 additions and 14 deletions

View file

@ -2897,10 +2897,14 @@ void __do_SAK(struct tty_struct *tty)
struct task_struct *g, *p; struct task_struct *g, *p;
struct pid *session; struct pid *session;
int i; int i;
unsigned long flags;
if (!tty) if (!tty)
return; 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); tty_ldisc_flush(tty);
@ -2932,6 +2936,7 @@ void __do_SAK(struct tty_struct *tty)
task_unlock(p); task_unlock(p);
} while_each_thread(g, p); } while_each_thread(g, p);
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
put_pid(session);
#endif #endif
} }

View file

@ -103,8 +103,8 @@ static void __proc_set_tty(struct tty_struct *tty)
put_pid(tty->session); put_pid(tty->session);
put_pid(tty->pgrp); put_pid(tty->pgrp);
tty->pgrp = get_pid(task_pgrp(current)); tty->pgrp = get_pid(task_pgrp(current));
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
tty->session = get_pid(task_session(current)); tty->session = get_pid(task_session(current));
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (current->signal->tty) { if (current->signal->tty) {
tty_debug(tty, "current tty %s not NULL!!\n", tty_debug(tty, "current tty %s not NULL!!\n",
current->signal->tty->name); current->signal->tty->name);
@ -293,20 +293,23 @@ void disassociate_ctty(int on_exit)
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
put_pid(current->signal->tty_old_pgrp); put_pid(current->signal->tty_old_pgrp);
current->signal->tty_old_pgrp = NULL; current->signal->tty_old_pgrp = NULL;
tty = tty_kref_get(current->signal->tty); tty = tty_kref_get(current->signal->tty);
spin_unlock_irq(&current->sighand->siglock);
if (tty) { if (tty) {
unsigned long flags; unsigned long flags;
tty_lock(tty);
spin_lock_irqsave(&tty->ctrl_lock, flags); spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(tty->session); put_pid(tty->session);
put_pid(tty->pgrp); put_pid(tty->pgrp);
tty->session = NULL; tty->session = NULL;
tty->pgrp = NULL; tty->pgrp = NULL;
spin_unlock_irqrestore(&tty->ctrl_lock, flags); spin_unlock_irqrestore(&tty->ctrl_lock, flags);
tty_unlock(tty);
tty_kref_put(tty); tty_kref_put(tty);
} }
spin_unlock_irq(&current->sighand->siglock);
/* Now clear signal->tty under the lock */ /* Now clear signal->tty under the lock */
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
session_clear_tty(task_session(current)); 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; return -ENOTTY;
if (retval) if (retval)
return 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)) if (get_user(pgrp_nr, p))
return -EFAULT; return -EFAULT;
if (pgrp_nr < 0) if (pgrp_nr < 0)
return -EINVAL; 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(); rcu_read_lock();
pgrp = find_vpid(pgrp_nr); pgrp = find_vpid(pgrp_nr);
retval = -ESRCH; 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)) if (session_of_pgrp(pgrp) != task_session(current))
goto out_unlock; goto out_unlock;
retval = 0; retval = 0;
spin_lock_irq(&tty->ctrl_lock);
put_pid(real_tty->pgrp); put_pid(real_tty->pgrp);
real_tty->pgrp = get_pid(pgrp); real_tty->pgrp = get_pid(pgrp);
spin_unlock_irq(&tty->ctrl_lock);
out_unlock: out_unlock:
rcu_read_unlock(); rcu_read_unlock();
out_unlock_ctrl:
spin_unlock_irq(&real_tty->ctrl_lock);
return retval; return retval;
} }
@ -511,20 +519,30 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
* *
* Obtain the session id of the tty. If there is no session * Obtain the session id of the tty. If there is no session
* return an error. * 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) 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 * (tty == real_tty) is a cheap way of
* testing if the tty is NOT a master pty. * testing if the tty is NOT a master pty.
*/ */
if (tty == real_tty && current->signal->tty != real_tty) if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY; return -ENOTTY;
spin_lock_irqsave(&real_tty->ctrl_lock, flags);
if (!real_tty->session) if (!real_tty->session)
return -ENOTTY; goto err;
return put_user(pid_vnr(real_tty->session), p); 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 */ struct termiox *termiox; /* May be NULL for unsupported */
char name[64]; char name[64];
struct pid *pgrp; /* Protected by ctrl lock */ 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; struct pid *session;
unsigned long flags; unsigned long flags;
int count; int count;