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

Commit 00aaae03 authored by Stanislav Kozina's avatar Stanislav Kozina Committed by Greg Kroah-Hartman
Browse files

tty: Fix possible race in n_tty_read()



Fix possible panic caused by unlocked access to tty->read_cnt in
while-loop condition in n_tty_read().

Signed-off-by: default avatarStanislav Kozina <skozina@redhat.com>
Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 857196e2
Loading
Loading
Loading
Loading
+5 −1
Original line number Original line Diff line number Diff line
@@ -1838,13 +1838,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,


		if (tty->icanon && !L_EXTPROC(tty)) {
		if (tty->icanon && !L_EXTPROC(tty)) {
			/* N.B. avoid overrun if nr == 0 */
			/* N.B. avoid overrun if nr == 0 */
			spin_lock_irqsave(&tty->read_lock, flags);
			while (nr && tty->read_cnt) {
			while (nr && tty->read_cnt) {
				int eol;
				int eol;


				eol = test_and_clear_bit(tty->read_tail,
				eol = test_and_clear_bit(tty->read_tail,
						tty->read_flags);
						tty->read_flags);
				c = tty->read_buf[tty->read_tail];
				c = tty->read_buf[tty->read_tail];
				spin_lock_irqsave(&tty->read_lock, flags);
				tty->read_tail = ((tty->read_tail+1) &
				tty->read_tail = ((tty->read_tail+1) &
						  (N_TTY_BUF_SIZE-1));
						  (N_TTY_BUF_SIZE-1));
				tty->read_cnt--;
				tty->read_cnt--;
@@ -1862,15 +1862,19 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
					if (tty_put_user(tty, c, b++)) {
					if (tty_put_user(tty, c, b++)) {
						retval = -EFAULT;
						retval = -EFAULT;
						b--;
						b--;
						spin_lock_irqsave(&tty->read_lock, flags);
						break;
						break;
					}
					}
					nr--;
					nr--;
				}
				}
				if (eol) {
				if (eol) {
					tty_audit_push(tty);
					tty_audit_push(tty);
					spin_lock_irqsave(&tty->read_lock, flags);
					break;
					break;
				}
				}
				spin_lock_irqsave(&tty->read_lock, flags);
			}
			}
			spin_unlock_irqrestore(&tty->read_lock, flags);
			if (retval)
			if (retval)
				break;
				break;
		} else {
		} else {