2015-04-16 18:57:45

by Joseph Salisbury

[permalink] [raw]
Subject: [v3.12.y][v3.13.y-ckt][3.14.y][3.16.y-ckt][3.18.y][3.19.y][V2][PATCH 0/1] n_tty: Fix read buffer overwrite when no newline

Hello,

Please consider including mainline commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e
in the next v3.12.y, v3.13.y-ckt, v3.14.y, 3.16.y-ckt, 3.18.y, and 3.19.y stable releases.
It was included mainline as of v4.0-rc1. It has been tested and confirmed to resolve
http://bugs.launchpad.net/bugs/1381005 . This bug was introduced in v3.12-rc1 when
commit 24a89d1 was applied. This commit is not needed in stable kernels prior to
v3.12.y.


commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e
Author: Peter Hurley <[email protected]>
Date: Fri Jan 16 15:05:39 2015 -0500

n_tty: Fix read buffer overwrite when no newline


This commit does not apply cleanly to the kernels versions mentined, so I performed
a backport, which is in email 1/1.

The 3.12.y and 3.13.y-ckt stable releases first need a cherry pick of commit
5c32d12378313e0096ea0d450462aa638a90fb6e. This is because in commit 5c32d123
n_tty_receive_buf and n_tty_receive_buf2 were merged into n_tty_receive_buf_common,
which is where the backport makes the needed changes.


Sincerely,

Joseph Salisbury

Peter Hurley (1):
n_tty: Fix read buffer overwrite when no newline

drivers/tty/n_tty.c | 106 +++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 79 insertions(+), 27 deletions(-)

--
2.1.0


2015-04-16 18:57:56

by Joseph Salisbury

[permalink] [raw]
Subject: [v3.12.y][v3.13.y-ckt][3.14.y][3.16.y-ckt][3.18.y][3.19.y][V2][PATCH 1/1] n_tty: Fix read buffer overwrite when no newline

From: Peter Hurley <[email protected]>

BugLink: http://bugs.launchpad.net/bugs/1381005

In canon mode, the read buffer head will advance over the buffer tail
if the input > 4095 bytes without receiving a line termination char.

Discard additional input until a line termination is received.
Before evaluating for overflow, the 'room' value is normalized for
I_PARMRK and 1 byte is reserved for line termination (even in !icanon
mode, in case the mode is switched). The following table shows the
transform:

actual buffer | 'room' value before overflow calc
space avail | !I_PARMRK | I_PARMRK
--------------------------------------------------
0 | -1 | -1
1 | 0 | 0
2 | 1 | 0
3 | 2 | 0
4+ | 3 | 1

When !icanon or when icanon and the read buffer contains newlines,
normalized 'room' values of -1 and 0 are clamped to 0, and
'overflow' is 0, so read_head is not adjusted and the input i/o loop
exits (setting no_room if called from flush_to_ldisc()). No input
is discarded since the reader does have input available to read
which ensures forward progress.

When icanon and the read buffer does not contain newlines and the
normalized 'room' value is 0, then overflow and room are reset to 1,
so that the i/o loop will process the next input char normally
(except for parity errors which are ignored). Thus, erasures, signalling
chars, 7-bit mode, etc. will continue to be handled properly.

If the input char processed was not a line termination char, then
the canon_head index will not have advanced, so the normalized 'room'
value will now be -1 and 'overflow' will be set, which indicates the
read_head can safely be reset, effectively erasing the last char
processed.

If the input char processed was a line termination, then the
canon_head index will have advanced, so 'overflow' is cleared to 0,
the read_head is not reset, and 'room' is cleared to 0, which exits
the i/o loop (because the reader now have input available to read
which ensures forward progress).

Note that it is possible for a line termination to be received, and
for the reader to copy the line to the user buffer before the
input i/o loop is ready to process the next input char. This is
why the i/o loop recomputes the room/overflow state with every
input char while handling overflow.

Finally, if the input data was processed without receiving
a line termination (so that overflow is still set), the pty
driver must receive a write wakeup. A pty writer may be waiting
to write more data in n_tty_write() but without unthrottling
here that wakeup will not arrive, and forward progress will halt.
(Normally, the pty writer is woken when the reader reads data out
of the buffer and more space become available).

Signed-off-by: Peter Hurley <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
(backported from commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e)
Signed-off-by: Joseph Salisbury <[email protected]>
---
drivers/tty/n_tty.c | 106 +++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 79 insertions(+), 27 deletions(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4ddfa60..6f8cf3a 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -247,8 +247,6 @@ static void n_tty_write_wakeup(struct tty_struct *tty)

static void n_tty_check_throttle(struct tty_struct *tty)
{
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY)
- return;
/*
* Check the remaining room for the input canonicalization
* mode. We don't want to throttle the driver if we're in
@@ -1512,23 +1510,6 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
n_tty_receive_char_flagged(tty, c, flag);
}

-/**
- * n_tty_receive_buf - data receive
- * @tty: terminal device
- * @cp: buffer
- * @fp: flag buffer
- * @count: characters
- *
- * Called by the terminal driver when a block of characters has
- * been received. This function must be called from soft contexts
- * not from interrupt context. The driver is responsible for making
- * calls one at a time and in order (or using flush_to_ldisc)
- *
- * n_tty_receive_buf()/producer path:
- * claims non-exclusive termios_rwsem
- * publishes read_head and canon_head
- */
-
static void
n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
@@ -1684,24 +1665,85 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
}

+/**
+ * n_tty_receive_buf_common - process input
+ * @tty: device to receive input
+ * @cp: input chars
+ * @fp: flags for each char (if NULL, all chars are TTY_NORMAL)
+ * @count: number of input chars in @cp
+ *
+ * Called by the terminal driver when a block of characters has
+ * been received. This function must be called from soft contexts
+ * not from interrupt context. The driver is responsible for making
+ * calls one at a time and in order (or using flush_to_ldisc)
+ *
+ * Returns the # of input chars from @cp which were processed.
+ *
+ * In canonical mode, the maximum line length is 4096 chars (including
+ * the line termination char); lines longer than 4096 chars are
+ * truncated. After 4095 chars, input data is still processed but
+ * not stored. Overflow processing ensures the tty can always
+ * receive more input until at least one line can be read.
+ *
+ * In non-canonical mode, the read buffer will only accept 4095 chars;
+ * this provides the necessary space for a newline char if the input
+ * mode is switched to canonical.
+ *
+ * Note it is possible for the read buffer to _contain_ 4096 chars
+ * in non-canonical mode: the read buffer could already contain the
+ * maximum canon line of 4096 chars when the mode is switched to
+ * non-canonical.
+ *
+ * n_tty_receive_buf()/producer path:
+ * claims non-exclusive termios_rwsem
+ * publishes commit_head or canon_head
+ */
static int
n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count, int flow)
{
struct n_tty_data *ldata = tty->disc_data;
- int room, n, rcvd = 0;
+ int room, n, rcvd = 0, overflow;

down_read(&tty->termios_rwsem);

while (1) {
- room = receive_room(tty);
+ /*
+ * When PARMRK is set, each input char may take up to 3 chars
+ * in the read buf; reduce the buffer space avail by 3x
+ *
+ * If we are doing input canonicalization, and there are no
+ * pending newlines, let characters through without limit, so
+ * that erase characters will be handled. Other excess
+ * characters will be beeped.
+ *
+ * paired with store in *_copy_from_read_buf() -- guarantees
+ * the consumer has loaded the data in read_buf up to the new
+ * read_tail (so this producer will not overwrite unread data)
+ */
+ size_t tail = ldata->read_tail;
+
+ room = N_TTY_BUF_SIZE - (ldata->read_head - tail);
+ if (I_PARMRK(tty))
+ room = (room + 2) / 3;
+ room--;
+ if (room <= 0) {
+ overflow = ldata->icanon && ldata->canon_head == tail;
+ if (overflow && room < 0)
+ ldata->read_head--;
+ room = overflow;
+ ldata->no_room = flow && !room;
+ } else
+ overflow = 0;
+
n = min(count, room);
- if (!n) {
- if (flow && !room)
- ldata->no_room = 1;
+ if (!n)
break;
- }
- __receive_buf(tty, cp, fp, n);
+
+ /* ignore parity errors if handling overflow */
+ if (!overflow || !fp || *fp != TTY_PARITY)
+ __receive_buf(tty, cp, fp, n);
+
cp += n;
if (fp)
fp += n;
@@ -1710,7 +1752,17 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
}

tty->receive_room = room;
- n_tty_check_throttle(tty);
+
+ /* Unthrottle if handling overflow on pty */
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
+ if (overflow) {
+ tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
+ tty_unthrottle_safe(tty);
+ __tty_set_flow_change(tty, 0);
+ }
+ } else
+ n_tty_check_throttle(tty);
+
up_read(&tty->termios_rwsem);

return rcvd;
--
2.1.0

2015-04-21 16:16:06

by Jiri Slaby

[permalink] [raw]
Subject: Re: [v3.12.y][v3.13.y-ckt][3.14.y][3.16.y-ckt][3.18.y][3.19.y][V2][PATCH 0/1] n_tty: Fix read buffer overwrite when no newline

On 04/16/2015, 08:57 PM, Joseph Salisbury wrote:
> Hello,
>
> Please consider including mainline commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e
> in the next v3.12.y, v3.13.y-ckt, v3.14.y, 3.16.y-ckt, 3.18.y, and 3.19.y stable releases.
> It was included mainline as of v4.0-rc1. It has been tested and confirmed to resolve
> http://bugs.launchpad.net/bugs/1381005 . This bug was introduced in v3.12-rc1 when
> commit 24a89d1 was applied. This commit is not needed in stable kernels prior to
> v3.12.y.
>
>
> commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e
> Author: Peter Hurley <[email protected]>
> Date: Fri Jan 16 15:05:39 2015 -0500
>
> n_tty: Fix read buffer overwrite when no newline
>
>
> This commit does not apply cleanly to the kernels versions mentined, so I performed
> a backport, which is in email 1/1.
>
> The 3.12.y and 3.13.y-ckt stable releases first need a cherry pick of commit
> 5c32d12378313e0096ea0d450462aa638a90fb6e. This is because in commit 5c32d123
> n_tty_receive_buf and n_tty_receive_buf2 were merged into n_tty_receive_buf_common,
> which is where the backport makes the needed changes.

I did for 3.12. Thanks.

--
js
suse labs

2015-04-22 13:19:04

by Luis Henriques

[permalink] [raw]
Subject: Re: [v3.12.y][v3.13.y-ckt][3.14.y][3.16.y-ckt][3.18.y][3.19.y][V2][PATCH 0/1] n_tty: Fix read buffer overwrite when no newline

On Thu, Apr 16, 2015 at 02:57:26PM -0400, Joseph Salisbury wrote:
> Hello,
>
> Please consider including mainline commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e
> in the next v3.12.y, v3.13.y-ckt, v3.14.y, 3.16.y-ckt, 3.18.y, and 3.19.y stable releases.
> It was included mainline as of v4.0-rc1. It has been tested and confirmed to resolve
> http://bugs.launchpad.net/bugs/1381005 . This bug was introduced in v3.12-rc1 when
> commit 24a89d1 was applied. This commit is not needed in stable kernels prior to
> v3.12.y.
>
>
> commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e
> Author: Peter Hurley <[email protected]>
> Date: Fri Jan 16 15:05:39 2015 -0500
>
> n_tty: Fix read buffer overwrite when no newline
>
>
> This commit does not apply cleanly to the kernels versions mentined, so I performed
> a backport, which is in email 1/1.
>
> The 3.12.y and 3.13.y-ckt stable releases first need a cherry pick of commit
> 5c32d12378313e0096ea0d450462aa638a90fb6e. This is because in commit 5c32d123
> n_tty_receive_buf and n_tty_receive_buf2 were merged into n_tty_receive_buf_common,
> which is where the backport makes the needed changes.
>
>

Thanks a lot for the backport. I'm queuing it for the 3.16 kernel.

Cheers,
--
Lu?s


> Sincerely,
>
> Joseph Salisbury
>
> Peter Hurley (1):
> n_tty: Fix read buffer overwrite when no newline
>
> drivers/tty/n_tty.c | 106 +++++++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 79 insertions(+), 27 deletions(-)
>
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe stable" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2015-05-01 15:58:07

by Kamal Mostafa

[permalink] [raw]
Subject: Re: [v3.12.y][v3.13.y-ckt][3.14.y][3.16.y-ckt][3.18.y][3.19.y][V2][PATCH 0/1] n_tty: Fix read buffer overwrite when no newline

On Thu, 2015-04-16 at 14:57 -0400, Joseph Salisbury wrote:
> Hello,
>
> Please consider including mainline commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e
> in the next v3.12.y, v3.13.y-ckt, v3.14.y, 3.16.y-ckt, 3.18.y, and 3.19.y stable releases.
> It was included mainline as of v4.0-rc1. It has been tested and confirmed to resolve
> http://bugs.launchpad.net/bugs/1381005 . This bug was introduced in v3.12-rc1 when
> commit 24a89d1 was applied. This commit is not needed in stable kernels prior to
> v3.12.y.
>
>
> commit fb5ef9e7da39968fec6d6f37f20a23d23740c75e
> Author: Peter Hurley <[email protected]>
> Date: Fri Jan 16 15:05:39 2015 -0500
>
> n_tty: Fix read buffer overwrite when no newline
>
>
> This commit does not apply cleanly to the kernels versions mentined, so I performed
> a backport, which is in email 1/1.
>
> The 3.12.y and 3.13.y-ckt stable releases first need a cherry pick of commit
> 5c32d12378313e0096ea0d450462aa638a90fb6e. This is because in commit 5c32d123
> n_tty_receive_buf and n_tty_receive_buf2 were merged into n_tty_receive_buf_common,
> which is where the backport makes the needed changes.
>
>
> Sincerely,
>
> Joseph Salisbury
>
> Peter Hurley (1):
> n_tty: Fix read buffer overwrite when no newline
>
> drivers/tty/n_tty.c | 106 +++++++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 79 insertions(+), 27 deletions(-)
>

Queued up for 3.13-stable. Thanks, Joseph and Peter!

-Kamal