Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -123,14 +123,14 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)

	tty = priv->tty;

	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	old_termios = tty->termios;
	cflag = tty->termios.c_cflag;
	tty_encode_baud_rate(tty, speed, speed);
	if (tty->ops->set_termios)
		tty->ops->set_termios(tty, &old_termios);
	priv->io.speed = speed;
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);

	return 0;
}
@@ -280,7 +280,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
	struct ktermios old_termios;
	int cflag;

	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	old_termios = tty->termios;
	cflag = tty->termios.c_cflag;
	
@@ -292,7 +292,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
	tty->termios.c_cflag = cflag;
	if (tty->ops->set_termios)
		tty->ops->set_termios(tty, &old_termios);
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
}

/*****************************************************************/
+1 −1
Original line number Diff line number Diff line
@@ -1539,7 +1539,7 @@ int is_ignored(int sig)
 *	guaranteed that this function will not be re-entered or in progress
 *	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)
+2 −2
Original line number Diff line number Diff line
@@ -287,7 +287,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
	struct tty_struct *pty = tty->link;

	/* 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)))
		goto done;

@@ -314,7 +314,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
	tty->winsize = *ws;
	pty->winsize = *ws;	/* Never used so will go away soon */
done:
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
	return 0;
}

+7 −7
Original line number Diff line number Diff line
@@ -604,7 +604,7 @@ static int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
 *		  redirect lock for undoing redirection
 *		  file list lock for manipulating list of ttys
 *		  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
 *		    ->siglock to protect ->signal/->sighand
 */
@@ -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.
 *
 *	Locking: tty->termios_mutex is taken to ensure the winsize data
 *	Locking: tty->termios_rwsem is taken to ensure the winsize data
 *		is consistent.
 */

@@ -2238,9 +2238,9 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
{
	int err;

	mutex_lock(&tty->termios_mutex);
	down_read(&tty->termios_rwsem);
	err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
	mutex_unlock(&tty->termios_mutex);
	up_read(&tty->termios_rwsem);

	return err ? -EFAULT: 0;
}
@@ -2261,7 +2261,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
	unsigned long flags;

	/* Lock the tty */
	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
		goto done;
	/* 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)

	tty->winsize = *ws;
done:
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
	return 0;
}
EXPORT_SYMBOL(tty_do_resize);
@@ -3015,7 +3015,7 @@ void initialize_tty_struct(struct tty_struct *tty,
	tty->session = NULL;
	tty->pgrp = NULL;
	mutex_init(&tty->legacy_mutex);
	mutex_init(&tty->termios_mutex);
	init_rwsem(&tty->termios_rwsem);
	init_ldsem(&tty->ldisc_sem);
	init_waitqueue_head(&tty->write_wait);
	init_waitqueue_head(&tty->read_wait);
+45 −45
Original line number Diff line number Diff line
@@ -94,20 +94,20 @@ EXPORT_SYMBOL(tty_driver_flush_buffer);
 *	@tty: terminal
 *
 *	Indicate that a tty should stop transmitting data down the stack.
 *	Takes the termios mutex to protect against parallel throttle/unthrottle
 *	Takes the termios rwsem to protect against parallel throttle/unthrottle
 *	and also to ensure the driver can consistently reference its own
 *	termios data at this point when implementing software flow control.
 */

void tty_throttle(struct tty_struct *tty)
{
	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	/* check TTY_THROTTLED first so it indicates our state */
	if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
	    tty->ops->throttle)
		tty->ops->throttle(tty);
	tty->flow_change = 0;
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
}
EXPORT_SYMBOL(tty_throttle);

@@ -116,7 +116,7 @@ EXPORT_SYMBOL(tty_throttle);
 *	@tty: terminal
 *
 *	Indicate that a tty may continue transmitting data down the stack.
 *	Takes the termios mutex to protect against parallel throttle/unthrottle
 *	Takes the termios rwsem to protect against parallel throttle/unthrottle
 *	and also to ensure the driver can consistently reference its own
 *	termios data at this point when implementing software flow control.
 *
@@ -126,12 +126,12 @@ EXPORT_SYMBOL(tty_throttle);

void tty_unthrottle(struct tty_struct *tty)
{
	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
	    tty->ops->unthrottle)
		tty->ops->unthrottle(tty);
	tty->flow_change = 0;
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
}
EXPORT_SYMBOL(tty_unthrottle);

@@ -151,7 +151,7 @@ int tty_throttle_safe(struct tty_struct *tty)
{
	int ret = 0;

	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	if (!test_bit(TTY_THROTTLED, &tty->flags)) {
		if (tty->flow_change != TTY_THROTTLE_SAFE)
			ret = 1;
@@ -161,7 +161,7 @@ int tty_throttle_safe(struct tty_struct *tty)
				tty->ops->throttle(tty);
		}
	}
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);

	return ret;
}
@@ -182,7 +182,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
{
	int ret = 0;

	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	if (test_bit(TTY_THROTTLED, &tty->flags)) {
		if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
			ret = 1;
@@ -192,7 +192,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
				tty->ops->unthrottle(tty);
		}
	}
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);

	return ret;
}
@@ -468,7 +468,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
 *	@obad: output baud rate
 *
 *	Update the current termios data for the tty with the new speed
 *	settings. The caller must hold the termios_mutex for the tty in
 *	settings. The caller must hold the termios_rwsem for the tty in
 *	question.
 */

@@ -528,7 +528,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
 *	is a bit of layering violation here with n_tty in terms of the
 *	internal knowledge of this function.
 *
 *	Locking: termios_mutex
 *	Locking: termios_rwsem
 */

int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
@@ -544,7 +544,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)

	/* FIXME: we need to decide on some locking/ordering semantics
	   for the set_termios notification eventually */
	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	old_termios = tty->termios;
	tty->termios = *new_termios;
	unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
@@ -586,7 +586,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
			(ld->ops->set_termios)(tty, &old_termios);
		tty_ldisc_deref(ld);
	}
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
	return 0;
}
EXPORT_SYMBOL_GPL(tty_set_termios);
@@ -601,7 +601,7 @@ EXPORT_SYMBOL_GPL(tty_set_termios);
 *	functions before using tty_set_termios to do the actual changes.
 *
 *	Locking:
 *		Called functions take ldisc and termios_mutex locks
 *		Called functions take ldisc and termios_rwsem locks
 */

static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
@@ -613,9 +613,9 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
	if (retval)
		return retval;

	mutex_lock(&tty->termios_mutex);
	down_read(&tty->termios_rwsem);
	tmp_termios = tty->termios;
	mutex_unlock(&tty->termios_mutex);
	up_read(&tty->termios_rwsem);

	if (opt & TERMIOS_TERMIO) {
		if (user_termio_to_kernel_termios(&tmp_termios,
@@ -667,16 +667,16 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)

static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
{
	mutex_lock(&tty->termios_mutex);
	down_read(&tty->termios_rwsem);
	*kterm = tty->termios;
	mutex_unlock(&tty->termios_mutex);
	up_read(&tty->termios_rwsem);
}

static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
{
	mutex_lock(&tty->termios_mutex);
	down_read(&tty->termios_rwsem);
	*kterm = tty->termios_locked;
	mutex_unlock(&tty->termios_mutex);
	up_read(&tty->termios_rwsem);
}

static int get_termio(struct tty_struct *tty, struct termio __user *termio)
@@ -723,10 +723,10 @@ static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
			return -ERESTARTSYS;
	}

	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	if (tty->ops->set_termiox)
		tty->ops->set_termiox(tty, &tnew);
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
	return 0;
}

@@ -761,13 +761,13 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
{
	struct sgttyb tmp;

	mutex_lock(&tty->termios_mutex);
	down_read(&tty->termios_rwsem);
	tmp.sg_ispeed = tty->termios.c_ispeed;
	tmp.sg_ospeed = tty->termios.c_ospeed;
	tmp.sg_erase = tty->termios.c_cc[VERASE];
	tmp.sg_kill = tty->termios.c_cc[VKILL];
	tmp.sg_flags = get_sgflags(tty);
	mutex_unlock(&tty->termios_mutex);
	up_read(&tty->termios_rwsem);

	return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -806,7 +806,7 @@ static void set_sgflags(struct ktermios *termios, int flags)
 *	Updates a terminal from the legacy BSD style terminal information
 *	structure.
 *
 *	Locking: termios_mutex
 *	Locking: termios_rwsem
 */

static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
@@ -822,7 +822,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
	if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
		return -EFAULT;

	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	termios = tty->termios;
	termios.c_cc[VERASE] = tmp.sg_erase;
	termios.c_cc[VKILL] = tmp.sg_kill;
@@ -832,7 +832,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
	tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
						termios.c_ospeed);
#endif
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
	tty_set_termios(tty, &termios);
	return 0;
}
@@ -843,14 +843,14 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
{
	struct tchars tmp;

	mutex_lock(&tty->termios_mutex);
	down_read(&tty->termios_rwsem);
	tmp.t_intrc = tty->termios.c_cc[VINTR];
	tmp.t_quitc = tty->termios.c_cc[VQUIT];
	tmp.t_startc = tty->termios.c_cc[VSTART];
	tmp.t_stopc = tty->termios.c_cc[VSTOP];
	tmp.t_eofc = tty->termios.c_cc[VEOF];
	tmp.t_brkc = tty->termios.c_cc[VEOL2];	/* what is brkc anyway? */
	mutex_unlock(&tty->termios_mutex);
	up_read(&tty->termios_rwsem);
	return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}

@@ -860,14 +860,14 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)

	if (copy_from_user(&tmp, tchars, sizeof(tmp)))
		return -EFAULT;
	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	tty->termios.c_cc[VINTR] = tmp.t_intrc;
	tty->termios.c_cc[VQUIT] = tmp.t_quitc;
	tty->termios.c_cc[VSTART] = tmp.t_startc;
	tty->termios.c_cc[VSTOP] = tmp.t_stopc;
	tty->termios.c_cc[VEOF] = tmp.t_eofc;
	tty->termios.c_cc[VEOL2] = tmp.t_brkc;	/* what is brkc anyway? */
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
	return 0;
}
#endif
@@ -877,7 +877,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
{
	struct ltchars tmp;

	mutex_lock(&tty->termios_mutex);
	down_read(&tty->termios_rwsem);
	tmp.t_suspc = tty->termios.c_cc[VSUSP];
	/* what is dsuspc anyway? */
	tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
@@ -886,7 +886,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
	tmp.t_flushc = tty->termios.c_cc[VEOL2];
	tmp.t_werasc = tty->termios.c_cc[VWERASE];
	tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
	mutex_unlock(&tty->termios_mutex);
	up_read(&tty->termios_rwsem);
	return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}

@@ -897,7 +897,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
	if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
		return -EFAULT;

	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	tty->termios.c_cc[VSUSP] = tmp.t_suspc;
	/* what is dsuspc anyway? */
	tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
@@ -906,7 +906,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
	tty->termios.c_cc[VEOL2] = tmp.t_flushc;
	tty->termios.c_cc[VWERASE] = tmp.t_werasc;
	tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
	return 0;
}
#endif
@@ -946,7 +946,7 @@ static int send_prio_char(struct tty_struct *tty, char ch)
 *	@arg: enable/disable CLOCAL
 *
 *	Perform a change to the CLOCAL state and call into the driver
 *	layer to make it visible. All done with the termios mutex
 *	layer to make it visible. All done with the termios rwsem
 */

static int tty_change_softcar(struct tty_struct *tty, int arg)
@@ -955,7 +955,7 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
	int bit = arg ? CLOCAL : 0;
	struct ktermios old;

	mutex_lock(&tty->termios_mutex);
	down_write(&tty->termios_rwsem);
	old = tty->termios;
	tty->termios.c_cflag &= ~CLOCAL;
	tty->termios.c_cflag |= bit;
@@ -963,7 +963,7 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
		tty->ops->set_termios(tty, &old);
	if ((tty->termios.c_cflag & CLOCAL) != bit)
		ret = -EINVAL;
	mutex_unlock(&tty->termios_mutex);
	up_write(&tty->termios_rwsem);
	return ret;
}

@@ -1066,9 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
		if (user_termios_to_kernel_termios(&kterm,
					       (struct termios __user *) arg))
			return -EFAULT;
		mutex_lock(&real_tty->termios_mutex);
		down_write(&real_tty->termios_rwsem);
		real_tty->termios_locked = kterm;
		mutex_unlock(&real_tty->termios_mutex);
		up_write(&real_tty->termios_rwsem);
		return 0;
#else
	case TIOCGLCKTRMIOS:
@@ -1083,9 +1083,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
		if (user_termios_to_kernel_termios_1(&kterm,
					       (struct termios __user *) arg))
			return -EFAULT;
		mutex_lock(&real_tty->termios_mutex);
		down_write(&real_tty->termios_rwsem);
		real_tty->termios_locked = kterm;
		mutex_unlock(&real_tty->termios_mutex);
		up_write(&real_tty->termios_rwsem);
		return ret;
#endif
#ifdef TCGETX
@@ -1093,9 +1093,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
		struct termiox ktermx;
		if (real_tty->termiox == NULL)
			return -EINVAL;
		mutex_lock(&real_tty->termios_mutex);
		down_read(&real_tty->termios_rwsem);
		memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
		mutex_unlock(&real_tty->termios_mutex);
		up_read(&real_tty->termios_rwsem);
		if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
			ret = -EFAULT;
		return ret;
Loading