Skip to content

Commit 9356b53

Browse files
peterhurleygregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 6a1c068 commit 9356b53

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

drivers/tty/n_tty.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,10 +1491,14 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
14911491
* canonical mode and don't have a newline yet!
14921492
*/
14931493
while (1) {
1494+
int throttled;
14941495
tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
14951496
if (receive_room(tty) >= TTY_THRESHOLD_THROTTLE)
14961497
break;
1497-
if (!tty_throttle_safe(tty))
1498+
up_read(&tty->termios_rwsem);
1499+
throttled = tty_throttle_safe(tty);
1500+
down_read(&tty->termios_rwsem);
1501+
if (!throttled)
14981502
break;
14991503
}
15001504
__tty_set_flow_change(tty, 0);
@@ -1503,7 +1507,9 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
15031507
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
15041508
char *fp, int count)
15051509
{
1510+
down_read(&tty->termios_rwsem);
15061511
__receive_buf(tty, cp, fp, count);
1512+
up_read(&tty->termios_rwsem);
15071513
}
15081514

15091515
static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
@@ -1512,13 +1518,17 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
15121518
struct n_tty_data *ldata = tty->disc_data;
15131519
int room;
15141520

1521+
down_read(&tty->termios_rwsem);
1522+
15151523
tty->receive_room = room = receive_room(tty);
15161524
if (!room)
15171525
ldata->no_room = 1;
15181526
count = min(count, room);
15191527
if (count)
15201528
__receive_buf(tty, cp, fp, count);
15211529

1530+
up_read(&tty->termios_rwsem);
1531+
15221532
return count;
15231533
}
15241534

@@ -1934,6 +1944,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
19341944
if (c < 0)
19351945
return c;
19361946

1947+
down_read(&tty->termios_rwsem);
1948+
19371949
minimum = time = 0;
19381950
timeout = MAX_SCHEDULE_TIMEOUT;
19391951
if (!ldata->icanon) {
@@ -1955,11 +1967,15 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
19551967
* Internal serialization of reads.
19561968
*/
19571969
if (file->f_flags & O_NONBLOCK) {
1958-
if (!mutex_trylock(&ldata->atomic_read_lock))
1970+
if (!mutex_trylock(&ldata->atomic_read_lock)) {
1971+
up_read(&tty->termios_rwsem);
19591972
return -EAGAIN;
1973+
}
19601974
} else {
1961-
if (mutex_lock_interruptible(&ldata->atomic_read_lock))
1975+
if (mutex_lock_interruptible(&ldata->atomic_read_lock)) {
1976+
up_read(&tty->termios_rwsem);
19621977
return -ERESTARTSYS;
1978+
}
19631979
}
19641980
packet = tty->packet;
19651981

@@ -2009,7 +2025,11 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
20092025
break;
20102026
}
20112027
n_tty_set_room(tty);
2028+
up_read(&tty->termios_rwsem);
2029+
20122030
timeout = schedule_timeout(timeout);
2031+
2032+
down_read(&tty->termios_rwsem);
20132033
continue;
20142034
}
20152035
__set_current_state(TASK_RUNNING);
@@ -2048,13 +2068,17 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
20482068
* we won't get any more characters.
20492069
*/
20502070
while (1) {
2071+
int unthrottled;
20512072
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
20522073
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
20532074
break;
20542075
if (!tty->count)
20552076
break;
20562077
n_tty_set_room(tty);
2057-
if (!tty_unthrottle_safe(tty))
2078+
up_read(&tty->termios_rwsem);
2079+
unthrottled = tty_unthrottle_safe(tty);
2080+
down_read(&tty->termios_rwsem);
2081+
if (!unthrottled)
20582082
break;
20592083
}
20602084
__tty_set_flow_change(tty, 0);
@@ -2076,10 +2100,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
20762100
retval = size;
20772101
if (nr)
20782102
clear_bit(TTY_PUSH, &tty->flags);
2079-
} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
2103+
} else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) {
2104+
up_read(&tty->termios_rwsem);
20802105
goto do_it_again;
2106+
}
20812107

20822108
n_tty_set_room(tty);
2109+
up_read(&tty->termios_rwsem);
20832110
return retval;
20842111
}
20852112

@@ -2120,6 +2147,8 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
21202147
return retval;
21212148
}
21222149

2150+
down_read(&tty->termios_rwsem);
2151+
21232152
/* Write out any echoed characters that are still pending */
21242153
process_echoes(tty);
21252154

@@ -2173,13 +2202,18 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
21732202
retval = -EAGAIN;
21742203
break;
21752204
}
2205+
up_read(&tty->termios_rwsem);
2206+
21762207
schedule();
2208+
2209+
down_read(&tty->termios_rwsem);
21772210
}
21782211
break_out:
21792212
__set_current_state(TASK_RUNNING);
21802213
remove_wait_queue(&tty->write_wait, &wait);
21812214
if (b - buf != nr && tty->fasync)
21822215
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
2216+
up_read(&tty->termios_rwsem);
21832217
return (b - buf) ? b - buf : retval;
21842218
}
21852219

0 commit comments

Comments
 (0)