All of lore.kernel.org
 help / color / mirror / Atom feed
* Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
@ 2013-07-25 11:29 Margarita Manterola
  2013-07-25 23:09 ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Margarita Manterola @ 2013-07-25 11:29 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, jslaby, Maximiliano Curia

[-- Attachment #1: Type: text/plain, Size: 3649 bytes --]

Hi,

The problem:
Large pastes (5k or more) into a readline enabled program fail when
running kernels larger than v2.6.31-rc5.  "Fail" means that some lines
are incomplete.  From v2.6.39-rc1 onwards, "some lines" become "almost
all lines after the first 4k".  This turns up at least in Fedora,
Debian, Ubuntu and Gentoo.  From our findings, it should happen in any
readline enabled program on a system running kernels later than the
mentioned ones.

The problematic commits in the kernel tree:
1 - 2009-07-27 (never shipped) -
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=3a54297478e6578f96fd54bf4daa1751130aca86

After this commit, pastes start breaking.  For a 35k file, about 50%
of the times one or two lines are partially incomplete.

2 - 2009-07-29 (v2.6.31-rc5) -
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=e043e42bdb66885b3ac10d27a01ccb9972e2b0a3

This commit reverts the previous one, but adds one extra call to
flush_to_ldisc.  Pastes still break, commenting out the function call
prevents breakage *up to 2.6.39-rc1*.

3 - 2011-03-22 (v2.6.39-rc1) -
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=f23eb2b2b28547fc70df82dd5049eb39bec5ba12

This commit changes many schedule/flush/cancel_delayed_work calls into
schedule/flush/cancel_work.  After this commit, the big breakage
starts: for the 35k example file, it starts breaking at aprox. 4k and
then every line is partially incomplete or directly not there.

Still after this commit, commenting out the tty_flush_to_ldisc(tty)
call added by e043e42bdb66885b3ac10d27a01ccb9972e2b0a3 prevents the
breakage.

4 - 2011-04-04 (v2.6.39-rc2) -
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=a5660b41af6a28f8004e70eb261e1202ad55c5e3

This commit modifies the behaviour of how the ttys are polled.  After
this commit, commenting out the tty_flush_to_ldisc(tty) call doesn't
prevent breakage anymore.

But then re-adding the call to schedule_work(&tty->buf.work) that was
removed in this commit, prevents the breakage even up to 3.11-rc2.
I'm attaching a diff of the patch that we applied, just to show what
had to be done, this is not a proposed fix, because this does cause a
busy loop that is particularly noticeable in VMs.

We haven't yet found a good fix for this issue, but we believe that
pasting into readline enabled programs shouldn't cause characters to
get lost, and it should be possible to do that properly without the
busy loop.

***
This was originally reported as a bug in readline, but it was found
that going back to very old kernels prevented the issue, regardless of
the version of readline.

Original Report (2012-06-25):
http://lists.gnu.org/archive/html/bug-readline/2012-06/msg00006.html
Follow Up thread (2013-07-22):
http://lists.gnu.org/archive/html/bug-readline/2013-07/msg00006.html

I'm attaching here a very simple readline enabled program that helps
with performing tests.  Compile, run, then copy and paste a large
enough file into it, close and diff.

Looking at the code in readline, the issue is triggered by these lines
in rltty.c, while preparing the input:

tiop->c_lflag &= ~(ICANON | ECHO);
(...)
tiop->c_iflag &= ~(ICRNL | INLCR);

If those two lines are replaced by:

tiop->c_lflag &= ~(ECHO);
(...)
tiop->c_iflag &= ~(INLCR);

Then the pastes work fine: no lines are missing.  Of course, this
means that readline doesn't work properly, but this is just to note
that those are the terminal settings that cause the issue to pop-up.

Credit: this investigation was done together with Maximiliano Curia.

-- 
Regards,
Margarita Manterola

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: minirl.c --]
[-- Type: text/x-csrc; name="minirl.c", Size: 862 bytes --]

/* mini program to demonstrate problem with cut and paste,  Frank Lübeck */
/* Simplified by Margarita Manterola. */
/* Compile:
 *    gcc -Wall -o minirl -O2 minirl.c -lreadline
 *    gcc -Wall -o minirl -O2 minirl.c $CPPFLAGS $LDFLAGS -lreadline -lncurses
 * Run:
 *    ./minirl TESTOUT
 * and paste the content of any text file (say 10kB without long lines),
 * end program with Ctrl-d.
 *
 * Then
 *    diff original-file TESTOUT
 * shows that in some lines trailing characters get lost. Or lines completely
 * lost.
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <readline/readline.h>

int main(int argc, char** argv) {

  char* s;
  FILE *out;

  if (argc == 1) return 1;
  out = fopen(argv[1], "w");
  while (1) {
    s = readline("> ");
    if (!s) break;
    fprintf(out,"%s\n",s);
    free(s);
  }
  fflush(out);
  return 0;
}

[-- Attachment #3: prevent_readline_paste_breakage.diff --]
[-- Type: application/octet-stream, Size: 1240 bytes --]

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4bf0fc0..6d4b647 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1667,7 +1667,7 @@ static inline int input_available_p(struct tty_struct
*tty, int amt)
 {
        struct n_tty_data *ldata = tty->disc_data;

-       tty_flush_to_ldisc(tty);
+       // tty_flush_to_ldisc(tty);
        if (ldata->icanon && !L_EXTPROC(tty)) {
                if (ldata->canon_data)
                        return 1;
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 9121c1f..6c2da95 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -449,8 +449,10 @@ static void flush_to_ldisc(struct work_struct *work)
                                tty_buffer_free(port, head);
                                continue;
                        }
-                       if (!tty->receive_room)
+                       if (!tty->receive_room) {
+                                schedule_work(&buf->work);
                                break;
+                        }
                        if (count > tty->receive_room)
                                count = tty->receive_room;
                        char_buf = head->char_buf_ptr + head->read;


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-07-25 11:29 Large pastes into readline enabled programs causes breakage from v2.6.31 onwards Margarita Manterola
@ 2013-07-25 23:09 ` Peter Hurley
  2013-07-30 12:41   ` Maximiliano Curia
       [not found]   ` <20130730124117.41DC55E4006@freak.gnuservers.com.ar>
  0 siblings, 2 replies; 40+ messages in thread
From: Peter Hurley @ 2013-07-25 23:09 UTC (permalink / raw)
  To: Margarita Manterola; +Cc: linux-kernel, gregkh, jslaby, Maximiliano Curia

On 07/25/2013 07:29 AM, Margarita Manterola wrote:
> Hi,
>
> The problem:
> Large pastes (5k or more) into a readline enabled program fail when
> running kernels larger than v2.6.31-rc5.  "Fail" means that some lines
> are incomplete.  From v2.6.39-rc1 onwards, "some lines" become "almost
> all lines after the first 4k".  This turns up at least in Fedora,
> Debian, Ubuntu and Gentoo.  From our findings, it should happen in any
> readline enabled program on a system running kernels later than the
> mentioned ones.
>
> The problematic commits in the kernel tree:
> 1 - 2009-07-27 (never shipped) -
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=3a54297478e6578f96fd54bf4daa1751130aca86
>
> After this commit, pastes start breaking.  For a 35k file, about 50%
> of the times one or two lines are partially incomplete.
>
> 2 - 2009-07-29 (v2.6.31-rc5) -
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=e043e42bdb66885b3ac10d27a01ccb9972e2b0a3
>
> This commit reverts the previous one, but adds one extra call to
> flush_to_ldisc.  Pastes still break, commenting out the function call
> prevents breakage *up to 2.6.39-rc1*.
>
> 3 - 2011-03-22 (v2.6.39-rc1) -
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=f23eb2b2b28547fc70df82dd5049eb39bec5ba12
>
> This commit changes many schedule/flush/cancel_delayed_work calls into
> schedule/flush/cancel_work.  After this commit, the big breakage
> starts: for the 35k example file, it starts breaking at aprox. 4k and
> then every line is partially incomplete or directly not there.
>
> Still after this commit, commenting out the tty_flush_to_ldisc(tty)
> call added by e043e42bdb66885b3ac10d27a01ccb9972e2b0a3 prevents the
> breakage.
>
> 4 - 2011-04-04 (v2.6.39-rc2) -
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=a5660b41af6a28f8004e70eb261e1202ad55c5e3
>
> This commit modifies the behaviour of how the ttys are polled.  After
> this commit, commenting out the tty_flush_to_ldisc(tty) call doesn't
> prevent breakage anymore.
>
> But then re-adding the call to schedule_work(&tty->buf.work) that was
> removed in this commit, prevents the breakage even up to 3.11-rc2.
> I'm attaching a diff of the patch that we applied, just to show what
> had to be done, this is not a proposed fix, because this does cause a
> busy loop that is particularly noticeable in VMs.
>
> We haven't yet found a good fix for this issue, but we believe that
> pasting into readline enabled programs shouldn't cause characters to
> get lost, and it should be possible to do that properly without the
> busy loop.
>
> ***
> This was originally reported as a bug in readline, but it was found
> that going back to very old kernels prevented the issue, regardless of
> the version of readline.
>
> Original Report (2012-06-25):
> http://lists.gnu.org/archive/html/bug-readline/2012-06/msg00006.html
> Follow Up thread (2013-07-22):
> http://lists.gnu.org/archive/html/bug-readline/2013-07/msg00006.html
>
> I'm attaching here a very simple readline enabled program that helps
> with performing tests.  Compile, run, then copy and paste a large
> enough file into it, close and diff.
>
> Looking at the code in readline, the issue is triggered by these lines
> in rltty.c, while preparing the input:
>
> tiop->c_lflag &= ~(ICANON | ECHO);
> (...)
> tiop->c_iflag &= ~(ICRNL | INLCR);
>
> If those two lines are replaced by:
>
> tiop->c_lflag &= ~(ECHO);
> (...)
> tiop->c_iflag &= ~(INLCR);
>
> Then the pastes work fine: no lines are missing.  Of course, this
> means that readline doesn't work properly, but this is just to note
> that those are the terminal settings that cause the issue to pop-up.
>
> Credit: this investigation was done together with Maximiliano Curia.
>

readline is fundamentally incompatible with an active writer.

readline() saves and restores the termios settings for each input
line it reads. However, tty i/o is asynchronous in the kernel.
This means that when readline() restores the original termios
settings, any new data received by the tty will be interpreted
with the current, original termios settings.

When a large paste happens, the tty/line discipline read buffer
quickly fills up (to 4k). When full, further input is forced to
wait. After readline() reads an input line, more space becomes
available in the read buffer. Unfortunately, this event roughly
coincides with restoring the original termios settings, and
thus increases the probability that more paste data will be
received with the wrong termios settings.

That's why the patches that involve scheduling the receive
buffer work seem to have some effect on the outcome.

As you've already noted, readline() termios settings are
substantially different than the default termios settings.

Below I've included a simple test jig that
  1) sets termios to the same settings as readline()
  2) uses the same read() method as readline()
  3) outputs what it reads to stdout
  4) restores the original termios

Note that the test jig differs from readline() in that
it reads _all_ the available input without changing
termios.

The test jig will identically duplicate a large paste. Feel
free to modify the test jig to change the termios settings
per-line.

Regards,
Peter Hurley


[ NB: In the test jig, I didn't bother with ensuring eof is
the first input of a new line.

I converted CR -> NL because that's what your test
program does, in conjunction with readline(). Pasted lines
are CR-terminated; readline() returns the input line less the
CR; your test program prints the line followed by NL.

]

--- >% ---
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {

	int c, eof;
         ssize_t actual;
	struct termios termios, save;
	int err;

	err = tcgetattr(STDIN_FILENO, &termios);
	if (err < 0)
		exit(EXIT_FAILURE);

	save = termios;

	termios.c_lflag &= ~(ICANON | ECHO | ISIG);
	termios.c_iflag &= ~(IXON | IXOFF);
	if ((termios.c_cflag & CSIZE) == CS8)
		termios.c_iflag &= ~(ISTRIP | INPCK);
	termios.c_iflag &= ~(ICRNL | INLCR);
	termios.c_cc[VMIN] = 1;
	termios.c_cc[VTIME] = 0;
	termios.c_cc[VLNEXT] = _POSIX_VDISABLE;
	eof = termios.c_cc[VEOF];

	err = tcsetattr(STDIN_FILENO, TCSANOW, &termios);
	if (err < 0)
		exit(EXIT_FAILURE);

	while (1) {
		actual = read( fileno(stdin), &c, sizeof(unsigned char));
		if (actual <= 0)
			break;
		if (actual == sizeof(unsigned char)) {
			if (c == eof)
				break;
			if (c == '\r')
				c = '\n';
			fputc(c, stdout);
		}
		fflush(stdout);
	}

	err = tcsetattr(STDIN_FILENO, TCSAFLUSH, &save);
	if (err < 0)
		exit(EXIT_FAILURE);

	return 0;
}


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-07-25 23:09 ` Peter Hurley
@ 2013-07-30 12:41   ` Maximiliano Curia
       [not found]   ` <20130730124117.41DC55E4006@freak.gnuservers.com.ar>
  1 sibling, 0 replies; 40+ messages in thread
From: Maximiliano Curia @ 2013-07-30 12:41 UTC (permalink / raw)
  To: linux-kernel

Peter Hurley wrote:

> readline is fundamentally incompatible with an active writer.

This wasn't the case with older kernel versions. I don't see any POSIX 
reference that claims user input could be lost setting termios so I think 
this is a serious regression.

Also, consider the readline use cases. bash, for instance, uses readline to 
process the command lines entered, but needs to change the termios to a 
canonical mode for each entered command. I would expect that pasting a 
sequence of commands (of 4K, which is not even 'a lot') to work.

The same is true for psql, where users might paste several KB of queries, or 
almost every readline enabled "shell".

> readline() saves and restores the termios settings for each input
> line it reads. However, tty i/o is asynchronous in the kernel.
> This means that when readline() restores the original termios
> settings, any new data received by the tty will be interpreted
> with the current, original termios settings.

> When a large paste happens, the tty/line discipline read buffer
> quickly fills up (to 4k). When full, further input is forced to
> wait. After readline() reads an input line, more space becomes
> available in the read buffer. Unfortunately, this event roughly
> coincides with restoring the original termios settings, and
> thus increases the probability that more paste data will be
> received with the wrong termios settings.

> That's why the patches that involve scheduling the receive
> buffer work seem to have some effect on the outcome.

It's not totally clear to me why receiving characters with the wrong termios 
settings might lead to this characters being dropped when reading them with 
different settings.

I took a deep look into the code, trying to find where was the code that ended 
up dropping characters, but could not find it.
Could you maybe point me to it?

> As you've already noted, readline() termios settings are
> substantially different than the default termios settings.
> 
> Below I've included a simple test jig that
>   1) sets termios to the same settings as readline()
>   2) uses the same read() method as readline()
>   3) outputs what it reads to stdout
>   4) restores the original termios

I've updated your code the be closer to the readline behaviour. readline 
calls tcsetattr with TCSADRAIN, and not TCSAFLUSH which explictly claims to 
discard the input. I've also reordered the call to process lines, and 
initialized the int c.

--- >% ---
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>

void init(int *eof, struct termios* save)
{
    int err;
    static struct termios termios;

    err = tcgetattr(STDIN_FILENO, &termios);
    if (err < 0)
        exit(EXIT_FAILURE);
    *save = termios;

    termios.c_lflag &= ~(ICANON | ECHO | ISIG);
    termios.c_iflag &= ~(IXON | IXOFF);
    if ((termios.c_cflag & CSIZE) == CS8)
        termios.c_iflag &= ~(ISTRIP | INPCK);
    termios.c_iflag &= ~(ICRNL | INLCR);
    termios.c_cc[VMIN] = 1;
    termios.c_cc[VTIME] = 0;
    termios.c_cc[VLNEXT] = _POSIX_VDISABLE;
    *eof = termios.c_cc[VEOF];

    err = tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
    if (err < 0)
        exit(EXIT_FAILURE);
}

void deinit(struct termios* termios)
{
    int err;
    err = tcsetattr(STDIN_FILENO, TCSADRAIN, termios);
    if (err < 0)
        exit(EXIT_FAILURE);
}

int main(int argc, char* argv[])
{
    int c=0, eof;
    ssize_t actual;
    struct termios save;

    while (1) {
        init(&eof, &save);
        while (1) {
            actual = read(fileno(stdin), &c, sizeof(unsigned char));
            if (actual <= 0)
                break;
            if (actual == sizeof(unsigned char)) {
                if (c == eof)
                    break;
                if (c == '\r') {
                    c = '\n';
                }
                fputc(c, stdout);
                fflush(stdout);
                if (c == '\n') break;
            }
        }
        deinit(&save);
        if (c == eof) break;
    }

    return 0;
}
--- >% ---

-- 
"Seek simplicity, and distrust it." -- Whitehead's Rule
Saludos /\/\ /\ >< `/



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
       [not found]   ` <20130730124117.41DC55E4006@freak.gnuservers.com.ar>
@ 2013-07-30 16:08     ` Peter Hurley
  2013-08-08 17:58       ` Maximiliano Curia
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-07-30 16:08 UTC (permalink / raw)
  To: Maximiliano Curia
  Cc: Margarita Manterola, Greg Kroah-Hartman, Jiri Slaby, Linux kernel

Please don't drop CCs.

[ +cc Margarita Manterola, Greg Kroah-Hartman, Jiri Slaby, linux-kernel ]

On 07/30/2013 08:41 AM, Maximiliano Curia wrote:
> Peter Hurley wrote:
>
>> readline is fundamentally incompatible with an active writer.
>
> This wasn't the case with older kernel versions. I don't see any POSIX
> reference that claims user input could be lost setting termios so I think
> this is a serious regression.

I'm only interested in this discussion on the basis of a kernel
regression, because this behavior is fully POSIX compliant.

 From POSIX 2008, Section 11. General Terminal Interface, Part 11.1.6.
Canonical Mode Input Processing:

      In canonical mode input processing, terminal input is processed in
      units of lines. A line is delimited by a <newline> character (NL),
      an end-of-file character (EOF), or an end-of-line (EOL) character.
      See Special Characters for more information on EOF and EOL. This
      means that a read request shall not return until an entire line has
      been typed or a signal has been received. Also, no matter how many
      bytes are requested in the read() call, at most one line shall be
      returned. It is not, however, necessary to read a whole line at once;
      any number of bytes, even one, may be requested in a read() without
      losing information.

      If {MAX_CANON} is defined for this terminal device, it shall be a
      limit on the number of bytes in a line. The behavior of the system
      when this limit is exceeded is implementation-defined.


In other words, while processing input in canonical mode, the system may
discard input in excess of MAX_CANON until a NL character is received.
Linux defines MAX_CANON as 255.


> Also, consider the readline use cases. bash, for instance, uses readline to
> process the command lines entered, but needs to change the termios to a
> canonical mode for each entered command. I would expect that pasting a
> sequence of commands (of 4K, which is not even 'a lot') to work.
>
> The same is true for psql, where users might paste several KB of queries, or
> almost every readline enabled "shell".
>
>> readline() saves and restores the termios settings for each input
>> line it reads. However, tty i/o is asynchronous in the kernel.
>> This means that when readline() restores the original termios
>> settings, any new data received by the tty will be interpreted
>> with the current, original termios settings.
>
>> When a large paste happens, the tty/line discipline read buffer
>> quickly fills up (to 4k). When full, further input is forced to
>> wait. After readline() reads an input line, more space becomes
>> available in the read buffer. Unfortunately, this event roughly
>> coincides with restoring the original termios settings, and
>> thus increases the probability that more paste data will be
>> received with the wrong termios settings.
>
>> That's why the patches that involve scheduling the receive
>> buffer work seem to have some effect on the outcome.
>
> It's not totally clear to me why receiving characters with the wrong termios
> settings might lead to this characters being dropped when reading them with
> different settings.

Many termios settings are applied when the input is received rather than when
the application reads them.

Here's an example sequence:

1. termios is set to non-canonical mode
2. the input buffer is filled with paste data (although unknown to the kernel
    there is more paste data which has not yet been received). The paste data
    contains CR as line delimiter.
3. the input buffer is read character-by-character until the first CR is found.
4. termios is set to canonical mode but ICRNL is not set.
5. the writer thread is woken because more space has become available in the
    input buffer.
6. more paste data is received in canonical mode but a NL cannot be found
    (because there are only CRs in the paste data).
7. the system discards this input to prevent already received data from being
    overrun and continues to do so until a NL is found (or termios is set back
    to non-canonical mode).


> I took a deep look into the code, trying to find where was the code that ended
> up dropping characters, but could not find it.
> Could you maybe point me to it?

n_tty_set_room() in drivers/tty/n_tty.c (3.10 mainline)

 From n_tty_set_room():

	/*
	 * 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.
	 */
	if (left <= 0)
		left = ldata->icanon && !ldata->canon_data;
	old_left = tty->receive_room;
	tty->receive_room = left;


The code means that if the input buffer is full and ICANON is set and
a NL has not been received yet, still report that space for 1 char
is available in the input buffer.

When the character is actually received and interpreted, if there is
no space in the input buffer, the character is dropped. If ECHO is set,
a '\a' (bell) is written to the tty's output.


>> As you've already noted, readline() termios settings are
>> substantially different than the default termios settings.
>>
>> Below I've included a simple test jig that
>>    1) sets termios to the same settings as readline()
>>    2) uses the same read() method as readline()
>>    3) outputs what it reads to stdout
>>    4) restores the original termios
>
> I've updated your code the be closer to the readline behaviour.

That's why I wrote the test jig: to show the paste data was
received error-free with _exactly_ the same termios settings
that readline() uses.

Re-introducing setting and unsetting termios simply confirms
what I already diagnosed.

Regards,
Peter Hurley


> readline calls tcsetattr with TCSADRAIN, and not TCSAFLUSH which explictly
> claims to discard the input. I've also reordered the call to process lines,
> and initialized the int c.
>
> --- >% ---
> #include <stdio.h>
> #include <termios.h>
> #include <unistd.h>
> #include <stdlib.h>
>
> void init(int *eof, struct termios* save)
> {
>      int err;
>      static struct termios termios;
>
>      err = tcgetattr(STDIN_FILENO, &termios);
>      if (err < 0)
>          exit(EXIT_FAILURE);
>      *save = termios;
>
>      termios.c_lflag &= ~(ICANON | ECHO | ISIG);
>      termios.c_iflag &= ~(IXON | IXOFF);
>      if ((termios.c_cflag & CSIZE) == CS8)
>          termios.c_iflag &= ~(ISTRIP | INPCK);
>      termios.c_iflag &= ~(ICRNL | INLCR);
>      termios.c_cc[VMIN] = 1;
>      termios.c_cc[VTIME] = 0;
>      termios.c_cc[VLNEXT] = _POSIX_VDISABLE;
>      *eof = termios.c_cc[VEOF];
>
>      err = tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
>      if (err < 0)
>          exit(EXIT_FAILURE);
> }
>
> void deinit(struct termios* termios)
> {
>      int err;
>      err = tcsetattr(STDIN_FILENO, TCSADRAIN, termios);
>      if (err < 0)
>          exit(EXIT_FAILURE);
> }
>
> int main(int argc, char* argv[])
> {
>      int c=0, eof;
>      ssize_t actual;
>      struct termios save;
>
>      while (1) {
>          init(&eof, &save);
>          while (1) {
>              actual = read(fileno(stdin), &c, sizeof(unsigned char));
>              if (actual <= 0)
>                  break;
>              if (actual == sizeof(unsigned char)) {
>                  if (c == eof)
>                      break;
>                  if (c == '\r') {
>                      c = '\n';
>                  }
>                  fputc(c, stdout);
>                  fflush(stdout);
>                  if (c == '\n') break;
>              }
>          }
>          deinit(&save);
>          if (c == eof) break;
>      }
>
>      return 0;
> }
> --- >% ---
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-07-30 16:08     ` Peter Hurley
@ 2013-08-08 17:58       ` Maximiliano Curia
  2013-08-17 15:28         ` Pavel Machek
  2013-08-19 12:25         ` Peter Hurley
  0 siblings, 2 replies; 40+ messages in thread
From: Maximiliano Curia @ 2013-08-08 17:58 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Margarita Manterola, Greg Kroah-Hartman, Jiri Slaby, Linux kernel

[-- Attachment #1: Type: text/plain, Size: 2074 bytes --]

Hi,

> n_tty_set_room() in drivers/tty/n_tty.c (3.10 mainline)

> From n_tty_set_room():

> 	/*
> 	 * 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.
> 	 */
> 	if (left <= 0)
> 		left = ldata->icanon && !ldata->canon_data;
> 	old_left = tty->receive_room;
> 	tty->receive_room = left;

I took a long look at this code and thought about how it could be made to work
for readline's case and also for the canonical readers.  I came up with this
simple patch:

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4bf0fc0..2ba7f4e 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -149,7 +149,8 @@ static int set_room(struct tty_struct *tty)
         * characters will be beeped.
         */
        if (left <= 0)
-               left = ldata->icanon && !ldata->canon_data;
+               if (waitqueue_active(&tty->read_wait))
+                       left = ldata->icanon && !ldata->canon_data;
        old_left = tty->receive_room;
        tty->receive_room = left;

This is of course just an idea, but I tested this and it worked correctly for
the cases I was testing.

The effect of this patch is that when there is a canonical reader waiting for
input, it maintains the previous behavior, but when there's no reader (like
when readline is changing modes), it blocks and doesn't lose any characters.

Another approach would be to recalculate the size of canon_data when the mode
is changed, but this would probably be much more invasive, and awfully less
efficient since it would imply going through the buffer.

What do you think? Is the proposed solution, or something along those lines,
acceptable?

If there are other cases that need to be taken into account and that I
currently don't know about, please let me know.

-- 
"If you think your users are idiots, only idiots will use it."
-- Linus Torvalds
Saludos /\/\ /\ >< `/

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-08-08 17:58       ` Maximiliano Curia
@ 2013-08-17 15:28         ` Pavel Machek
  2013-08-17 22:57           ` Margarita Manterola
  2013-08-19 12:25         ` Peter Hurley
  1 sibling, 1 reply; 40+ messages in thread
From: Pavel Machek @ 2013-08-17 15:28 UTC (permalink / raw)
  To: Maximiliano Curia
  Cc: Peter Hurley, Margarita Manterola, Greg Kroah-Hartman,
	Jiri Slaby, Linux kernel

Hi!

> > n_tty_set_room() in drivers/tty/n_tty.c (3.10 mainline)
> 
> > From n_tty_set_room():
> 
> > 	/*
> > 	 * 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.
> > 	 */
> > 	if (left <= 0)
> > 		left = ldata->icanon && !ldata->canon_data;
> > 	old_left = tty->receive_room;
> > 	tty->receive_room = left;
> 
> I took a long look at this code and thought about how it could be made to work
> for readline's case and also for the canonical readers.  I came up with this
> simple patch:
> 
> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> index 4bf0fc0..2ba7f4e 100644
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -149,7 +149,8 @@ static int set_room(struct tty_struct *tty)
>          * characters will be beeped.
>          */
>         if (left <= 0)
> -               left = ldata->icanon && !ldata->canon_data;
> +               if (waitqueue_active(&tty->read_wait))
> +                       left = ldata->icanon && !ldata->canon_data;
>         old_left = tty->receive_room;
>         tty->receive_room = left;
> 
> This is of course just an idea, but I tested this and it worked correctly for
> the cases I was testing.
> 
> The effect of this patch is that when there is a canonical reader waiting for
> input, it maintains the previous behavior, but when there's no reader (like
> when readline is changing modes), it blocks and doesn't lose any characters.
> 
> Another approach would be to recalculate the size of canon_data when the mode
> is changed, but this would probably be much more invasive, and awfully less
> efficient since it would imply going through the buffer.
> 
> What do you think? Is the proposed solution, or something along those lines,
> acceptable?
> 
> If there are other cases that need to be taken into account and that I
> currently don't know about, please let me know.

Was this applied? You may want to cc rjw... it is a regression, it is
not pretty, and it is something I blieve I hit but thought it was some
kind of "X weirdness".

Thanks,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-08-17 15:28         ` Pavel Machek
@ 2013-08-17 22:57           ` Margarita Manterola
  2013-08-18  8:08             ` Geert Uytterhoeven
  2013-09-03  5:17             ` Arkadiusz Miskiewicz
  0 siblings, 2 replies; 40+ messages in thread
From: Margarita Manterola @ 2013-08-17 22:57 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Maximiliano Curia, Peter Hurley, Greg Kroah-Hartman, Jiri Slaby,
	Linux kernel

Hi,

On Sat, Aug 17, 2013 at 5:28 PM, Pavel Machek <pavel@ucw.cz> wrote:

>> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
>> index 4bf0fc0..2ba7f4e 100644
>> --- a/drivers/tty/n_tty.c
>> +++ b/drivers/tty/n_tty.c
>> @@ -149,7 +149,8 @@ static int set_room(struct tty_struct *tty)
>>          * characters will be beeped.
>>          */
>>         if (left <= 0)
>> -               left = ldata->icanon && !ldata->canon_data;
>> +               if (waitqueue_active(&tty->read_wait))
>> +                       left = ldata->icanon && !ldata->canon_data;
>>         old_left = tty->receive_room;
>>         tty->receive_room = left;

> Was this applied? You may want to cc rjw... it is a regression, it is
> not pretty, and it is something I blieve I hit but thought it was some
> kind of "X weirdness".

There were no replies to the previous mail asking for comments, and as
far as I can see this has not been applied. I don't know who rjw is,
could you be a bit more explicit, please?

-- 
Besos,
Marga

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-08-17 22:57           ` Margarita Manterola
@ 2013-08-18  8:08             ` Geert Uytterhoeven
  2013-09-03  5:17             ` Arkadiusz Miskiewicz
  1 sibling, 0 replies; 40+ messages in thread
From: Geert Uytterhoeven @ 2013-08-18  8:08 UTC (permalink / raw)
  To: Margarita Manterola
  Cc: Pavel Machek, Maximiliano Curia, Peter Hurley,
	Greg Kroah-Hartman, Jiri Slaby, Linux kernel

On Sun, Aug 18, 2013 at 12:57 AM, Margarita Manterola
<margamanterola@gmail.com> wrote:
> There were no replies to the previous mail asking for comments, and as
> far as I can see this has not been applied. I don't know who rjw is,
> could you be a bit more explicit, please?

"git grep rjw MAINTAINERS"

Rafael J. Wysocki <rjw@sisk.pl>

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-08-08 17:58       ` Maximiliano Curia
  2013-08-17 15:28         ` Pavel Machek
@ 2013-08-19 12:25         ` Peter Hurley
  2013-09-03 21:12           ` Maximiliano Curia
  1 sibling, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-08-19 12:25 UTC (permalink / raw)
  To: Maximiliano Curia
  Cc: Margarita Manterola, Greg Kroah-Hartman, Jiri Slaby, Linux kernel

On 08/08/2013 01:58 PM, Maximiliano Curia wrote:
> Hi,
>
>> n_tty_set_room() in drivers/tty/n_tty.c (3.10 mainline)
>
>>  From n_tty_set_room():
>
>> 	/*
>> 	 * 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.
>> 	 */
>> 	if (left <= 0)
>> 		left = ldata->icanon && !ldata->canon_data;
>> 	old_left = tty->receive_room;
>> 	tty->receive_room = left;
>
> I took a long look at this code and thought about how it could be made to work
> for readline's case and also for the canonical readers.  I came up with this
> simple patch:
>
> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> index 4bf0fc0..2ba7f4e 100644
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -149,7 +149,8 @@ static int set_room(struct tty_struct *tty)
>           * characters will be beeped.
>           */
>          if (left <= 0)
> -               left = ldata->icanon && !ldata->canon_data;
> +               if (waitqueue_active(&tty->read_wait))
> +                       left = ldata->icanon && !ldata->canon_data;
>          old_left = tty->receive_room;
>          tty->receive_room = left;
>
> This is of course just an idea, but I tested this and it worked correctly for
> the cases I was testing.
>
> The effect of this patch is that when there is a canonical reader waiting for
> input, it maintains the previous behavior, but when there's no reader (like
> when readline is changing modes), it blocks and doesn't lose any characters.

Apologies for taking so long to reply.

My primary concern is canonical readers not become stuck with a full
read buffer, even with bogus input data (IOW, that an error condition will
not prevent a reader from making forward progress). I believe that won't
happen with this change, but what I really need in this case is a detailed
analysis from you of why that won't happen. That analysis should be in
the patch changelog. (Feel free to send me private mail if you need help
preparing a patch.)

And the patch above has a bug that allows a negative 'left' to be
assigned to tty->receive_room which will be interpreted as a very large
positive value.

This approach still has several drawbacks.

1) Since additional state is reset when the termios is changed by
readline(), the canonical line buffer state will be bogus.
This renders the termios change by readline() pointless; the
caller will not be able to retrieve expected input properly.

2) Since the input data is interpreted with the current termios when
data is received, any embedded control characters will not be
interpreted properly; again, the caller will not be able to retrieve
expected input properly.

> Another approach would be to recalculate the size of canon_data when the mode
> is changed, but this would probably be much more invasive, and awfully less
> efficient since it would imply going through the buffer.

This approach is not possible prior to linux-next since the input worker
thread and the reader thread are not locked out of access to the read buffer
while changing the termios.

And while rescanning the read buffer is possible in linux-next (eg, to
compute the read_flags bitmap indicating the position of NLs), this doesn't
address embedded control characters not being reinterpreted. And completely
reinterpreting the read buffer makes interpreting when receiving pointless.

> What do you think? Is the proposed solution, or something along those lines,
> acceptable?

I'm wondering if this problem might be best addressed on the paste side
instead of the read side. Although this wouldn't be a magic bullet, it
would be easier to control when more paste data is added.

Regards,
Peter Hurley



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-08-17 22:57           ` Margarita Manterola
  2013-08-18  8:08             ` Geert Uytterhoeven
@ 2013-09-03  5:17             ` Arkadiusz Miskiewicz
  2013-10-24 16:00               ` Arkadiusz Miskiewicz
  1 sibling, 1 reply; 40+ messages in thread
From: Arkadiusz Miskiewicz @ 2013-09-03  5:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Margarita Manterola, Pavel Machek, Maximiliano Curia,
	Peter Hurley, Greg Kroah-Hartman, Jiri Slaby

On Sunday 18 of August 2013, Margarita Manterola wrote:
> Hi,
> 
> On Sat, Aug 17, 2013 at 5:28 PM, Pavel Machek <pavel@ucw.cz> wrote:
> >> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> >> index 4bf0fc0..2ba7f4e 100644
> >> --- a/drivers/tty/n_tty.c
> >> +++ b/drivers/tty/n_tty.c
> >> @@ -149,7 +149,8 @@ static int set_room(struct tty_struct *tty)
> >> 
> >>          * characters will be beeped.
> >>          */
> >>         
> >>         if (left <= 0)
> >> 
> >> -               left = ldata->icanon && !ldata->canon_data;
> >> +               if (waitqueue_active(&tty->read_wait))
> >> +                       left = ldata->icanon && !ldata->canon_data;
> >> 
> >>         old_left = tty->receive_room;
> >>         tty->receive_room = left;
> > 
> > Was this applied? You may want to cc rjw... it is a regression, it is
> > not pretty, and it is something I blieve I hit but thought it was some
> > kind of "X weirdness".
> 
> There were no replies to the previous mail asking for comments, and as
> far as I can see this has not been applied. I don't know who rjw is,
> could you be a bit more explicit, please?

Hi.

Was there some kind of continuation of this thread or the thing died 
completly?

-- 
Arkadiusz Miśkiewicz, arekm / maven.pl

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-08-19 12:25         ` Peter Hurley
@ 2013-09-03 21:12           ` Maximiliano Curia
  2013-09-12  1:36             ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Maximiliano Curia @ 2013-09-03 21:12 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Margarita Manterola, Greg Kroah-Hartman, Jiri Slaby, Linux kernel

[-- Attachment #1: Type: text/plain, Size: 3880 bytes --]

¡Hola Peter!

El 2013-08-19 a las 08:25 -0400, Peter Hurley escribió:
> My primary concern is canonical readers not become stuck with a full
> read buffer, even with bogus input data (IOW, that an error condition will
> not prevent a reader from making forward progress). I believe that won't
> happen with this change, but what I really need in this case is a detailed
> analysis from you of why that won't happen. That analysis should be in
> the patch changelog. (Feel free to send me private mail if you need help
> preparing a patch.)

I'm not sure what level of analysis you are looking for. The driver will block
when there are no readers but as soon as there is a read call it unblocks.
I've added this information to the patch description that I'm including below.

> And the patch above has a bug that allows a negative 'left' to be
> assigned to tty->receive_room which will be interpreted as a very large
> positive value.

Ok, fixed with an else clause. It could also use an extra &&, but it looks a
bit confusing.

> This approach still has several drawbacks.

> 1) Since additional state is reset when the termios is changed by
> readline(), the canonical line buffer state will be bogus.
> This renders the termios change by readline() pointless; the
> caller will not be able to retrieve expected input properly.

> 2) Since the input data is interpreted with the current termios when
> data is received, any embedded control characters will not be
> interpreted properly; again, the caller will not be able to retrieve
> expected input properly.

Indeed this is correct, however this is not an issue of this patch but of the
current interaction between the kernel and readline. In order to fix this, the
reading buffer should always be in raw and only when responding to a read call
for canonical mode should it be interpreted. This is a very big change, and
I'm not sure if anybody will be interested in implementing it.

> >What do you think? Is the proposed solution, or something along those lines,
> >acceptable?

> I'm wondering if this problem might be best addressed on the paste side
> instead of the read side. Although this wouldn't be a magic bullet, it
> would be easier to control when more paste data is added.

I don't see how this could work, could you elaborate?

This is the patch proposal, for comments:

From 81afd3b666cbf94bb9923ebf87fb2017a7cd645e Mon Sep 17 00:00:00 2001
From: Maximiliano Curia <maxy@gnuservers.com.ar>
Date: Tue, 3 Sep 2013 22:48:34 +0200
Subject: [PATCH] Only let characters through when there are active readers.

If there is an active reader, previous behavior is in place. When there is no
active reader, input is blocked until the next read call unblocks it.

This fixes a long standing issue with readline when pasting more than 4096
bytes.
---
 drivers/tty/n_tty.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4bf0fc0..cdc3b19 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -147,9 +147,16 @@ static int set_room(struct tty_struct *tty)
 	 * pending newlines, let characters through without limit, so
 	 * that erase characters will be handled.  Other excess
 	 * characters will be beeped.
+	 * If there is no reader waiting for the input, block instead of
+	 * letting the characters through.
 	 */
 	if (left <= 0)
-		left = ldata->icanon && !ldata->canon_data;
+		if (waitqueue_active(&tty->read_wait)) {
+			left = ldata->icanon && !ldata->canon_data;
+		} else {
+			left = 0;
+		}
+
 	old_left = tty->receive_room;
 	tty->receive_room = left;
 
-- 
1.8.4.rc3


-- 
"Always code as if the person who ends up maintaining your code is a violent
psychopath who knows where you live."
-- John Woods
Saludos /\/\ /\ >< `/

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-09-03 21:12           ` Maximiliano Curia
@ 2013-09-12  1:36             ` Peter Hurley
  0 siblings, 0 replies; 40+ messages in thread
From: Peter Hurley @ 2013-09-12  1:36 UTC (permalink / raw)
  To: Maximiliano Curia
  Cc: Margarita Manterola, Greg Kroah-Hartman, Jiri Slaby, Linux kernel

On 09/03/2013 05:12 PM, Maximiliano Curia wrote:
> ¡Hola Peter!
>
> El 2013-08-19 a las 08:25 -0400, Peter Hurley escribió:
>> My primary concern is canonical readers not become stuck with a full
>> read buffer, even with bogus input data (IOW, that an error condition will
>> not prevent a reader from making forward progress). I believe that won't
>> happen with this change, but what I really need in this case is a detailed
>> analysis from you of why that won't happen. That analysis should be in
>> the patch changelog. (Feel free to send me private mail if you need help
>> preparing a patch.)
>
> I'm not sure what level of analysis you are looking for.

For example, why will CPU 0 (the reader) not hang forever under the following
circumstances?

CPU 0                                | CPU 1
                                      |
n_tty_read()                         | n_tty_receive_buf2()
   .                                  |   receive_room
   .                                  |     .
   .                                  |     is waitqueue_active()? no
   add_wait_queue()                   |       .
     .                                |       .
     is input_available_p()?          |       .
       no - schedule_timeout()  <-- reader sleeps

                                      |       .
                                      |       return 0
                                      | exit i/o loop in flush_to_ldisc() work function
                                      |


A complete and detailed analysis would go a long way to getting this patch
accepted. If you show that your patch won't hang readers _and_ fixes the
larger-than-4k-paste bug, then the readline() deficiencies will probably be
overlooked.

> The driver will block
> when there are no readers but as soon as there is a read call it unblocks.
> I've added this information to the patch description that I'm including below.
>
>> And the patch above has a bug that allows a negative 'left' to be
>> assigned to tty->receive_room which will be interpreted as a very large
>> positive value.
>
> Ok, fixed with an else clause. It could also use an extra &&, but it looks a
> bit confusing.
>
>> This approach still has several drawbacks.
>
>> 1) Since additional state is reset when the termios is changed by
>> readline(), the canonical line buffer state will be bogus.
>> This renders the termios change by readline() pointless; the
>> caller will not be able to retrieve expected input properly.
>
>> 2) Since the input data is interpreted with the current termios when
>> data is received, any embedded control characters will not be
>> interpreted properly; again, the caller will not be able to retrieve
>> expected input properly.
>
> Indeed this is correct, however this is not an issue of this patch but of the
> current interaction between the kernel and readline.

My point here was this: the whole point of readline() flipping termios settings
back and forth is to allow readline() to use one setting while the caller
uses a different setting.

If you don't care that the readline() caller doesn't receives its input
properly when pasted, why is the solution to this problem patching the
linux kernel instead of ripping out the termios-flipping that readline()
does?

> In order to fix this, the
> reading buffer should always be in raw and only when responding to a read call
> for canonical mode should it be interpreted. This is a very big change, and
> I'm not sure if anybody will be interested in implementing it.

So the receiver only echoes input once it's been read???  Because if implemented
as you suggest, until the input has been read you wouldn't know what termios
settings to apply for the echoed chars (or even if to echo).

>>> What do you think? Is the proposed solution, or something along those lines,
>>> acceptable?
>
>> I'm wondering if this problem might be best addressed on the paste side
>> instead of the read side. Although this wouldn't be a magic bullet, it
>> would be easier to control when more paste data is added.
>
> I don't see how this could work, could you elaborate?

Well, the vt driver already supports a PASTE_SELECTION ioctl
which bypasses the flip buffers. Something similar might be suitable
for line-oriented pasting, where only one line is written at a time.
I haven't given too much thought to how/what would perform the wake
up of the paster; right now, the vt driver implements unthrottle to
continue pasting.

> This is the patch proposal, for comments:
>
>  From 81afd3b666cbf94bb9923ebf87fb2017a7cd645e Mon Sep 17 00:00:00 2001
> From: Maximiliano Curia <maxy@gnuservers.com.ar>
> Date: Tue, 3 Sep 2013 22:48:34 +0200
> Subject: [PATCH] Only let characters through when there are active readers.
>
> If there is an active reader, previous behavior is in place. When there is no
> active reader, input is blocked until the next read call unblocks it.
>
> This fixes a long standing issue with readline when pasting more than 4096
> bytes.
> ---
>   drivers/tty/n_tty.c | 9 ++++++++-
>   1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> index 4bf0fc0..cdc3b19 100644
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -147,9 +147,16 @@ static int set_room(struct tty_struct *tty)
>   	 * pending newlines, let characters through without limit, so
>   	 * that erase characters will be handled.  Other excess
>   	 * characters will be beeped.
> +	 * If there is no reader waiting for the input, block instead of
> +	 * letting the characters through.
>   	 */
>   	if (left <= 0)
> -		left = ldata->icanon && !ldata->canon_data;
> +		if (waitqueue_active(&tty->read_wait)) {
> +			left = ldata->icanon && !ldata->canon_data;
> +		} else {
> +			left = 0;
> +		}

Style nitpick. Single-line if-else shouldn't have braces.

> +
>   	old_left = tty->receive_room;
>   	tty->receive_room = left;
>
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-09-03  5:17             ` Arkadiusz Miskiewicz
@ 2013-10-24 16:00               ` Arkadiusz Miskiewicz
  2013-10-29 13:50                 ` Maximiliano Curia
  0 siblings, 1 reply; 40+ messages in thread
From: Arkadiusz Miskiewicz @ 2013-10-24 16:00 UTC (permalink / raw)
  To: linux-kernel
  Cc: Margarita Manterola, Pavel Machek, Maximiliano Curia,
	Peter Hurley, Greg Kroah-Hartman, Jiri Slaby, bug-readline,
	Rafael J. Wysocki

On Tuesday 03 of September 2013, Arkadiusz Miskiewicz wrote:
> On Sunday 18 of August 2013, Margarita Manterola wrote:
> > Hi,
> > 
> > On Sat, Aug 17, 2013 at 5:28 PM, Pavel Machek <pavel@ucw.cz> wrote:
> > >> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> > >> index 4bf0fc0..2ba7f4e 100644
> > >> --- a/drivers/tty/n_tty.c
> > >> +++ b/drivers/tty/n_tty.c
> > >> @@ -149,7 +149,8 @@ static int set_room(struct tty_struct *tty)
> > >> 
> > >>          * characters will be beeped.
> > >>          */
> > >>         
> > >>         if (left <= 0)
> > >> 
> > >> -               left = ldata->icanon && !ldata->canon_data;
> > >> +               if (waitqueue_active(&tty->read_wait))
> > >> +                       left = ldata->icanon && !ldata->canon_data;
> > >> 
> > >>         old_left = tty->receive_room;
> > >>         tty->receive_room = left;
> > > 
> > > Was this applied? You may want to cc rjw... it is a regression, it is
> > > not pretty, and it is something I blieve I hit but thought it was some
> > > kind of "X weirdness".
> > 
> > There were no replies to the previous mail asking for comments, and as
> > far as I can see this has not been applied. I don't know who rjw is,
> > could you be a bit more explicit, please?
> 

Hi

Was just going over bug-readline and lkml archives and found no continuation 
of this. 

There was a patch proposed but didn't get applied. 
https://lkml.org/lkml/2013/8/17/31
Maybe it only needs proper patch submission?

Looking from bug-readline archives debugging it took huge amount of work and 
would be sad that all that ended up being wasted.

Whole thread if someone lost it https://lkml.org/lkml/2013/7/25/205

-- 
Arkadiusz Miśkiewicz, arekm / maven.pl

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-10-24 16:00               ` Arkadiusz Miskiewicz
@ 2013-10-29 13:50                 ` Maximiliano Curia
  2013-10-30 11:21                   ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Maximiliano Curia @ 2013-10-29 13:50 UTC (permalink / raw)
  To: Arkadiusz Miskiewicz
  Cc: linux-kernel, Margarita Manterola, Pavel Machek, Peter Hurley,
	Greg Kroah-Hartman, Jiri Slaby, bug-readline, Rafael J. Wysocki

[-- Attachment #1: Type: text/plain, Size: 1170 bytes --]

¡Hola Arkadiusz!

El 2013-10-24 a las 18:00 +0200, Arkadiusz Miskiewicz escribió:
> Was just going over bug-readline and lkml archives and found no continuation
> of this.

> There was a patch proposed but didn't get applied.
> https://lkml.org/lkml/2013/8/17/31
> Maybe it only needs proper patch submission?

The latest patch is: https://lkml.org/lkml/2013/9/3/539

And the latest reply is: https://lkml.org/lkml/2013/9/11/825

Where Peter Hurley suggests that the patch needs a complete and detailed
analysis, but sadly I'm still not sure how to provide it. If anybody is up for
the task, by all means, go ahead.

The patch seems to be applied in the ubuntu kernel without any known issues so
far.

> Looking from bug-readline archives debugging it took huge amount of work and
> would be sad that all that ended up being wasted.

True, but I somehow agree with Peter in that a known bug is better than
applying a fix with unknown consequences, even though I think that
this particular patch won't break anything.

Happy hacking,
-- 
"If you have too many special cases, you are doing it wrong." -- Craig Zarouni
Saludos /\/\ /\ >< `/

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-10-29 13:50                 ` Maximiliano Curia
@ 2013-10-30 11:21                   ` Peter Hurley
  2013-11-17 18:29                     ` Pavel Machek
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-10-30 11:21 UTC (permalink / raw)
  To: Maximiliano Curia, Arkadiusz Miskiewicz
  Cc: linux-kernel, Margarita Manterola, Pavel Machek,
	Greg Kroah-Hartman, Jiri Slaby, bug-readline, Rafael J. Wysocki

On 10/29/2013 09:50 AM, Maximiliano Curia wrote:
> ¡Hola Arkadiusz!
>
> El 2013-10-24 a las 18:00 +0200, Arkadiusz Miskiewicz escribió:
>> Was just going over bug-readline and lkml archives and found no continuation
>> of this.
>
>> There was a patch proposed but didn't get applied.
>> https://lkml.org/lkml/2013/8/17/31
>> Maybe it only needs proper patch submission?
>
> The latest patch is: https://lkml.org/lkml/2013/9/3/539
>
> And the latest reply is: https://lkml.org/lkml/2013/9/11/825
>
> Where Peter Hurley suggests that the patch needs a complete and detailed
> analysis, but sadly I'm still not sure how to provide it. If anybody is up for
> the task, by all means, go ahead.

The analysis is on my TODO list. I'll include it with a proper patch, this or
next weekend.

Regards,
Peter Hurley


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-10-30 11:21                   ` Peter Hurley
@ 2013-11-17 18:29                     ` Pavel Machek
  2013-11-17 21:38                       ` Margarita Manterola
  2013-11-21  5:04                       ` Peter Hurley
  0 siblings, 2 replies; 40+ messages in thread
From: Pavel Machek @ 2013-11-17 18:29 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Maximiliano Curia, Arkadiusz Miskiewicz, linux-kernel,
	Margarita Manterola, Greg Kroah-Hartman, Jiri Slaby,
	bug-readline, Rafael J. Wysocki

Hi!

On Wed 2013-10-30 07:21:13, Peter Hurley wrote:
> On 10/29/2013 09:50 AM, Maximiliano Curia wrote:
> >??Hola Arkadiusz!
> >
> >El 2013-10-24 a las 18:00 +0200, Arkadiusz Miskiewicz escribió:
> >>Was just going over bug-readline and lkml archives and found no continuation
> >>of this.
> >
> >>There was a patch proposed but didn't get applied.
> >>https://lkml.org/lkml/2013/8/17/31
> >>Maybe it only needs proper patch submission?
> >
> >The latest patch is: https://lkml.org/lkml/2013/9/3/539
> >
> >And the latest reply is: https://lkml.org/lkml/2013/9/11/825
> >
> >Where Peter Hurley suggests that the patch needs a complete and detailed
> >analysis, but sadly I'm still not sure how to provide it. If anybody is up for
> >the task, by all means, go ahead.
> 
> The analysis is on my TODO list. I'll include it with a proper patch, this or
> next weekend.

Any news?
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-11-17 18:29                     ` Pavel Machek
@ 2013-11-17 21:38                       ` Margarita Manterola
  2013-11-21  5:04                       ` Peter Hurley
  1 sibling, 0 replies; 40+ messages in thread
From: Margarita Manterola @ 2013-11-17 21:38 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Peter Hurley, Maximiliano Curia, Arkadiusz Miskiewicz,
	Linux kernel, Greg Kroah-Hartman, Jiri Slaby, bug-readline,
	Rafael J. Wysocki

HI,

On Sun, Nov 17, 2013 at 7:29 PM, Pavel Machek <pavel@ucw.cz> wrote:
> Any news?

I'm also not capable of doing the analysis requested, but I want to
add a link for the the fact that Canonical has applied the patch to
the kernels shipped in Ubuntu, and up to now there have been no
reports of problems:

https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1208740

It was applied in Saucy on Sept. 11th. Ported to the previous Ubuntu
versions on Oct. 24th through the "proposed" mechanism (only reaches a
portion of the users).  Released in the official kernels on Nov. 8th.

Since a few days, then, everyone running an updated Ubuntu system,
regardless of the specific version, should have this patch.

-- 
Besos,
Marga

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-11-17 18:29                     ` Pavel Machek
  2013-11-17 21:38                       ` Margarita Manterola
@ 2013-11-21  5:04                       ` Peter Hurley
  2013-11-22 12:57                         ` Peter Hurley
  1 sibling, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-11-21  5:04 UTC (permalink / raw)
  To: Pavel Machek, Maximiliano Curia
  Cc: Arkadiusz Miskiewicz, linux-kernel, Margarita Manterola,
	Greg Kroah-Hartman, Jiri Slaby, bug-readline, Rafael J. Wysocki

On 11/17/2013 01:29 PM, Pavel Machek wrote:
> Hi!
>
> On Wed 2013-10-30 07:21:13, Peter Hurley wrote:
>> On 10/29/2013 09:50 AM, Maximiliano Curia wrote:
>>> ??Hola Arkadiusz!
>>>
>>> El 2013-10-24 a las 18:00 +0200, Arkadiusz Miskiewicz escribió:
>>>> Was just going over bug-readline and lkml archives and found no continuation
>>>> of this.
>>>
>>>> There was a patch proposed but didn't get applied.
>>>> https://lkml.org/lkml/2013/8/17/31
>>>> Maybe it only needs proper patch submission?
>>>
>>> The latest patch is: https://lkml.org/lkml/2013/9/3/539
>>>
>>> And the latest reply is: https://lkml.org/lkml/2013/9/11/825
>>>
>>> Where Peter Hurley suggests that the patch needs a complete and detailed
>>> analysis, but sadly I'm still not sure how to provide it. If anybody is up for
>>> the task, by all means, go ahead.
>>
>> The analysis is on my TODO list. I'll include it with a proper patch, this or
>> next weekend.
>
> Any news?
> 									Pavel
>

A quick overview of the problem and proposed solution:

Larger than 4k pastes immediately fill the line discipline buffer
and trigger an error recovery path which discards input. The error
recovery path exists to avoid wedging userspace when the line
discipline buffer is full but no newline has been received. Without
the error recovery, a canonical (line-by-line) reader will _never_
receive more input when the line discipline buffer is full because,
since no more input will be accepted, no pending newline will
be received, which is a pre-condition for a canonical reader to
read input.

readline() can inadvertently trigger the error recovery path
with pastes larger than 4k because it changes the termios to non-canonical
mode to perform its read() and restores the canonical mode for the caller.
When canonical mode is restored, the error recovery path is triggered and
input is discarded until a newline is received.

The proposed patch below disables the error recovery path unless a blocking
reader/poll is waiting. IOW, if a blocking reader/poll is waiting and the
line discipline buffer is full, input will continue to be accepted but
discarded until a newline is received. If a blocking reader is not waiting,
the receive_buf() worker is aborted and no further input is processed.


From: Maximiliano Curia <maxy@gnuservers.com.ar>
Date: Tue, 3 Sep 2013 22:48:34 +0200
Subject: [PATCH] Only let characters through when there are active readers.

If there is an active reader, previous behavior is in place. When there is no
active reader, input is blocked until the next read call unblocks it.

This fixes a long standing issue with readline when pasting more than 4096
bytes.
---
  drivers/tty/n_tty.c | 9 ++++++++-
  1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4bf0fc0..cdc3b19 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -147,9 +147,16 @@ static int set_room(struct tty_struct *tty)
  	 * pending newlines, let characters through without limit, so
  	 * that erase characters will be handled.  Other excess
  	 * characters will be beeped.
+	 * If there is no reader waiting for the input, block instead of
+	 * letting the characters through.
  	 */
  	if (left <= 0)
-		left = ldata->icanon && !ldata->canon_data;
+		if (waitqueue_active(&tty->read_wait)) {
+			left = ldata->icanon && !ldata->canon_data;
+		} else {
+			left = 0;
+		}
+
  	old_left = tty->receive_room;
  	tty->receive_room = left;

-- 

Analysis:

There are two concerns that require analysis:
1) Does the patch function as designed? and
2) Does the error recovery continue to function as designed? If not, are there
    suitable alternatives?

For the first concern; yes, the patch functions as designed (provided the
departing reader is not on the waitqueue when n_tty_set_room() is called;
currently a patch queued for 3.13 has re-ordered the exit in n_tty_read() so
that would need to be re-re-ordered).

The central concept of the proposed patch is to ensure that the error
recovery path is only evaluated when a read() is in-progress, and thus only when
the termios state corresponding with that read() has already been set.

Also, since a blocking reader will evaluate the buffer state before sleeping,
if the buffer is full, the worker will be started and the error recovery path
correctly triggered, which will in turn re-wake the reader when a newline is
received.

However, error recovery will only continue to function correctly for that
one i/o model, blocking reads.

Users of the signal-driven i/o model would become wedged when the line discipline
buffer is full because there is no thread on the read_wait queue and SIGIO will
no longer be sent.

The non-blocking i/o model also becomes susceptible to wedging, if, for example,
poll() is called _after_ the worker has discovered the buffer is full; poll()
won't see input available and the worker will not be restarted.

ioctl(FIONREAD) will also indicate no input is available; emacs uses this
in conjunction with both select() and SIGIO to determine if a read() is
even necessary.


Other possible solutions:

1) I experimented with forcing would-be readers to accept input from partially
completed lines; that is, to wakeup readers/send SIGIO if the line discipline
buffer is full and return read data as if newline had been received when it
had not. While I got that working, I couldn't really convince myself that
this wouldn't cause buffer overruns or access faults for readers not
expecting lines > 4096.

2) A variation of #1 would be to do the wakeup/send SIGIO but have the
reader discard input instead. Unfortunately, there may not be a newline
in the buffered input, which would require returning an error from
the read; I'm not sure how some apps might interpret that.

3) Simplify the whole process and let user apps get wedged; they can be
un-wedged with tcflush(TCIFLUSH/TCIOFLUSH).

4) Unwedge with a watchdog timer.

5) Something I haven't thought of (like fix console selection ioctls and
use those).

6) Fix this in userspace.


Regards,
Peter Hurley



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-11-21  5:04                       ` Peter Hurley
@ 2013-11-22 12:57                         ` Peter Hurley
  2013-11-24  0:29                           ` One Thousand Gnomes
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-11-22 12:57 UTC (permalink / raw)
  To: Pavel Machek, Maximiliano Curia, Margarita Manterola
  Cc: Arkadiusz Miskiewicz, linux-kernel, Greg Kroah-Hartman,
	Jiri Slaby, bug-readline, Rafael J. Wysocki

On 11/21/2013 12:04 AM, Peter Hurley wrote:
> On 11/17/2013 01:29 PM, Pavel Machek wrote:
>> Hi!
>>
>> On Wed 2013-10-30 07:21:13, Peter Hurley wrote:
>>> On 10/29/2013 09:50 AM, Maximiliano Curia wrote:
>>>> ??Hola Arkadiusz!
>>>>
>>>> El 2013-10-24 a las 18:00 +0200, Arkadiusz Miskiewicz escribió:
>>>>> Was just going over bug-readline and lkml archives and found no continuation
>>>>> of this.
>>>>
>>>>> There was a patch proposed but didn't get applied.
>>>>> https://lkml.org/lkml/2013/8/17/31
>>>>> Maybe it only needs proper patch submission?
>>>>
>>>> The latest patch is: https://lkml.org/lkml/2013/9/3/539
>>>>
>>>> And the latest reply is: https://lkml.org/lkml/2013/9/11/825
>>>>
>>>> Where Peter Hurley suggests that the patch needs a complete and detailed
>>>> analysis, but sadly I'm still not sure how to provide it. If anybody is up for
>>>> the task, by all means, go ahead.
>>>
>>> The analysis is on my TODO list. I'll include it with a proper patch, this or
>>> next weekend.
>>
>> Any news?
>>                                     Pavel
>>
> Other possible solutions:

<...>
7) Rescan line discipline buffer when changing from non-canonical to canonical
mode. The real problem with this approach (besides the inefficiency) is that this
solution could break some (admittedly unknown) program that contrived to exchange
data in non-canonical mode but read in canonical mode (just not exceeding the
line discipline buffer limit).

8) Don't restart the input processing worker with the termios change, but rather
wait for the future reader (which is woken if waiting) to restart input processing
instead (if it needs to).

If signal-driven i/o is being used for this tty, then the input processing worker
is immediately restarted in the line buffer is full. This is necessary to ensure
a full line buffer does not wedge a userspace program using signal-driven i/o
exclusively (because there is no waiting reader).

Similarly, since non-blocking i/o will not have a waiting reader, poll() must
restart the input processing iff there is no input and the tty is in canonical
mode and the line buffer was full. These conditions can only exist immediately
after a termios change (since terminals always start in canonical mode, the
line buffer cannot become full and have no input available without first having
been changed to non-canonical mode and then reset back to canonical mode).

Test patch below

--- >% ---
Subject: [PATCH] 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.

Instead of restarting the input processing worker from the
change in termios, let the waking reader restart the worker.
In this way, the termios set at the time of the actual read() will
apply if/when the worker restarts.

Because signal-driven i/o may not have an active reader to restart
the worker, the change in termios must restart the worker if
O_ASYNC flag was set.

Similarly, because a poll() may not be waiting at the time the
termios is changed, the worker may need to be restarted by the
poll() (if the specific conditions exist; namely, canonical mode
&& no input available && receive buffer was full).

Reported-by: Margarita Manterola <margamanterola@gmail.com>
Cc: Maximiliano Curia <maxy@gnuservers.com.ar>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Arkadiusz Miskiewicz <a.miskiewicz@gmail.com>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
---
  drivers/tty/n_tty.c | 9 ++++++++-
  1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 0f74945..ddc0129 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1809,7 +1809,12 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
  		else
  			ldata->real_raw = 0;
  	}
-	n_tty_set_room(tty);
+
+	/* Only restart worker if tty is using signal-driven i/o.
+	 * Otherwise, let the reader restart the worker
+	 */
+	if (tty->fasync)
+		n_tty_set_room(tty);
  	/*
  	 * Fix tty hang when I_IXON(tty) is cleared, but the tty
  	 * been stopped by STOP_CHAR(tty) before it.
@@ -2393,6 +2398,8 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
  	poll_wait(file, &tty->write_wait, wait);
  	if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
  		mask |= POLLIN | POLLRDNORM;
+	else if (ldata->icanon)
+		n_tty_set_room(tty);
  	if (tty->packet && tty->link->ctrl_status)
  		mask |= POLLPRI | POLLIN | POLLRDNORM;
  	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-- 
1.8.1.2



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-11-22 12:57                         ` Peter Hurley
@ 2013-11-24  0:29                           ` One Thousand Gnomes
  2013-11-24 11:55                             ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: One Thousand Gnomes @ 2013-11-24  0:29 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Pavel Machek, Maximiliano Curia, Margarita Manterola,
	Arkadiusz Miskiewicz, linux-kernel, Greg Kroah-Hartman,
	Jiri Slaby, bug-readline, Rafael J. Wysocki

> 7) Rescan line discipline buffer when changing from non-canonical to canonical
> mode. The real problem with this approach (besides the inefficiency) is that this
> solution could break some (admittedly unknown) program that contrived to exchange
> data in non-canonical mode but read in canonical mode (just not exceeding the
> line discipline buffer limit).

See bugzilla 55981, 55991 btw

Alan

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-11-24  0:29                           ` One Thousand Gnomes
@ 2013-11-24 11:55                             ` Peter Hurley
  2013-11-26  1:16                               ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-11-24 11:55 UTC (permalink / raw)
  To: One Thousand Gnomes
  Cc: Pavel Machek, Maximiliano Curia, Margarita Manterola,
	Arkadiusz Miskiewicz, linux-kernel, Greg Kroah-Hartman,
	Jiri Slaby, bug-readline, Rafael J. Wysocki

On 11/23/2013 07:29 PM, One Thousand Gnomes wrote:
>> 7) Rescan line discipline buffer when changing from non-canonical to canonical
>> mode. The real problem with this approach (besides the inefficiency) is that this
>> solution could break some (admittedly unknown) program that contrived to exchange
>> data in non-canonical mode but read in canonical mode (just not exceeding the
>> line discipline buffer limit).
>
> See bugzilla 55981, 55991 btw

Thanks for the bug references, Alan.

The solution proposed in 55991 (to perform an EOF push when switching from
non-canon to canon) would further break paste to readline().

The caller to readline() may not actually perform any read() but may
simply loop, calling readline();  in this case, when readline()
switches back to non-canonical, it will eventually read the inserted '\0'.
That would be bad.

Regards,
Peter Hurley



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-11-24 11:55                             ` Peter Hurley
@ 2013-11-26  1:16                               ` Peter Hurley
  2013-12-03  0:18                                 ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-11-26  1:16 UTC (permalink / raw)
  To: Margarita Manterola, Maximiliano Curia
  Cc: Pavel Machek, Arkadiusz Miskiewicz, Stas Sergeev,
	One Thousand Gnomes, linux-kernel, Greg Kroah-Hartman,
	Jiri Slaby, Rafael J. Wysocki, Peter Hurley

On 11/24/2013 06:55 AM, Peter Hurley wrote:
> On 11/23/2013 07:29 PM, One Thousand Gnomes wrote:
>>> 7) Rescan line discipline buffer when changing from non-canonical to canonical
>>> mode. The real problem with this approach (besides the inefficiency) is that this
>>> solution could break some (admittedly unknown) program that contrived to exchange
>>> data in non-canonical mode but read in canonical mode (just not exceeding the
>>> line discipline buffer limit).
>>
>> See bugzilla 55981, 55991 btw
>
> Thanks for the bug references, Alan.
>
> The solution proposed in 55991 (to perform an EOF push when switching from
> non-canon to canon) would further break paste to readline().
>
> The caller to readline() may not actually perform any read() but may
> simply loop, calling readline();  in this case, when readline()
> switches back to non-canonical, it will eventually read the inserted '\0'.
> That would be bad.

Stas Sergeev (the reporter of kernel bug# 55991) had proposed a
solution allowing data in the read buffer to become immediately
available for read when switching to canonical mode.

With one minor change, the proposed solution appears to solve the
readline() paste overflow problem (at least, that's the result of
my testing on the test bench originally provided by Margarita
earlier in the thread).

This patch should apply cleanly to 3.13-rc1+ (or to 3.12-final+ with
'git am -C1 <patch_file_name>'.

Please test ASAP as I'd like to see this in 3.13. I'll backport it
to the stable kernels once this is in mainline.

Regards,
Peter Hurley

--- >% ---
Subject: [PATCH v2] 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. canon_copy_to_read_buf()
correctly interprets this condition and will return data in the
read buffer as one line.

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).

Patch based on original proposal and discussion here
https://bugzilla.kernel.org/show_bug.cgi?id=55991
by Stas Sergeev <stsp@users.sourceforge.net>

Reported-by: Margarita Manterola <margamanterola@gmail.com>
Cc: Maximiliano Curia <maxy@gnuservers.com.ar>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Arkadiusz Miskiewicz <a.miskiewicz@gmail.com>
Acked-by: Stas Sergeev <stsp@users.sourceforge.net>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
---
 drivers/tty/n_tty.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 3919ced..2184d7b 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1778,7 +1778,13 @@ 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;
+		if (!L_ICANON(tty) || !read_cnt(ldata))
+			ldata->line_start = ldata->canon_head = ldata->read_tail;
+		else {
+			set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1),
+				ldata->read_flags);
+			ldata->canon_head = ldata->read_head;
+		}
 		ldata->erasing = 0;
 		ldata->lnext = 0;
 	}
@@ -1993,6 +1999,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:
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-11-26  1:16                               ` Peter Hurley
@ 2013-12-03  0:18                                 ` Peter Hurley
  2013-12-03  9:01                                   ` Stas Sergeev
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-12-03  0:18 UTC (permalink / raw)
  To: Margarita Manterola, Maximiliano Curia, Stas Sergeev
  Cc: Pavel Machek, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Peter Hurley

[-- Attachment #1: Type: text/plain, Size: 5717 bytes --]

On 11/25/2013 08:16 PM, Peter Hurley wrote:
> On 11/24/2013 06:55 AM, Peter Hurley wrote:
>> On 11/23/2013 07:29 PM, One Thousand Gnomes wrote:
>>>> 7) Rescan line discipline buffer when changing from non-canonical to canonical
>>>> mode. The real problem with this approach (besides the inefficiency) is that this
>>>> solution could break some (admittedly unknown) program that contrived to exchange
>>>> data in non-canonical mode but read in canonical mode (just not exceeding the
>>>> line discipline buffer limit).
>>>
>>> See bugzilla 55981, 55991 btw
>>
>> Thanks for the bug references, Alan.
>>
>> The solution proposed in 55991 (to perform an EOF push when switching from
>> non-canon to canon) would further break paste to readline().
>>
>> The caller to readline() may not actually perform any read() but may
>> simply loop, calling readline();  in this case, when readline()
>> switches back to non-canonical, it will eventually read the inserted '\0'.
>> That would be bad.
>
> Stas Sergeev (the reporter of kernel bug# 55991) had proposed a
> solution allowing data in the read buffer to become immediately
> available for read when switching to canonical mode.
>
> With one minor change, the proposed solution appears to solve the
> readline() paste overflow problem (at least, that's the result of
> my testing on the test bench originally provided by Margarita
> earlier in the thread).
>
> This patch should apply cleanly to 3.13-rc1+ (or to 3.12-final+ with
> 'git am -C1 <patch_file_name>'.
>
> Please test ASAP as I'd like to see this in 3.13. I'll backport it
> to the stable kernels once this is in mainline.

Unfortunately, this patch breaks EOF push handling.

Normally, when an EOF is found not at the line start, the output
is made available to a canonical reader (without the EOF) -- this is
commonly referred to as EOF push. An EOF at the beginning of a line
forces the read to return 0 bytes read, which the caller interprets
as an end-of-file and discontinues reading.

Since this patch simulates an EOF push, an actual EOF push that
follows will appear to be an EOF at the beginning of a line and
cause read to return 0, thus indicating premature end-of-file.

I've attached a simulation testcase that shows the unexpected EOF.

I think this general approach is still the way forward with this bug
but I need to ponder how the simulated EOF push state can properly be
distinguished from the other eol conditions in canon_copy_from_read_buf()
so line_start is not reset to the read_tail.

Regards,
Peter Hurley

> --- >% ---
> Subject: [PATCH v2] 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. canon_copy_to_read_buf()
> correctly interprets this condition and will return data in the
> read buffer as one line.
>
> 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).
>
> Patch based on original proposal and discussion here
> https://bugzilla.kernel.org/show_bug.cgi?id=55991
> by Stas Sergeev <stsp@users.sourceforge.net>
>
> Reported-by: Margarita Manterola <margamanterola@gmail.com>
> Cc: Maximiliano Curia <maxy@gnuservers.com.ar>
> Cc: Pavel Machek <pavel@ucw.cz>
> Cc: Arkadiusz Miskiewicz <a.miskiewicz@gmail.com>
> Acked-by: Stas Sergeev <stsp@users.sourceforge.net>
> Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
> ---
>   drivers/tty/n_tty.c | 14 +++++++++++++-
>   1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> index 3919ced..2184d7b 100644
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -1778,7 +1778,13 @@ 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;
> +		if (!L_ICANON(tty) || !read_cnt(ldata))
> +			ldata->line_start = ldata->canon_head = ldata->read_tail;
> +		else {
> +			set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1),
> +				ldata->read_flags);
> +			ldata->canon_head = ldata->read_head;
> +		}
>   		ldata->erasing = 0;
>   		ldata->lnext = 0;
>   	}
> @@ -1993,6 +1999,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:
>


[-- Attachment #2: canon_switch2.c --]
[-- Type: text/x-csrc, Size: 3828 bytes --]

/*
 * canon_switch2.c
 *
 * Test read() after non-canon -> canon switch
 *  w/ EOL push immediately after
 *
 *    gcc -Wall -o canon_switch canon_switch.c
 *
 * Based on orginal code by Ilya Zykov <ilya@ilyx.ru>
 */

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <poll.h>
#include <sys/wait.h>

static int fd;

static void error_exit(char *f, ...) {
	va_list va;

	va_start(va, f);
	vprintf(f, va);
	if (errno)
		printf(": %s (code: %d)\n", strerror(errno), errno);
	else
		printf("\n");
	va_end(va);

	if (fd >= 0)
		close(fd);

	exit(EXIT_FAILURE);
}

static void fill_pattern(char *pattern, size_t len) {
	size_t i, n;
	const char test[] = "1234567890";

	n = strlen(test);
	for (i = 0; i <= len - n; i += n)
		strncpy(&pattern[i], test, n);
	strncpy(&pattern[i], test, len % n);
}

int main(int argc, char *argv[]) {
	int child_id;
	char pts_name[24];
	int ptn, unlock = 0;
	struct termios termios, save;

	setbuf(stdout, NULL);

	fd = open("/dev/ptmx", O_RDWR);
	if (fd < 0)
		error_exit("opening pty master");
	if (ioctl(fd, TIOCGPTN, &ptn) < 0)
		error_exit("getting pty #");
	if (ioctl(fd, TIOCSPTLCK, &unlock) < 0)
                error_exit("unlocking pty pair");
        snprintf(pts_name, sizeof(pts_name), "/dev/pts/%d", ptn);

	if (tcgetattr(fd, &termios) < 0)
		error_exit("tcgetattr");
	save = termios;
	termios.c_lflag &= ~(ICANON | ECHO | ISIG);
	termios.c_iflag &= ~(IXON | IXOFF | ICRNL | INLCR);
	if ((termios.c_cflag & CSIZE) == CS8)
		termios.c_cflag &= ~(ISTRIP | INPCK);
	termios.c_cc[VMIN] = 1;
	termios.c_cc[VTIME] = 0;
	termios.c_cc[VLNEXT] = _POSIX_VDISABLE;
	termios.c_oflag &= ~OPOST;
	if (tcsetattr(fd, TCSAFLUSH, &termios) < 0)
		error_exit("tcsetattr master");

	child_id = fork();
	switch (child_id) {
	case -1: error_exit("forking child");

	case 0:	{ /* child */
		printf("Child [%ld] on slave pty %s\n", (long)getpid(), pts_name);

		close(fd);	/* master pty no longer needed */

		fd = open(pts_name, O_RDWR);
		if (fd < 0)
			error_exit("opening pty slave");

		/* wait for master write in non-canon mode */
		{
			struct pollfd pollfds[1] = { { fd, POLLIN },
						   };
			poll(pollfds, 1, -1);
		}

		sleep(1);

		if (tcsetattr(fd, TCSANOW, &save))
			error_exit("tcsetattr restore");

		{
			char buf[8192];
			int n;

			n = read(fd, buf, sizeof(buf));
			if (n < 0)
				error_exit("slave reading");
			printf("read: %d\n", n);
			printf("%.*s", n, buf);

			n = read(fd, buf, sizeof(buf));
			if (n < 0)
				error_exit("slave reading");
			printf("read: %d\n", n);
			if (n == 0)
				error_exit("unexpected EOF");
			printf("%.*s", n, buf);

			n = read(fd, buf, sizeof(buf));
			if (n < 0)
				error_exit("slave reading");
			printf("read: %d\n", n);
			printf("%.*s", n, buf);
		}

		close(fd);
		}
		return 0;

	default: { /* parent */
		int n, id, status, c;

		char pattern[4096];
		char pattern2[] = "The quick brown fox jumped over the lazy dog.\r";

		/* Simulate an input pattern that was supposed to be
		 * all 4096 chars of pattern (which terminates in an EOF push)
		 * but was received as 4095 (because that's the maximum raw mode
		 * allows in the input buffer at once).
		 */
		fill_pattern(pattern, sizeof(pattern));
		pattern[4095] = termios.c_cc[VEOF];
		c = 4096;
		n = write(fd, pattern, c);
		if (n < 0)
			error_exit("master writing");
		printf("write: %d, wrote: %d\n", c, n);

		c = strlen(pattern2);
		n = write(fd, pattern2, c);
		if (n < 0)
			error_exit("master writing");
		printf("write: %d, wrote: %d\n", c, n);

		id = waitpid(child_id, &status, 0);
		if (id < 0 || id != child_id)
			error_exit("waiting for child");
		printf("[%ld] exited status: %d\n", (long) child_id, status);
		}
		return 0;
	}
}

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-12-03  0:18                                 ` Peter Hurley
@ 2013-12-03  9:01                                   ` Stas Sergeev
  2013-12-03 17:00                                     ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Stas Sergeev @ 2013-12-03  9:01 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Margarita Manterola, Maximiliano Curia, Stas Sergeev,
	Pavel Machek, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Caylan Van Larson

03.12.2013 04:18, Peter Hurley пишет:
> Unfortunately, this patch breaks EOF push handling.
>
> Normally, when an EOF is found not at the line start, the output
> is made available to a canonical reader (without the EOF) -- this is
> commonly referred to as EOF push. An EOF at the beginning of a line
> forces the read to return 0 bytes read, which the caller interprets
> as an end-of-file and discontinues reading.
>
> Since this patch simulates an EOF push, an actual EOF push that
> follows will appear to be an EOF at the beginning of a line and
> cause read to return 0, thus indicating premature end-of-file.
>
> I've attached a simulation testcase that shows the unexpected EOF.
>
> I think this general approach is still the way forward with this bug
> but I need to ponder how the simulated EOF push state can properly be
> distinguished from the other eol conditions in canon_copy_from_read_buf()
> so line_start is not reset to the read_tail.
Hi Peter, why do you think this is even a problem?
If you enable icanon and the first thing you did was
to send VEOF, then you need an EOF.
If you want to be backward-compatible, you'll likely need
to go that route, because currently it works exactly that
way, except that the read buffer is lost. Other than preserving
the read buffer, my patch was not supposed to change anything.
I already have a program (written, tested, went to customer,
used in production, oops sorry:) that switches to icanon and
sends VEOF to simulate EOF. If you change this, then the behaviour
will depend on whether the reader happened to read the data
while still in RAW mode or already in icanon mode, which will
create an unfixable race.

I think the only reliable and consistent fix would be to add ioctls
for EOF and EOL pushes. Then people will not even need to switch
back-n-forth like crazy. But as things are now, I think my patch
is conservative and safe. Do you think it can break something real,
other than the test-case? I think your test-case was made with the
particular patch in mind, but it is not compatible with the current
kernel, so it can't be "broken".

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-12-03  9:01                                   ` Stas Sergeev
@ 2013-12-03 17:00                                     ` Peter Hurley
  2013-12-03 19:18                                       ` Stas Sergeev
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-12-03 17:00 UTC (permalink / raw)
  To: Stas Sergeev
  Cc: Margarita Manterola, Maximiliano Curia, Stas Sergeev,
	Pavel Machek, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Caylan Van Larson

On 12/03/2013 04:01 AM, Stas Sergeev wrote:
> 03.12.2013 04:18, Peter Hurley пишет:
>> Unfortunately, this patch breaks EOF push handling.
>>
>> Normally, when an EOF is found not at the line start, the output
>> is made available to a canonical reader (without the EOF) -- this is
>> commonly referred to as EOF push. An EOF at the beginning of a line
>> forces the read to return 0 bytes read, which the caller interprets
>> as an end-of-file and discontinues reading.
>>
>> Since this patch simulates an EOF push, an actual EOF push that
>> follows will appear to be an EOF at the beginning of a line and
>> cause read to return 0, thus indicating premature end-of-file.
>>
>> I've attached a simulation testcase that shows the unexpected EOF.
>>
>> I think this general approach is still the way forward with this bug
>> but I need to ponder how the simulated EOF push state can properly be
>> distinguished from the other eol conditions in canon_copy_from_read_buf()
>> so line_start is not reset to the read_tail.
> Hi Peter, why do you think this is even a problem?
> If you enable icanon and the first thing you did was
> to send VEOF, then you need an EOF.
> If you want to be backward-compatible, you'll likely need
> to go that route, because currently it works exactly that
> way, except that the read buffer is lost. Other than preserving
> the read buffer, my patch was not supposed to change anything.
> I already have a program (written, tested, went to customer,
> used in production, oops sorry:) that switches to icanon and
> sends VEOF to simulate EOF. If you change this, then the behaviour
> will depend on whether the reader happened to read the data
> while still in RAW mode or already in icanon mode, which will
> create an unfixable race.
>
> I think the only reliable and consistent fix would be to add ioctls
> for EOF and EOL pushes. Then people will not even need to switch
> back-n-forth like crazy. But as things are now, I think my patch
> is conservative and safe. Do you think it can break something real,
> other than the test-case? I think your test-case was made with the
> particular patch in mind, but it is not compatible with the current
> kernel, so it can't be "broken".

Stas,

Any unit test is specifically designed to break the code under test.
This unit test does in fact break a possible input: note specifically
that the writer is not changing the termios so has no control over
the timing of when the input is received.

Also note that the test is a simulation; the patch will break any
input stream under the following conditions:
1. The writer writes an EOF-terminated buffer
2. All the input is received _except_ the EOF; this is strictly
    timing-related and not controllable.
3. The reader changes the termios from non-canon -> canon.

At that point the damage is done; the read_flags will indicate
2 EOFs and the 2nd EOF will be interpreted as end-of-file because
it will appear to begin on a new line.

That said, this problem is definitely solvable; I'm just looking
for the best way to solve it.

Consider the total brute-force approach; a shadow read_flags that
distinguishes a real EOF receive from the fake EOF push initiated
by the patch. That would work, but I'm looking for a solution more
space-efficient and simpler than a duplicate 256-byte buffer :)

Regards,
Peter Hurley


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-12-03 17:00                                     ` Peter Hurley
@ 2013-12-03 19:18                                       ` Stas Sergeev
  2013-12-03 23:53                                         ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Stas Sergeev @ 2013-12-03 19:18 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Margarita Manterola, Maximiliano Curia, Stas Sergeev,
	Pavel Machek, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Caylan Van Larson

03.12.2013 21:00, Peter Hurley пишет:
> Any unit test is specifically designed to break the code under test.
> This unit test does in fact break a possible input: note specifically
> that the writer is not changing the termios so has no control over
> the timing of when the input is received.
>
> Also note that the test is a simulation; the patch will break any
> input stream under the following conditions:
> 1. The writer writes an EOF-terminated buffer
> 2. All the input is received _except_ the EOF; this is strictly
>    timing-related and not controllable.
> 3. The reader changes the termios from non-canon -> canon.
>
> At that point the damage is done; the read_flags will indicate
> 2 EOFs and the 2nd EOF will be interpreted as end-of-file because
> it will appear to begin on a new line.
How is this different from the unpatched kernel?
In the unpatched kernel, if you happen on reader side
to enable icanon while n_tty received all but VEOF (is this possible at 
all?),
then the buffer will be flushed, and the remaining VEOF
will get you a nice EOF.
So, in the unpatched kernel you get EOF because the buffer
gets wiped.
On patched kernel you get EOF because of 2 consequitive marks
in read_flags.
This is intentional, for backward compatibility.
What is the problem with that, why do you call it a breakage?
Or am I misreading the scenario you describe?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-12-03 19:18                                       ` Stas Sergeev
@ 2013-12-03 23:53                                         ` Peter Hurley
  2013-12-04 18:57                                           ` Stas Sergeev
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-12-03 23:53 UTC (permalink / raw)
  To: Stas Sergeev
  Cc: Margarita Manterola, Maximiliano Curia, Stas Sergeev,
	Pavel Machek, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Caylan Van Larson

On 12/03/2013 02:18 PM, Stas Sergeev wrote:
> 03.12.2013 21:00, Peter Hurley пишет:
>> Any unit test is specifically designed to break the code under test.
>> This unit test does in fact break a possible input: note specifically
>> that the writer is not changing the termios so has no control over
>> the timing of when the input is received.
>>
>> Also note that the test is a simulation; the patch will break any
>> input stream under the following conditions:
>> 1. The writer writes an EOF-terminated buffer
>> 2. All the input is received _except_ the EOF; this is strictly
>>    timing-related and not controllable.
>> 3. The reader changes the termios from non-canon -> canon.
>>
>> At that point the damage is done; the read_flags will indicate
>> 2 EOFs and the 2nd EOF will be interpreted as end-of-file because
>> it will appear to begin on a new line.
> How is this different from the unpatched kernel?
> In the unpatched kernel, if you happen on reader side
> to enable icanon while n_tty received all but VEOF (is this possible at all?),
> then the buffer will be flushed, and the remaining VEOF
> will get you a nice EOF.
> So, in the unpatched kernel you get EOF because the buffer
> gets wiped.

???

Testcase output from 3.12 w/o patch:

write: 4096, wrote: 4096
write: 46, wrote: 46
Child [4444] on slave pty /dev/pts/1
read: 4095
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345read: 
46
The quick brown fox jumped over the lazy dog.

This output is correct (child had to be terminated
because there is no 3rd read data.)



Testcase output from 3.12 w/patch:

write: 4096, wrote: 4096
write: 46, wrote: 46
Child [9453] on slave pty /dev/pts/2
read: 4095
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345read: 
0
unexpected EOF
[9453] exited status: 256


> On patched kernel you get EOF because of 2 consequitive marks
> in read_flags.
> This is intentional, for backward compatibility.
> What is the problem with that, why do you call it a breakage?
> Or am I misreading the scenario you describe?


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-12-03 23:53                                         ` Peter Hurley
@ 2013-12-04 18:57                                           ` Stas Sergeev
  2013-12-09 14:50                                             ` [PATCH v3] n_tty: Fix buffer overruns with larger-than-4k pastes Peter Hurley
  2014-01-28 12:03                                             ` Large pastes into readline enabled programs causes breakage from v2.6.31 onwards Pavel Machek
  0 siblings, 2 replies; 40+ messages in thread
From: Stas Sergeev @ 2013-12-04 18:57 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Margarita Manterola, Maximiliano Curia, Stas Sergeev,
	Pavel Machek, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Caylan Van Larson

04.12.2013 03:53, Peter Hurley пишет:
> On 12/03/2013 02:18 PM, Stas Sergeev wrote:
>> 03.12.2013 21:00, Peter Hurley пишет:
>>> Any unit test is specifically designed to break the code under test.
>>> This unit test does in fact break a possible input: note specifically
>>> that the writer is not changing the termios so has no control over
>>> the timing of when the input is received.
>>>
>>> Also note that the test is a simulation; the patch will break any
>>> input stream under the following conditions:
>>> 1. The writer writes an EOF-terminated buffer
>>> 2. All the input is received _except_ the EOF; this is strictly
>>>    timing-related and not controllable.
>>> 3. The reader changes the termios from non-canon -> canon.
>>>
>>> At that point the damage is done; the read_flags will indicate
>>> 2 EOFs and the 2nd EOF will be interpreted as end-of-file because
>>> it will appear to begin on a new line.
>> How is this different from the unpatched kernel?
>> In the unpatched kernel, if you happen on reader side
>> to enable icanon while n_tty received all but VEOF (is this possible 
>> at all?),
>> then the buffer will be flushed, and the remaining VEOF
>> will get you a nice EOF.
>> So, in the unpatched kernel you get EOF because the buffer
>> gets wiped.
>
> ???
>
> Testcase output from 3.12 w/o patch:
OK, sorry, after a year of rot of my patch in bugzilla, I've
completely forgot the pre-conditions, which is that the
buffer is not discarded, just not pushed.

> Consider the total brute-force approach; a shadow read_flags that
> distinguishes a real EOF receive from the fake EOF push initiated
> by the patch.
What is to do with them?
Remove all "fake" EOFs on receiving the real one?
But that will depend on whether the reader happened to
read everything before the real one arrived.
I think that changing termios on reader side while another
process is writing, is full of surprises. For example, even in
your test-case (without the patch) the writer could expect
that the reader would receive the VEOF char in raw mode.
But the reader switced icanon and the VEOF char is not being read.
And I am sure there are other oddities to suspect, so why
the unexpected EOF is any worse?

> That would work, but I'm looking for a solution more
> space-efficient and simpler than a duplicate 256-byte buffer 
I think "fake" EOFs do not need the entire bitmap.
It is only important to remember the position where icanon was
enabled the last time I suppose, even if it was switched many
times.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v3] n_tty: Fix buffer overruns with larger-than-4k pastes
  2013-12-04 18:57                                           ` Stas Sergeev
@ 2013-12-09 14:50                                             ` Peter Hurley
       [not found]                                               ` <52A5EF3F.2070805@list.ru>
  2014-01-28 12:03                                             ` Large pastes into readline enabled programs causes breakage from v2.6.31 onwards Pavel Machek
  1 sibling, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-12-09 14:50 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Margarita Manterola, Maximiliano Curia, Stas Sergeev
  Cc: Pavel Machek, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Caylan Van Larson, Peter Hurley

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. canon_copy_to_read_buf()
correctly interprets this condition and will return data in the
read buffer as one line.

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).

Patch based on original proposal and discussion here
https://bugzilla.kernel.org/show_bug.cgi?id=55991
by Stas Sergeev <stsp@users.sourceforge.net>

Reported-by: Margarita Manterola <margamanterola@gmail.com>
Cc: Maximiliano Curia <maxy@gnuservers.com.ar>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Arkadiusz Miskiewicz <a.miskiewicz@gmail.com>
Acked-by: Stas Sergeev <stsp@users.sourceforge.net>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
---

v3 - Fix false-positive end-of-file indication when an actual
     EOF push coincidentally happens to be the next input
     char (but not @ line start)

 drivers/tty/n_tty.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 0f74945..e9e3e52 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -104,6 +104,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];
@@ -1755,7 +1756,15 @@ 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;
+		if (!L_ICANON(tty) || !read_cnt(ldata)) {
+			ldata->line_start = 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;
 	}
@@ -1958,6 +1967,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:
@@ -2007,6 +2022,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
 	if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
 		n--;
 		eof_push = !n && ldata->read_tail != ldata->line_start;
+		ldata->push = 0;
 	}
 
 	n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n",
@@ -2031,7 +2047,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;
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v3] n_tty: Fix buffer overruns with larger-than-4k pastes
       [not found]                                               ` <52A5EF3F.2070805@list.ru>
@ 2013-12-09 17:10                                                 ` Peter Hurley
  2013-12-10  6:15                                                   ` Stas Sergeev
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-12-09 17:10 UTC (permalink / raw)
  To: Stas Sergeev
  Cc: Greg Kroah-Hartman, Margarita Manterola, Maximiliano Curia,
	Stas Sergeev, Pavel Machek, Arkadiusz Miskiewicz,
	One Thousand Gnomes, linux-kernel, Caylan Van Larson

On 12/09/2013 11:26 AM, Stas Sergeev wrote:
> 09.12.2013 18:50, Peter Hurley пишет:
>>   	if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
>>   		n--;
>>   		eof_push = !n && ldata->read_tail != ldata->line_start;
>> +		ldata->push = 0;
>>   	}
> Will this work if the last (and only) char written in raw
> mode appear to be \0 (__DISABLED_CHAR)?

That would have triggered an EOF in older kernels so not a
regression.

>
>> -		ldata->line_start = ldata->read_tail;
>> +		if (!ldata->push)
>> +			ldata->line_start = ldata->read_tail;
>> +		else
>> +			ldata->push = 0;
> Will this work if more that one "fake" EOF is accumulated
> in bitmap because of multiple icanon switches?

Not possible. The read_flags and push indicator are reset
with icanon -> !icanon switches.

> Also, I am a bit surprised with the presence of the code
> like this:
> ---
>
> |	if  (n>  4096)
> 		n+=  4096;
> |
>
> ---
> Am I the only one thinking it is unclear what it does?
> Doesn't it deserve the comment at least?
>
> Or this:
> ---
>
> |eof_push= !n&&  ldata->read_tail!=  ldata->line_start;|
>
> ---
> If eof_push means that the EOL mark was found not at the
> line start, then it is completely confusing why !n is here
> (one have to read a lot of context to find out why).|||
> When I created the patch, the code was much more easy
> to follow than now.

The previous kernels did byte-by-byte copy with lock/unlock
for every byte, into the input buffer and back out of the input
buffer. Simple, but inefficient.

This version has roughly 4n-2 fewer bus locks. The necessary
unsigned arithmetic and additional condition checks make the
code somewhat more complex.

But please feel free to submit patches that fix or clarify
anything you find.

Regards,
Peter Hurley

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3] n_tty: Fix buffer overruns with larger-than-4k pastes
  2013-12-09 17:10                                                 ` Peter Hurley
@ 2013-12-10  6:15                                                   ` Stas Sergeev
  2013-12-10 22:05                                                     ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Stas Sergeev @ 2013-12-10  6:15 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Greg Kroah-Hartman, Margarita Manterola, Maximiliano Curia,
	Stas Sergeev, Pavel Machek, Arkadiusz Miskiewicz,
	One Thousand Gnomes, linux-kernel, Caylan Van Larson

09.12.2013 21:10, Peter Hurley пишет:
> On 12/09/2013 11:26 AM, Stas Sergeev wrote:
>> 09.12.2013 18:50, Peter Hurley пишет:
>>>       if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
>>>           n--;
>>>           eof_push = !n && ldata->read_tail != ldata->line_start;
>>> +        ldata->push = 0;
>>>       }
>> Will this work if the last (and only) char written in raw
>> mode appear to be \0 (__DISABLED_CHAR)?
>
> That would have triggered an EOF in older kernels so not a
> regression.
I mean the case when icanon is enabled _after_ the
\0 was written. In an unpatched kernel it will not result
in an EOL mark, so I don't expect it to trigger EOF.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3] n_tty: Fix buffer overruns with larger-than-4k pastes
  2013-12-10  6:15                                                   ` Stas Sergeev
@ 2013-12-10 22:05                                                     ` Peter Hurley
  2013-12-10 22:12                                                       ` [PATCH v4] " Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-12-10 22:05 UTC (permalink / raw)
  To: Stas Sergeev
  Cc: Greg Kroah-Hartman, Margarita Manterola, Maximiliano Curia,
	Stas Sergeev, Pavel Machek, Arkadiusz Miskiewicz,
	One Thousand Gnomes, linux-kernel, Caylan Van Larson

On 12/10/2013 01:15 AM, Stas Sergeev wrote:
> 09.12.2013 21:10, Peter Hurley пишет:
>> On 12/09/2013 11:26 AM, Stas Sergeev wrote:
>>> 09.12.2013 18:50, Peter Hurley пишет:
>>>>       if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
>>>>           n--;
>>>>           eof_push = !n && ldata->read_tail != ldata->line_start;
>>>> +        ldata->push = 0;
>>>>       }
>>> Will this work if the last (and only) char written in raw
>>> mode appear to be \0 (__DISABLED_CHAR)?
>>
>> That would have triggered an EOF in older kernels so not a
>> regression.
> I mean the case when icanon is enabled _after_ the
> \0 was written. In an unpatched kernel it will not result
> in an EOL mark, so I don't expect it to trigger EOF.

Right you are, Stas.
I found some other problems as well, so v4 coming.

Regards,
Peter Hurley

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v4] n_tty: Fix buffer overruns with larger-than-4k pastes
  2013-12-10 22:05                                                     ` Peter Hurley
@ 2013-12-10 22:12                                                       ` Peter Hurley
  2013-12-17  0:57                                                         ` Greg Kroah-Hartman
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-12-10 22:12 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Stas Sergeev, Margarita Manterola
  Cc: linux-kernel, One Thousand Gnomes, Caylan Van Larson,
	Peter Hurley, Maximiliano Curia, Pavel Machek,
	Arkadiusz Miskiewicz

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@users.sourceforge.net>

Reported-by: Margarita Manterola <margamanterola@gmail.com>
Cc: Maximiliano Curia <maxy@gnuservers.com.ar>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Arkadiusz Miskiewicz <a.miskiewicz@gmail.com>
Acked-by: Stas Sergeev <stsp@users.sourceforge.net>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
---

v3 - Fix false-positive end-of-file indication when an actual
     EOF push coincidentally happens to be the next input
     char (but not @ line start)

v4 - Always reset line_start to read_tail when changing icanon
   - Reset 'fake' EOF push status when flushing buffers
   - Allow '\0' written in non-canon to be read in canon
     (preserves existing userspace-visible behavior)

 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 669a507..1a25552 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];
@@ -341,6 +342,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)
@@ -1758,7 +1760,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;
 	}
@@ -1964,6 +1975,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:
@@ -2010,7 +2027,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;
 	}
@@ -2037,7 +2054,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;
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v4] n_tty: Fix buffer overruns with larger-than-4k pastes
  2013-12-10 22:12                                                       ` [PATCH v4] " Peter Hurley
@ 2013-12-17  0:57                                                         ` Greg Kroah-Hartman
  2013-12-17  1:24                                                           ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Greg Kroah-Hartman @ 2013-12-17  0:57 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Stas Sergeev, Margarita Manterola, linux-kernel,
	One Thousand Gnomes, Caylan Van Larson, Maximiliano Curia,
	Pavel Machek, Arkadiusz Miskiewicz

On Tue, Dec 10, 2013 at 05:12:02PM -0500, Peter Hurley wrote:
> 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@users.sourceforge.net>
> 
> Reported-by: Margarita Manterola <margamanterola@gmail.com>
> Cc: Maximiliano Curia <maxy@gnuservers.com.ar>
> Cc: Pavel Machek <pavel@ucw.cz>
> Cc: Arkadiusz Miskiewicz <a.miskiewicz@gmail.com>
> Acked-by: Stas Sergeev <stsp@users.sourceforge.net>
> Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
> ---

Is this a 3.13-final thing, or can it wait for 3.14-rc1?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4] n_tty: Fix buffer overruns with larger-than-4k pastes
  2013-12-17  0:57                                                         ` Greg Kroah-Hartman
@ 2013-12-17  1:24                                                           ` Peter Hurley
  2013-12-18 11:48                                                             ` Henrique de Moraes Holschuh
  0 siblings, 1 reply; 40+ messages in thread
From: Peter Hurley @ 2013-12-17  1:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Stas Sergeev, Margarita Manterola, linux-kernel,
	One Thousand Gnomes, Caylan Van Larson, Maximiliano Curia,
	Pavel Machek, Arkadiusz Miskiewicz

On 12/16/2013 07:57 PM, Greg Kroah-Hartman wrote:
> On Tue, Dec 10, 2013 at 05:12:02PM -0500, Peter Hurley wrote:
>> 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@users.sourceforge.net>
>>
>> Reported-by: Margarita Manterola <margamanterola@gmail.com>
>> Cc: Maximiliano Curia <maxy@gnuservers.com.ar>
>> Cc: Pavel Machek <pavel@ucw.cz>
>> Cc: Arkadiusz Miskiewicz <a.miskiewicz@gmail.com>
>> Acked-by: Stas Sergeev <stsp@users.sourceforge.net>
>> Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
>> ---
>
> Is this a 3.13-final thing, or can it wait for 3.14-rc1?

Definitely not 3.13 at this point -- it should go to -next.

Regards,
Peter Hurley


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4] n_tty: Fix buffer overruns with larger-than-4k pastes
  2013-12-17  1:24                                                           ` Peter Hurley
@ 2013-12-18 11:48                                                             ` Henrique de Moraes Holschuh
  2013-12-18 13:41                                                               ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Henrique de Moraes Holschuh @ 2013-12-18 11:48 UTC (permalink / raw)
  To: linux-kernel

On Mon, 16 Dec 2013, Peter Hurley wrote:
> >Is this a 3.13-final thing, or can it wait for 3.14-rc1?
> 
> Definitely not 3.13 at this point -- it should go to -next.

Please earmark it for stable, if possible. This fixes a rather annoying long
time bug, after all...

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4] n_tty: Fix buffer overruns with larger-than-4k pastes
  2013-12-18 11:48                                                             ` Henrique de Moraes Holschuh
@ 2013-12-18 13:41                                                               ` Peter Hurley
  0 siblings, 0 replies; 40+ messages in thread
From: Peter Hurley @ 2013-12-18 13:41 UTC (permalink / raw)
  To: Henrique de Moraes Holschuh, linux-kernel; +Cc: Greg KH

On 12/18/2013 06:48 AM, Henrique de Moraes Holschuh wrote:
> On Mon, 16 Dec 2013, Peter Hurley wrote:
>>> Is this a 3.13-final thing, or can it wait for 3.14-rc1?
>>
>> Definitely not 3.13 at this point -- it should go to -next.
>
> Please earmark it for stable, if possible. This fixes a rather annoying long
> time bug, after all...

There is a (unlikely) possibility that this will cause a regression
in userspace (because this causes a successful read() to return when
it would not have in prior kernels).

I'd like to see this survive into 3.14-rc5+ before this goes to 3.12
& 3.13 -stable.

This will need multiple, different backports for pre-3.12 kernels,
which may not work correctly because pre-3.12 didn't lock out the input
processing worker during termios changes.

Regards,
Peter Hurley



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2013-12-04 18:57                                           ` Stas Sergeev
  2013-12-09 14:50                                             ` [PATCH v3] n_tty: Fix buffer overruns with larger-than-4k pastes Peter Hurley
@ 2014-01-28 12:03                                             ` Pavel Machek
  2014-01-28 12:17                                               ` Stas Sergeev
  1 sibling, 1 reply; 40+ messages in thread
From: Pavel Machek @ 2014-01-28 12:03 UTC (permalink / raw)
  To: Stas Sergeev
  Cc: Peter Hurley, Margarita Manterola, Maximiliano Curia,
	Stas Sergeev, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Caylan Van Larson

Hi!

> >>How is this different from the unpatched kernel?
> >>In the unpatched kernel, if you happen on reader side
> >>to enable icanon while n_tty received all but VEOF (is this
> >>possible at all?),
> >>then the buffer will be flushed, and the remaining VEOF
> >>will get you a nice EOF.
> >>So, in the unpatched kernel you get EOF because the buffer
> >>gets wiped.
> >
> >???
> >
> >Testcase output from 3.12 w/o patch:
> OK, sorry, after a year of rot of my patch in bugzilla, I've
> completely forgot the pre-conditions, which is that the
> buffer is not discarded, just not pushed.
> 
> >Consider the total brute-force approach; a shadow read_flags that
> >distinguishes a real EOF receive from the fake EOF push initiated
> >by the patch.

Was this solved somehow?

Given that it is recent regression, maybe right solution is to do the brute-force patch
now, and worry about effectivity later?

										Pavel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2014-01-28 12:03                                             ` Large pastes into readline enabled programs causes breakage from v2.6.31 onwards Pavel Machek
@ 2014-01-28 12:17                                               ` Stas Sergeev
  2014-01-28 13:31                                                 ` Peter Hurley
  0 siblings, 1 reply; 40+ messages in thread
From: Stas Sergeev @ 2014-01-28 12:17 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Peter Hurley, Margarita Manterola, Maximiliano Curia,
	Stas Sergeev, Arkadiusz Miskiewicz, One Thousand Gnomes,
	linux-kernel, Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Caylan Van Larson

28.01.2014 16:03, Pavel Machek пишет:
> Hi!
>
>>>> How is this different from the unpatched kernel?
>>>> In the unpatched kernel, if you happen on reader side
>>>> to enable icanon while n_tty received all but VEOF (is this
>>>> possible at all?),
>>>> then the buffer will be flushed, and the remaining VEOF
>>>> will get you a nice EOF.
>>>> So, in the unpatched kernel you get EOF because the buffer
>>>> gets wiped.
>>> ???
>>>
>>> Testcase output from 3.12 w/o patch:
>> OK, sorry, after a year of rot of my patch in bugzilla, I've
>> completely forgot the pre-conditions, which is that the
>> buffer is not discarded, just not pushed.
>>
>>> Consider the total brute-force approach; a shadow read_flags that
>>> distinguishes a real EOF receive from the fake EOF push initiated
>>> by the patch.
> Was this solved somehow?
Wasn't this already applied?
I think you've missed the part of the discussion thread:
https://groups.google.com/forum/#!msg/linux.kernel/05c-vQUDww4/umXJsD_uiskJ

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: Large pastes into readline enabled programs causes breakage from v2.6.31 onwards
  2014-01-28 12:17                                               ` Stas Sergeev
@ 2014-01-28 13:31                                                 ` Peter Hurley
  0 siblings, 0 replies; 40+ messages in thread
From: Peter Hurley @ 2014-01-28 13:31 UTC (permalink / raw)
  To: Stas Sergeev, Pavel Machek
  Cc: Margarita Manterola, Maximiliano Curia, Stas Sergeev,
	Arkadiusz Miskiewicz, One Thousand Gnomes, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki,
	Caylan Van Larson

On 01/28/2014 07:17 AM, Stas Sergeev wrote:
> 28.01.2014 16:03, Pavel Machek пишет:
>> Hi!
>>
>>>>> How is this different from the unpatched kernel?
>>>>> In the unpatched kernel, if you happen on reader side
>>>>> to enable icanon while n_tty received all but VEOF (is this
>>>>> possible at all?),
>>>>> then the buffer will be flushed, and the remaining VEOF
>>>>> will get you a nice EOF.
>>>>> So, in the unpatched kernel you get EOF because the buffer
>>>>> gets wiped.
>>>> ???
>>>>
>>>> Testcase output from 3.12 w/o patch:
>>> OK, sorry, after a year of rot of my patch in bugzilla, I've
>>> completely forgot the pre-conditions, which is that the
>>> buffer is not discarded, just not pushed.
>>>
>>>> Consider the total brute-force approach; a shadow read_flags that
>>>> distinguishes a real EOF receive from the fake EOF push initiated
>>>> by the patch.
>> Was this solved somehow?
> Wasn't this already applied?

Yes, this was applied and is on the mainline master branch,
so will appear in 3.14-rc1.

Regards,
Peter Hurley


^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2014-01-28 13:31 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-25 11:29 Large pastes into readline enabled programs causes breakage from v2.6.31 onwards Margarita Manterola
2013-07-25 23:09 ` Peter Hurley
2013-07-30 12:41   ` Maximiliano Curia
     [not found]   ` <20130730124117.41DC55E4006@freak.gnuservers.com.ar>
2013-07-30 16:08     ` Peter Hurley
2013-08-08 17:58       ` Maximiliano Curia
2013-08-17 15:28         ` Pavel Machek
2013-08-17 22:57           ` Margarita Manterola
2013-08-18  8:08             ` Geert Uytterhoeven
2013-09-03  5:17             ` Arkadiusz Miskiewicz
2013-10-24 16:00               ` Arkadiusz Miskiewicz
2013-10-29 13:50                 ` Maximiliano Curia
2013-10-30 11:21                   ` Peter Hurley
2013-11-17 18:29                     ` Pavel Machek
2013-11-17 21:38                       ` Margarita Manterola
2013-11-21  5:04                       ` Peter Hurley
2013-11-22 12:57                         ` Peter Hurley
2013-11-24  0:29                           ` One Thousand Gnomes
2013-11-24 11:55                             ` Peter Hurley
2013-11-26  1:16                               ` Peter Hurley
2013-12-03  0:18                                 ` Peter Hurley
2013-12-03  9:01                                   ` Stas Sergeev
2013-12-03 17:00                                     ` Peter Hurley
2013-12-03 19:18                                       ` Stas Sergeev
2013-12-03 23:53                                         ` Peter Hurley
2013-12-04 18:57                                           ` Stas Sergeev
2013-12-09 14:50                                             ` [PATCH v3] n_tty: Fix buffer overruns with larger-than-4k pastes Peter Hurley
     [not found]                                               ` <52A5EF3F.2070805@list.ru>
2013-12-09 17:10                                                 ` Peter Hurley
2013-12-10  6:15                                                   ` Stas Sergeev
2013-12-10 22:05                                                     ` Peter Hurley
2013-12-10 22:12                                                       ` [PATCH v4] " Peter Hurley
2013-12-17  0:57                                                         ` Greg Kroah-Hartman
2013-12-17  1:24                                                           ` Peter Hurley
2013-12-18 11:48                                                             ` Henrique de Moraes Holschuh
2013-12-18 13:41                                                               ` Peter Hurley
2014-01-28 12:03                                             ` Large pastes into readline enabled programs causes breakage from v2.6.31 onwards Pavel Machek
2014-01-28 12:17                                               ` Stas Sergeev
2014-01-28 13:31                                                 ` Peter Hurley
2013-08-19 12:25         ` Peter Hurley
2013-09-03 21:12           ` Maximiliano Curia
2013-09-12  1:36             ` Peter Hurley

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.