n_tty: Access termios values safely
Use termios_rwsem to guarantee safe access to the termios values. This is particularly important for N_TTY as changing certain termios settings alters the mode of operation. termios_rwsem must be dropped across throttle/unthrottle since those functions claim the termios_rwsem exclusively (to guarantee safe access to the termios and for mutual exclusion). Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
6a1c0680cf
commit
9356b535fc
|
@ -1491,10 +1491,14 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||||
* canonical mode and don't have a newline yet!
|
* canonical mode and don't have a newline yet!
|
||||||
*/
|
*/
|
||||||
while (1) {
|
while (1) {
|
||||||
|
int throttled;
|
||||||
tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
|
tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
|
||||||
if (receive_room(tty) >= TTY_THRESHOLD_THROTTLE)
|
if (receive_room(tty) >= TTY_THRESHOLD_THROTTLE)
|
||||||
break;
|
break;
|
||||||
if (!tty_throttle_safe(tty))
|
up_read(&tty->termios_rwsem);
|
||||||
|
throttled = tty_throttle_safe(tty);
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
|
if (!throttled)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
__tty_set_flow_change(tty, 0);
|
__tty_set_flow_change(tty, 0);
|
||||||
|
@ -1503,7 +1507,9 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||||
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||||
char *fp, int count)
|
char *fp, int count)
|
||||||
{
|
{
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
__receive_buf(tty, cp, fp, count);
|
__receive_buf(tty, cp, fp, count);
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
|
static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
|
||||||
|
@ -1512,6 +1518,8 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
|
||||||
struct n_tty_data *ldata = tty->disc_data;
|
struct n_tty_data *ldata = tty->disc_data;
|
||||||
int room;
|
int room;
|
||||||
|
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
|
|
||||||
tty->receive_room = room = receive_room(tty);
|
tty->receive_room = room = receive_room(tty);
|
||||||
if (!room)
|
if (!room)
|
||||||
ldata->no_room = 1;
|
ldata->no_room = 1;
|
||||||
|
@ -1519,6 +1527,8 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
|
||||||
if (count)
|
if (count)
|
||||||
__receive_buf(tty, cp, fp, count);
|
__receive_buf(tty, cp, fp, count);
|
||||||
|
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1934,6 +1944,8 @@ do_it_again:
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
return c;
|
return c;
|
||||||
|
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
|
|
||||||
minimum = time = 0;
|
minimum = time = 0;
|
||||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||||
if (!ldata->icanon) {
|
if (!ldata->icanon) {
|
||||||
|
@ -1955,11 +1967,15 @@ do_it_again:
|
||||||
* Internal serialization of reads.
|
* Internal serialization of reads.
|
||||||
*/
|
*/
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
if (file->f_flags & O_NONBLOCK) {
|
||||||
if (!mutex_trylock(&ldata->atomic_read_lock))
|
if (!mutex_trylock(&ldata->atomic_read_lock)) {
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mutex_lock_interruptible(&ldata->atomic_read_lock))
|
if (mutex_lock_interruptible(&ldata->atomic_read_lock)) {
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
packet = tty->packet;
|
packet = tty->packet;
|
||||||
|
|
||||||
|
@ -2009,7 +2025,11 @@ do_it_again:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n_tty_set_room(tty);
|
n_tty_set_room(tty);
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
|
|
||||||
timeout = schedule_timeout(timeout);
|
timeout = schedule_timeout(timeout);
|
||||||
|
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
__set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
|
@ -2048,13 +2068,17 @@ do_it_again:
|
||||||
* we won't get any more characters.
|
* we won't get any more characters.
|
||||||
*/
|
*/
|
||||||
while (1) {
|
while (1) {
|
||||||
|
int unthrottled;
|
||||||
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
|
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
|
||||||
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
|
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
|
||||||
break;
|
break;
|
||||||
if (!tty->count)
|
if (!tty->count)
|
||||||
break;
|
break;
|
||||||
n_tty_set_room(tty);
|
n_tty_set_room(tty);
|
||||||
if (!tty_unthrottle_safe(tty))
|
up_read(&tty->termios_rwsem);
|
||||||
|
unthrottled = tty_unthrottle_safe(tty);
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
|
if (!unthrottled)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
__tty_set_flow_change(tty, 0);
|
__tty_set_flow_change(tty, 0);
|
||||||
|
@ -2076,10 +2100,13 @@ do_it_again:
|
||||||
retval = size;
|
retval = size;
|
||||||
if (nr)
|
if (nr)
|
||||||
clear_bit(TTY_PUSH, &tty->flags);
|
clear_bit(TTY_PUSH, &tty->flags);
|
||||||
} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
|
} else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) {
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
goto do_it_again;
|
goto do_it_again;
|
||||||
|
}
|
||||||
|
|
||||||
n_tty_set_room(tty);
|
n_tty_set_room(tty);
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2120,6 +2147,8 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
|
|
||||||
/* Write out any echoed characters that are still pending */
|
/* Write out any echoed characters that are still pending */
|
||||||
process_echoes(tty);
|
process_echoes(tty);
|
||||||
|
|
||||||
|
@ -2173,13 +2202,18 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
|
||||||
retval = -EAGAIN;
|
retval = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
|
|
||||||
schedule();
|
schedule();
|
||||||
|
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
}
|
}
|
||||||
break_out:
|
break_out:
|
||||||
__set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
remove_wait_queue(&tty->write_wait, &wait);
|
remove_wait_queue(&tty->write_wait, &wait);
|
||||||
if (b - buf != nr && tty->fasync)
|
if (b - buf != nr && tty->fasync)
|
||||||
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
return (b - buf) ? b - buf : retval;
|
return (b - buf) ? b - buf : retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue