APPLIED: [Trusty][pull request] (upstream) n_tty: Fix buffer overruns with larger-than-4k pastes
Brad Figg
brad.figg at canonical.com
Fri Jul 25 14:46:12 UTC 2014
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/24/2014 01:43 PM, Rafael David Tinoco wrote:
> From 0b8b060c8932c600a240fb1fa055fa103b5e969a Mon Sep 17 00:00:00 2001
> From: Peter Hurley <peter at hurleysoftware.com>
> Date: Tue, 10 Dec 2013 17:12:02 -0500
> Subject: n_tty: Fix buffer overruns with larger-than-4k pastes
>
> BugLink: http://bugs.launchpad.net/bugs/1208740
>
> n_tty: Fix buffer overruns with larger-than-4k pastes
>
> readline() inadvertently triggers an error recovery path when
> pastes larger than 4k overrun the line discipline buffer. The
> error recovery path discards input when the line discipline buffer
> is full and operating in canonical mode and no newline has been
> received. Because readline() changes the termios to non-canonical
> mode to read the line char-by-char, the line discipline buffer
> can become full, and then when readline() restores termios back
> to canonical mode for the caller, the now-full line discipline
> buffer triggers the error recovery.
>
> When changing termios from non-canon to canon mode and the read
> buffer contains data, simulate an EOF push _without_ the
> DISABLED_CHAR in the read buffer.
>
> Importantly for the readline() problem, the termios can be
> changed back to non-canonical mode without changes to the read
> buffer occurring; ie., as if the previous termios change had not
> happened (as long as no intervening read took place).
>
> Preserve existing userspace behavior which allows '\0's already
> received in non-canon mode to be read as '\0's in canon mode
> (rather than trigger add'l EOF pushes or an actual EOF).
>
> Patch based on original proposal and discussion here
> https://bugzilla.kernel.org/show_bug.cgi?id=55991
> by Stas Sergeev <stsp at users.sourceforge.net>
>
> OriginalAuthor: Peter Hurley <peter at hurleysoftware.com>
> Reported-by: Margarita Manterola <margamanterola at gmail.com>
> Acked-by: Stas Sergeev <stsp at users.sourceforge.net>
> Signed-off-by: Peter Hurley <peter at hurleysoftware.com>
> (cherry-picked from commit 4d0ed18277cc6f07513ee0b04475f19cd69e75ef v3.14-rc1)
> Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Signed-off-by: Rafael David Tinoco <rafael.tinoco at canonical.com>
> ---
> drivers/tty/n_tty.c | 26 +++++++++++++++++++++++---
> 1 file changed, 23 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> index 86093e2..f591184 100644
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -105,6 +105,7 @@ struct n_tty_data {
>
> /* must hold exclusive termios_rwsem to reset these */
> unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
> + unsigned char push:1;
>
> /* shared by producer and consumer */
> char read_buf[N_TTY_BUF_SIZE];
> @@ -342,6 +343,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
>
> ldata->erasing = 0;
> bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
> + ldata->push = 0;
> }
>
> static void n_tty_packet_mode_flush(struct tty_struct *tty)
> @@ -1762,7 +1764,16 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
>
> if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) {
> bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
> - ldata->line_start = ldata->canon_head = ldata->read_tail;
> + ldata->line_start = ldata->read_tail;
> + if (!L_ICANON(tty) || !read_cnt(ldata)) {
> + ldata->canon_head = ldata->read_tail;
> + ldata->push = 0;
> + } else {
> + set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1),
> + ldata->read_flags);
> + ldata->canon_head = ldata->read_head;
> + ldata->push = 1;
> + }
> ldata->erasing = 0;
> ldata->lnext = 0;
> }
> @@ -1967,6 +1978,12 @@ static int copy_from_read_buf(struct tty_struct *tty,
> * it copies one line of input up to and including the line-delimiting
> * character into the user-space buffer.
> *
> + * NB: When termios is changed from non-canonical to canonical mode and
> + * the read buffer contains data, n_tty_set_termios() simulates an EOF
> + * push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer.
> + * This causes data already processed as input to be immediately available
> + * as input although a newline has not been received.
> + *
> * Called under the atomic_read_lock mutex
> *
> * n_tty_read()/consumer path:
> @@ -2013,7 +2030,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
> n += found;
> c = n;
>
> - if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
> + if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) {
> n--;
> eof_push = !n && ldata->read_tail != ldata->line_start;
> }
> @@ -2040,7 +2057,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
> ldata->read_tail += c;
>
> if (found) {
> - ldata->line_start = ldata->read_tail;
> + if (!ldata->push)
> + ldata->line_start = ldata->read_tail;
> + else
> + ldata->push = 0;
> tty_audit_push(tty);
> }
> return eof_push ? -EAGAIN : 0;
>
>
>
- --
Brad Figg brad.figg at canonical.com http://www.canonical.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
iQIcBAEBAgAGBQJT0m2sAAoJEAx7WJsQW+f3TxYQAIZVxLQsVeBuDIsjRWgzSoLt
WYGIjgC7erWhbziJ54jwZUEGqGoUBIwYMlMV0M7ty0B/J0tbH9VaACkM/MjOwoYZ
AhKgZot4GarmZTlelb8hAoq0nNIa25L2P0fKzHU3Rfd2DWJ/ck7el1+YMPc+xxgS
Zq6tCTvCq3R51zUxXc4SFe/nNPH/6ljEF/OKRQeuZE89YarOkhT9c8BDCxnxkoKu
5bMCjGZ55vt85N72Hr2C21qufeKGIP8n3s46hQmLe5KVNmgmC9Zh7HK61e3HTUge
QkP8LphlaIxWqZYxUsy5Eul1++xqD0r3Y1Lti+U3e70x5YG8TlUsNV5X2dzV00xW
nRIlD6gu1d1hPY9IJctseYKqpjVmlP9bhFnuKZsPnsqIFOO1rMO5SELc2PTg7iCH
LWF29Ldin1Jz2pyJSCGRaGqaHeKtym4Sb13L1RhfJ64UStvxAJVY8wmd5/ch73+I
ZMYCzKfNRFQFTwUT4BBqOcD6ugvhqSYD3ymBm+hIXg/xu2KAh+Vc5KkgLUtfFx8e
kf5KKzklVcqDi0bAi19xZ3xzZeghWA9yK3u21yqw1Zg/mWT9P3vYcEC68BtMPipg
hqcNACpkebIuqS9MMyVCgSvP0337PxsBk7dAmZpLM/w8aexeKRPk0achm73qO/gV
zQjHQfZ8jtNsGCTNnwmH
=Dfqh
-----END PGP SIGNATURE-----
More information about the kernel-team
mailing list