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

tty: Convert termios_mutex to termios_rwsem

termios is commonly accessed unsafely (especially by N_TTY)
because the existing mutex forces exclusive access.
Convert existing usage.
Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a2f73be8
...@@ -123,14 +123,14 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed) ...@@ -123,14 +123,14 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
tty = priv->tty; tty = priv->tty;
mutex_lock(&tty->termios_mutex); down_write(&tty->termios_rwsem);
old_termios = tty->termios; old_termios = tty->termios;
cflag = tty->termios.c_cflag; cflag = tty->termios.c_cflag;
tty_encode_baud_rate(tty, speed, speed); tty_encode_baud_rate(tty, speed, speed);
if (tty->ops->set_termios) if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios); tty->ops->set_termios(tty, &old_termios);
priv->io.speed = speed; priv->io.speed = speed;
mutex_unlock(&tty->termios_mutex); up_write(&tty->termios_rwsem);
return 0; return 0;
} }
...@@ -280,7 +280,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) ...@@ -280,7 +280,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
struct ktermios old_termios; struct ktermios old_termios;
int cflag; int cflag;
mutex_lock(&tty->termios_mutex); down_write(&tty->termios_rwsem);
old_termios = tty->termios; old_termios = tty->termios;
cflag = tty->termios.c_cflag; cflag = tty->termios.c_cflag;
...@@ -292,7 +292,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) ...@@ -292,7 +292,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
tty->termios.c_cflag = cflag; tty->termios.c_cflag = cflag;
if (tty->ops->set_termios) if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios); tty->ops->set_termios(tty, &old_termios);
mutex_unlock(&tty->termios_mutex); up_write(&tty->termios_rwsem);
} }
/*****************************************************************/ /*****************************************************************/
......
...@@ -1539,7 +1539,7 @@ int is_ignored(int sig) ...@@ -1539,7 +1539,7 @@ int is_ignored(int sig)
* guaranteed that this function will not be re-entered or in progress * guaranteed that this function will not be re-entered or in progress
* when the ldisc is closed. * when the ldisc is closed.
* *
* Locking: Caller holds tty->termios_mutex * Locking: Caller holds tty->termios_rwsem
*/ */
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
......
...@@ -287,7 +287,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws) ...@@ -287,7 +287,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
struct tty_struct *pty = tty->link; struct tty_struct *pty = tty->link;
/* For a PTY we need to lock the tty side */ /* For a PTY we need to lock the tty side */
mutex_lock(&tty->termios_mutex); down_write(&tty->termios_rwsem);
if (!memcmp(ws, &tty->winsize, sizeof(*ws))) if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done; goto done;
...@@ -314,7 +314,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws) ...@@ -314,7 +314,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
tty->winsize = *ws; tty->winsize = *ws;
pty->winsize = *ws; /* Never used so will go away soon */ pty->winsize = *ws; /* Never used so will go away soon */
done: done:
mutex_unlock(&tty->termios_mutex); up_write(&tty->termios_rwsem);
return 0; return 0;
} }
......
...@@ -604,7 +604,7 @@ static int tty_signal_session_leader(struct tty_struct *tty, int exit_session) ...@@ -604,7 +604,7 @@ static int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
* redirect lock for undoing redirection * redirect lock for undoing redirection
* file list lock for manipulating list of ttys * file list lock for manipulating list of ttys
* tty_ldiscs_lock from called functions * tty_ldiscs_lock from called functions
* termios_mutex resetting termios data * termios_rwsem resetting termios data
* 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
*/ */
...@@ -2230,7 +2230,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) ...@@ -2230,7 +2230,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
* *
* Copies the kernel idea of the window size into the user buffer. * Copies the kernel idea of the window size into the user buffer.
* *
* Locking: tty->termios_mutex is taken to ensure the winsize data * Locking: tty->termios_rwsem is taken to ensure the winsize data
* is consistent. * is consistent.
*/ */
...@@ -2238,9 +2238,9 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) ...@@ -2238,9 +2238,9 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
{ {
int err; int err;
mutex_lock(&tty->termios_mutex); down_read(&tty->termios_rwsem);
err = copy_to_user(arg, &tty->winsize, sizeof(*arg)); err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
mutex_unlock(&tty->termios_mutex); up_read(&tty->termios_rwsem);
return err ? -EFAULT: 0; return err ? -EFAULT: 0;
} }
...@@ -2261,7 +2261,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws) ...@@ -2261,7 +2261,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
unsigned long flags; unsigned long flags;
/* Lock the tty */ /* Lock the tty */
mutex_lock(&tty->termios_mutex); down_write(&tty->termios_rwsem);
if (!memcmp(ws, &tty->winsize, sizeof(*ws))) if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done; goto done;
/* Get the PID values and reference them so we can /* Get the PID values and reference them so we can
...@@ -2276,7 +2276,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws) ...@@ -2276,7 +2276,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
tty->winsize = *ws; tty->winsize = *ws;
done: done:
mutex_unlock(&tty->termios_mutex); up_write(&tty->termios_rwsem);
return 0; return 0;
} }
EXPORT_SYMBOL(tty_do_resize); EXPORT_SYMBOL(tty_do_resize);
...@@ -3015,7 +3015,7 @@ void initialize_tty_struct(struct tty_struct *tty, ...@@ -3015,7 +3015,7 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->session = NULL; tty->session = NULL;
tty->pgrp = NULL; tty->pgrp = NULL;
mutex_init(&tty->legacy_mutex); mutex_init(&tty->legacy_mutex);
mutex_init(&tty->termios_mutex); init_rwsem(&tty->termios_rwsem);
init_ldsem(&tty->ldisc_sem); init_ldsem(&tty->ldisc_sem);
init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait); init_waitqueue_head(&tty->read_wait);
......
This diff is collapsed.
...@@ -415,14 +415,14 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); ...@@ -415,14 +415,14 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
* they are not on hot paths so a little discipline won't do * they are not on hot paths so a little discipline won't do
* any harm. * any harm.
* *
* Locking: takes termios_mutex * Locking: takes termios_rwsem
*/ */
static void tty_set_termios_ldisc(struct tty_struct *tty, int num) static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
{ {
mutex_lock(&tty->termios_mutex); down_write(&tty->termios_rwsem);
tty->termios.c_line = num; tty->termios.c_line = num;
mutex_unlock(&tty->termios_mutex); up_write(&tty->termios_rwsem);
} }
/** /**
...@@ -602,11 +602,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -602,11 +602,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
static void tty_reset_termios(struct tty_struct *tty) static void tty_reset_termios(struct tty_struct *tty)
{ {
mutex_lock(&tty->termios_mutex); down_write(&tty->termios_rwsem);
tty->termios = tty->driver->init_termios; tty->termios = tty->driver->init_termios;
tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
mutex_unlock(&tty->termios_mutex); up_write(&tty->termios_rwsem);
} }
......
...@@ -828,7 +828,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, ...@@ -828,7 +828,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
* If the caller passes a tty structure then update the termios winsize * If the caller passes a tty structure then update the termios winsize
* information and perform any necessary signal handling. * information and perform any necessary signal handling.
* *
* Caller must hold the console semaphore. Takes the termios mutex and * Caller must hold the console semaphore. Takes the termios rwsem and
* ctrl_lock of the tty IFF a tty is passed. * ctrl_lock of the tty IFF a tty is passed.
*/ */
...@@ -972,7 +972,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) ...@@ -972,7 +972,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
* the actual work. * the actual work.
* *
* Takes the console sem and the called methods then take the tty * Takes the console sem and the called methods then take the tty
* termios_mutex and the tty ctrl_lock in that order. * termios_rwsem and the tty ctrl_lock in that order.
*/ */
static int vt_resize(struct tty_struct *tty, struct winsize *ws) static int vt_resize(struct tty_struct *tty, struct winsize *ws)
{ {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/tty_flags.h> #include <linux/tty_flags.h>
#include <uapi/linux/tty.h> #include <uapi/linux/tty.h>
#include <linux/rwsem.h>
...@@ -243,9 +244,9 @@ struct tty_struct { ...@@ -243,9 +244,9 @@ struct tty_struct {
struct mutex atomic_write_lock; struct mutex atomic_write_lock;
struct mutex legacy_mutex; struct mutex legacy_mutex;
struct mutex termios_mutex; struct rw_semaphore termios_rwsem;
spinlock_t ctrl_lock; spinlock_t ctrl_lock;
/* Termios values are protected by the termios mutex */ /* Termios values are protected by the termios rwsem */
struct ktermios termios, termios_locked; struct ktermios termios, termios_locked;
struct termiox *termiox; /* May be NULL for unsupported */ struct termiox *termiox; /* May be NULL for unsupported */
char name[64]; char name[64];
...@@ -253,7 +254,7 @@ struct tty_struct { ...@@ -253,7 +254,7 @@ struct tty_struct {
struct pid *session; struct pid *session;
unsigned long flags; unsigned long flags;
int count; int count;
struct winsize winsize; /* termios mutex */ struct winsize winsize; /* termios rwsem */
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1; unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
unsigned char ctrl_status; /* ctrl_lock */ unsigned char ctrl_status; /* ctrl_lock */
unsigned int receive_room; /* Bytes free for queue */ unsigned int receive_room; /* Bytes free for queue */
......
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