All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
@ 2012-04-20 15:52 ` Emil Goode
  0 siblings, 0 replies; 10+ messages in thread
From: Emil Goode @ 2012-04-20 15:52 UTC (permalink / raw)
  To: gregkh; +Cc: kernel-janitors, linux-kernel, Emil Goode

We should use the get_user macro instead of dereferencing user
pointers directly.

This patch fixes the following sparse warning:
drivers/tty/n_tty.c:1648:51: warning:
	dereference of noderef expression

Signed-off-by: Emil Goode <emilgoode@gmail.com>
---
I'm a newbie so please review carefully.
Not sure if I should add error handling for the get_user call here.

 drivers/tty/n_tty.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94b6eda..5ff63cc 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
 	int retval;
 	size_t n;
 	unsigned long flags;
+	unsigned char ch;
 
 	retval = 0;
 	spin_lock_irqsave(&tty->read_lock, flags);
@@ -1645,7 +1646,8 @@ static int copy_from_read_buf(struct tty_struct *tty,
 		tty->read_cnt -= n;
 		/* Turn single EOF into zero-length read */
 		if (L_EXTPROC(tty) && tty->icanon && n == 1) {
-			if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
+			get_user(ch, b[n-1]);
+			if (!tty->read_cnt && ch == EOF_CHAR(tty))
 				n--;
 		}
 		spin_unlock_irqrestore(&tty->read_lock, flags);
-- 
1.7.9.5


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

* [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
@ 2012-04-20 15:52 ` Emil Goode
  0 siblings, 0 replies; 10+ messages in thread
From: Emil Goode @ 2012-04-20 15:52 UTC (permalink / raw)
  To: gregkh; +Cc: kernel-janitors, linux-kernel, Emil Goode

We should use the get_user macro instead of dereferencing user
pointers directly.

This patch fixes the following sparse warning:
drivers/tty/n_tty.c:1648:51: warning:
	dereference of noderef expression

Signed-off-by: Emil Goode <emilgoode@gmail.com>
---
I'm a newbie so please review carefully.
Not sure if I should add error handling for the get_user call here.

 drivers/tty/n_tty.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94b6eda..5ff63cc 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
 	int retval;
 	size_t n;
 	unsigned long flags;
+	unsigned char ch;
 
 	retval = 0;
 	spin_lock_irqsave(&tty->read_lock, flags);
@@ -1645,7 +1646,8 @@ static int copy_from_read_buf(struct tty_struct *tty,
 		tty->read_cnt -= n;
 		/* Turn single EOF into zero-length read */
 		if (L_EXTPROC(tty) && tty->icanon && n = 1) {
-			if (!tty->read_cnt && (*b)[n-1] = EOF_CHAR(tty))
+			get_user(ch, b[n-1]);
+			if (!tty->read_cnt && ch = EOF_CHAR(tty))
 				n--;
 		}
 		spin_unlock_irqrestore(&tty->read_lock, flags);
-- 
1.7.9.5


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

* Re: [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
  2012-04-20 15:52 ` Emil Goode
@ 2012-04-20 21:00   ` Alan Cox
  -1 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2012-04-20 20:59 UTC (permalink / raw)
  To: Emil Goode; +Cc: gregkh, kernel-janitors, linux-kernel

On Fri, 20 Apr 2012 17:52:34 +0200
Emil Goode <emilgoode@gmail.com> wrote:

> We should use the get_user macro instead of dereferencing user
> pointers directly.
> 
> This patch fixes the following sparse warning:
> drivers/tty/n_tty.c:1648:51: warning:
> 	dereference of noderef expression
> 
> Signed-off-by: Emil Goode <emilgoode@gmail.com>

So I gave it a five second glance and thought "must be a crazy newbie",
then I looked harder 8)

> I'm a newbie so please review carefully.
> Not sure if I should add error handling for the get_user call here.

You are correct, and it's been wrong for ages. You are also the first
person to my knowledge to actually dig into that sparse warning and fix
it!

>  		/* Turn single EOF into zero-length read */
>  		if (L_EXTPROC(tty) && tty->icanon && n = 1) {
> -			if (!tty->read_cnt && (*b)[n-1] = EOF_CHAR(tty))
> +			get_user(ch, b[n-1]);
> +			if (!tty->read_cnt && ch = EOF_CHAR(tty))
>  				n--;
>  		}

The real question is what this code should be doing. The only case it can
be triggered as far as I can see is:

User provides buffer one byte shorter than the size passed to the syscall
Data is copied and copy_to_user returns 1 byte uncopied
n ends up as one

At this point we can take this path. What I don't understand at this
point is what this code path is actually *supposed* to do.

I think it should be testing against the value of n before the n -retval, and also checking the data it copied *from* in kernel space, not
the user size. The user data might be changed by another thread.

First problem therefore is to figure out what this code is supposed to be
doing. However you are right that the code is incorrect, and if it was a
simple bug your fix would also be correct.

It's not simple however, so can anyone work out or remember wtf the code
should be doing ???

Alan

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

* Re: [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
@ 2012-04-20 21:00   ` Alan Cox
  0 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2012-04-20 21:00 UTC (permalink / raw)
  To: Emil Goode; +Cc: gregkh, kernel-janitors, linux-kernel

On Fri, 20 Apr 2012 17:52:34 +0200
Emil Goode <emilgoode@gmail.com> wrote:

> We should use the get_user macro instead of dereferencing user
> pointers directly.
> 
> This patch fixes the following sparse warning:
> drivers/tty/n_tty.c:1648:51: warning:
> 	dereference of noderef expression
> 
> Signed-off-by: Emil Goode <emilgoode@gmail.com>

So I gave it a five second glance and thought "must be a crazy newbie",
then I looked harder 8)

> I'm a newbie so please review carefully.
> Not sure if I should add error handling for the get_user call here.

You are correct, and it's been wrong for ages. You are also the first
person to my knowledge to actually dig into that sparse warning and fix
it!

>  		/* Turn single EOF into zero-length read */
>  		if (L_EXTPROC(tty) && tty->icanon && n == 1) {
> -			if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
> +			get_user(ch, b[n-1]);
> +			if (!tty->read_cnt && ch == EOF_CHAR(tty))
>  				n--;
>  		}

The real question is what this code should be doing. The only case it can
be triggered as far as I can see is:

User provides buffer one byte shorter than the size passed to the syscall
Data is copied and copy_to_user returns 1 byte uncopied
n ends up as one

At this point we can take this path. What I don't understand at this
point is what this code path is actually *supposed* to do.

I think it should be testing against the value of n before the n -=
retval, and also checking the data it copied *from* in kernel space, not
the user size. The user data might be changed by another thread.

First problem therefore is to figure out what this code is supposed to be
doing. However you are right that the code is incorrect, and if it was a
simple bug your fix would also be correct.

It's not simple however, so can anyone work out or remember wtf the code
should be doing ???

Alan

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

* Re: [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
  2012-04-20 21:00   ` Alan Cox
@ 2012-04-21  9:04     ` Jiri Slaby
  -1 siblings, 0 replies; 10+ messages in thread
From: Jiri Slaby @ 2012-04-21  9:04 UTC (permalink / raw)
  To: Alan Cox
  Cc: Emil Goode, gregkh, kernel-janitors, linux-kernel, hyc, Jiri Slaby

On 04/20/2012 11:00 PM, Alan Cox wrote:
> It's not simple however, so can anyone work out or remember wtf the code
> should be doing ???

Huh.

The code was added by:
commit 26df6d13406d1a53b0bda08bd712f1924affd7cd
Author: hyc@symas.com <hyc@symas.com>
Date:   Tue Jun 22 10:14:49 2010 -0700

    tty: Add EXTPROC support for LINEMODE

====

The code is now:

retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n;
if (L_EXTPROC(tty) && tty->icanon && n == 1) {
        if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
                n--;
}

====

n after "n -= retval" means number of successfully copied chars. So the
test "n == 1" along with "!tty->read_cnt" actually should ensure we
copied everything and that is exactly one char. Further we test if that
one is EOF. If so, ignore that char by pretending we copied nothing.

However the implementation does not count with buffer wrapped like:
EOF..........................something
                             ^----- tail

Here, the first call to copy_from_read_buf copies "something" and the
second one is to copy single EOF. But that would be ignored! Is this
expected?


So to fix the user buffer dereference, the following diff should help.
In any case the wrapped buffer is still to be fixed... (Or ignored.)
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
        int retval;
        size_t n;
        unsigned long flags;
+       bool is_eof;

        retval = 0;
        spin_lock_irqsave(&tty->read_lock, flags);
@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct
*tty,
        if (n) {
                retval = copy_to_user(*b,
&tty->read_buf[tty->read_tail], n);
                n -= retval;
+               is_eof = n == 1 &&
+                       tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
                tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
                spin_lock_irqsave(&tty->read_lock, flags);
                tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
                tty->read_cnt -= n;
                /* Turn single EOF into zero-length read */
-               if (L_EXTPROC(tty) && tty->icanon && n == 1) {
-                       if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
-                               n--;
-               }
+               if (L_EXTPROC(tty) && tty->icanon && is_eof &&
!tty->read_cnt)
+                       n = 0;
                spin_unlock_irqrestore(&tty->read_lock, flags);
                *b += n;
                *nr -= n;

thanks,
-- 
js
suse labs

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

* Re: [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
@ 2012-04-21  9:04     ` Jiri Slaby
  0 siblings, 0 replies; 10+ messages in thread
From: Jiri Slaby @ 2012-04-21  9:04 UTC (permalink / raw)
  To: Alan Cox
  Cc: Emil Goode, gregkh, kernel-janitors, linux-kernel, hyc, Jiri Slaby

On 04/20/2012 11:00 PM, Alan Cox wrote:
> It's not simple however, so can anyone work out or remember wtf the code
> should be doing ???

Huh.

The code was added by:
commit 26df6d13406d1a53b0bda08bd712f1924affd7cd
Author: hyc@symas.com <hyc@symas.com>
Date:   Tue Jun 22 10:14:49 2010 -0700

    tty: Add EXTPROC support for LINEMODE

==

The code is now:

retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n;
if (L_EXTPROC(tty) && tty->icanon && n = 1) {
        if (!tty->read_cnt && (*b)[n-1] = EOF_CHAR(tty))
                n--;
}

==

n after "n -= retval" means number of successfully copied chars. So the
test "n = 1" along with "!tty->read_cnt" actually should ensure we
copied everything and that is exactly one char. Further we test if that
one is EOF. If so, ignore that char by pretending we copied nothing.

However the implementation does not count with buffer wrapped like:
EOF..........................something
                             ^----- tail

Here, the first call to copy_from_read_buf copies "something" and the
second one is to copy single EOF. But that would be ignored! Is this
expected?


So to fix the user buffer dereference, the following diff should help.
In any case the wrapped buffer is still to be fixed... (Or ignored.)
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
        int retval;
        size_t n;
        unsigned long flags;
+       bool is_eof;

        retval = 0;
        spin_lock_irqsave(&tty->read_lock, flags);
@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct
*tty,
        if (n) {
                retval = copy_to_user(*b,
&tty->read_buf[tty->read_tail], n);
                n -= retval;
+               is_eof = n = 1 &&
+                       tty->read_buf[tty->read_tail] = EOF_CHAR(tty);
                tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
                spin_lock_irqsave(&tty->read_lock, flags);
                tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
                tty->read_cnt -= n;
                /* Turn single EOF into zero-length read */
-               if (L_EXTPROC(tty) && tty->icanon && n = 1) {
-                       if (!tty->read_cnt && (*b)[n-1] = EOF_CHAR(tty))
-                               n--;
-               }
+               if (L_EXTPROC(tty) && tty->icanon && is_eof &&
!tty->read_cnt)
+                       n = 0;
                spin_unlock_irqrestore(&tty->read_lock, flags);
                *b += n;
                *nr -= n;

thanks,
-- 
js
suse labs

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

* Re: [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
  2012-04-21  9:04     ` Jiri Slaby
@ 2012-04-21 14:04       ` Howard Chu
  -1 siblings, 0 replies; 10+ messages in thread
From: Howard Chu @ 2012-04-21 14:04 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Alan Cox, Emil Goode, gregkh, kernel-janitors, linux-kernel, Jiri Slaby

Jiri Slaby wrote:
> On 04/20/2012 11:00 PM, Alan Cox wrote:
>> It's not simple however, so can anyone work out or remember wtf the code
>> should be doing ???
>
> Huh.
>
> The code was added by:
> commit 26df6d13406d1a53b0bda08bd712f1924affd7cd
> Author: hyc@symas.com<hyc@symas.com>
> Date:   Tue Jun 22 10:14:49 2010 -0700
>
>      tty: Add EXTPROC support for LINEMODE
>
> ====
>
> The code is now:
>
> retval = copy_to_user(*b,&tty->read_buf[tty->read_tail], n);
> n -= retval;
> tty_audit_add_data(tty,&tty->read_buf[tty->read_tail], n);
> spin_lock_irqsave(&tty->read_lock, flags);
> tty->read_tail = (tty->read_tail + n)&  (N_TTY_BUF_SIZE-1);
> tty->read_cnt -= n;
> if (L_EXTPROC(tty)&&  tty->icanon&&  n == 1) {
>          if (!tty->read_cnt&&  (*b)[n-1] == EOF_CHAR(tty))
>                  n--;
> }
>
> ====
>
> n after "n -= retval" means number of successfully copied chars. So the
> test "n == 1" along with "!tty->read_cnt" actually should ensure we
> copied everything and that is exactly one char. Further we test if that
> one is EOF. If so, ignore that char by pretending we copied nothing.

Correct.

> However the implementation does not count with buffer wrapped like:
> EOF..........................something
>                               ^----- tail
>
> Here, the first call to copy_from_read_buf copies "something" and the
> second one is to copy single EOF. But that would be ignored! Is this
> expected?

Hmmm, probably not expected, no. The intent was to pass the EOF character 
through if it's part of a non-empty input line. But if the EOF is the first 
character on an input line, it should be treated as an EOF and no data 
returned from the read.

> So to fix the user buffer dereference, the following diff should help.
> In any case the wrapped buffer is still to be fixed... (Or ignored.)
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
>          int retval;
>          size_t n;
>          unsigned long flags;
> +       bool is_eof;
>
>          retval = 0;
>          spin_lock_irqsave(&tty->read_lock, flags);
> @@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct
> *tty,
>          if (n) {
>                  retval = copy_to_user(*b,
> &tty->read_buf[tty->read_tail], n);
>                  n -= retval;
> +               is_eof = n == 1&&
> +                       tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
>                  tty_audit_add_data(tty,&tty->read_buf[tty->read_tail], n);
>                  spin_lock_irqsave(&tty->read_lock, flags);
>                  tty->read_tail = (tty->read_tail + n)&  (N_TTY_BUF_SIZE-1);
>                  tty->read_cnt -= n;
>                  /* Turn single EOF into zero-length read */
> -               if (L_EXTPROC(tty)&&  tty->icanon&&  n == 1) {
> -                       if (!tty->read_cnt&&  (*b)[n-1] == EOF_CHAR(tty))
> -                               n--;
> -               }
> +               if (L_EXTPROC(tty)&&  tty->icanon&&  is_eof&&
> !tty->read_cnt)
> +                       n = 0;
>                  spin_unlock_irqrestore(&tty->read_lock, flags);
>                  *b += n;
>                  *nr -= n;
>
> thanks,


-- 
   -- Howard Chu
   CTO, Symas Corp.           http://www.symas.com
   Director, Highland Sun     http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP  http://www.openldap.org/project/

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

* Re: [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
@ 2012-04-21 14:04       ` Howard Chu
  0 siblings, 0 replies; 10+ messages in thread
From: Howard Chu @ 2012-04-21 14:04 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Alan Cox, Emil Goode, gregkh, kernel-janitors, linux-kernel, Jiri Slaby

Jiri Slaby wrote:
> On 04/20/2012 11:00 PM, Alan Cox wrote:
>> It's not simple however, so can anyone work out or remember wtf the code
>> should be doing ???
>
> Huh.
>
> The code was added by:
> commit 26df6d13406d1a53b0bda08bd712f1924affd7cd
> Author: hyc@symas.com<hyc@symas.com>
> Date:   Tue Jun 22 10:14:49 2010 -0700
>
>      tty: Add EXTPROC support for LINEMODE
>
> ==
>
> The code is now:
>
> retval = copy_to_user(*b,&tty->read_buf[tty->read_tail], n);
> n -= retval;
> tty_audit_add_data(tty,&tty->read_buf[tty->read_tail], n);
> spin_lock_irqsave(&tty->read_lock, flags);
> tty->read_tail = (tty->read_tail + n)&  (N_TTY_BUF_SIZE-1);
> tty->read_cnt -= n;
> if (L_EXTPROC(tty)&&  tty->icanon&&  n = 1) {
>          if (!tty->read_cnt&&  (*b)[n-1] = EOF_CHAR(tty))
>                  n--;
> }
>
> ==
>
> n after "n -= retval" means number of successfully copied chars. So the
> test "n = 1" along with "!tty->read_cnt" actually should ensure we
> copied everything and that is exactly one char. Further we test if that
> one is EOF. If so, ignore that char by pretending we copied nothing.

Correct.

> However the implementation does not count with buffer wrapped like:
> EOF..........................something
>                               ^----- tail
>
> Here, the first call to copy_from_read_buf copies "something" and the
> second one is to copy single EOF. But that would be ignored! Is this
> expected?

Hmmm, probably not expected, no. The intent was to pass the EOF character 
through if it's part of a non-empty input line. But if the EOF is the first 
character on an input line, it should be treated as an EOF and no data 
returned from the read.

> So to fix the user buffer dereference, the following diff should help.
> In any case the wrapped buffer is still to be fixed... (Or ignored.)
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
>          int retval;
>          size_t n;
>          unsigned long flags;
> +       bool is_eof;
>
>          retval = 0;
>          spin_lock_irqsave(&tty->read_lock, flags);
> @@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct
> *tty,
>          if (n) {
>                  retval = copy_to_user(*b,
> &tty->read_buf[tty->read_tail], n);
>                  n -= retval;
> +               is_eof = n = 1&&
> +                       tty->read_buf[tty->read_tail] = EOF_CHAR(tty);
>                  tty_audit_add_data(tty,&tty->read_buf[tty->read_tail], n);
>                  spin_lock_irqsave(&tty->read_lock, flags);
>                  tty->read_tail = (tty->read_tail + n)&  (N_TTY_BUF_SIZE-1);
>                  tty->read_cnt -= n;
>                  /* Turn single EOF into zero-length read */
> -               if (L_EXTPROC(tty)&&  tty->icanon&&  n = 1) {
> -                       if (!tty->read_cnt&&  (*b)[n-1] = EOF_CHAR(tty))
> -                               n--;
> -               }
> +               if (L_EXTPROC(tty)&&  tty->icanon&&  is_eof&&
> !tty->read_cnt)
> +                       n = 0;
>                  spin_unlock_irqrestore(&tty->read_lock, flags);
>                  *b += n;
>                  *nr -= n;
>
> thanks,


-- 
   -- Howard Chu
   CTO, Symas Corp.           http://www.symas.com
   Director, Highland Sun     http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP  http://www.openldap.org/project/

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

* Re: [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
  2012-04-21 14:04       ` Howard Chu
@ 2012-04-21 14:25         ` Howard Chu
  -1 siblings, 0 replies; 10+ messages in thread
From: Howard Chu @ 2012-04-21 14:25 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Alan Cox, Emil Goode, gregkh, kernel-janitors, linux-kernel, Jiri Slaby

Howard Chu wrote:
> Jiri Slaby wrote:
>> On 04/20/2012 11:00 PM, Alan Cox wrote:
>>> It's not simple however, so can anyone work out or remember wtf the code
>>> should be doing ???
>>
>> Huh.
>>
>> The code was added by:
>> commit 26df6d13406d1a53b0bda08bd712f1924affd7cd
>> Author: hyc@symas.com<hyc@symas.com>
>> Date:   Tue Jun 22 10:14:49 2010 -0700
>>
>>       tty: Add EXTPROC support for LINEMODE
>>
>> ====
>>
>> The code is now:
>>
>> retval = copy_to_user(*b,&tty->read_buf[tty->read_tail], n);
>> n -= retval;
>> tty_audit_add_data(tty,&tty->read_buf[tty->read_tail], n);
>> spin_lock_irqsave(&tty->read_lock, flags);
>> tty->read_tail = (tty->read_tail + n)&   (N_TTY_BUF_SIZE-1);
>> tty->read_cnt -= n;
>> if (L_EXTPROC(tty)&&   tty->icanon&&   n == 1) {
>>           if (!tty->read_cnt&&   (*b)[n-1] == EOF_CHAR(tty))
>>                   n--;
>> }
>>
>> ====
>>
>> n after "n -= retval" means number of successfully copied chars. So the
>> test "n == 1" along with "!tty->read_cnt" actually should ensure we
>> copied everything and that is exactly one char. Further we test if that
>> one is EOF. If so, ignore that char by pretending we copied nothing.
>
> Correct.
>
>> However the implementation does not count with buffer wrapped like:
>> EOF..........................something
>>                                ^----- tail
>>
>> Here, the first call to copy_from_read_buf copies "something" and the
>> second one is to copy single EOF. But that would be ignored! Is this
>> expected?
>
> Hmmm, probably not expected, no. The intent was to pass the EOF character
> through if it's part of a non-empty input line. But if the EOF is the first
> character on an input line, it should be treated as an EOF and no data
> returned from the read.

Been a while since I've thought about this. Perhaps it should simply have 
checked if (tty->read_cnt == 1).

>> So to fix the user buffer dereference, the following diff should help.
>> In any case the wrapped buffer is still to be fixed... (Or ignored.)
>> --- a/drivers/tty/n_tty.c
>> +++ b/drivers/tty/n_tty.c
>> @@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
>>           int retval;
>>           size_t n;
>>           unsigned long flags;
>> +       bool is_eof;
>>
>>           retval = 0;
>>           spin_lock_irqsave(&tty->read_lock, flags);
>> @@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct
>> *tty,
>>           if (n) {
>>                   retval = copy_to_user(*b,
>> &tty->read_buf[tty->read_tail], n);
>>                   n -= retval;
>> +               is_eof = n == 1&&
>> +                       tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
>>                   tty_audit_add_data(tty,&tty->read_buf[tty->read_tail], n);
>>                   spin_lock_irqsave(&tty->read_lock, flags);
>>                   tty->read_tail = (tty->read_tail + n)&   (N_TTY_BUF_SIZE-1);
>>                   tty->read_cnt -= n;
>>                   /* Turn single EOF into zero-length read */
>> -               if (L_EXTPROC(tty)&&   tty->icanon&&   n == 1) {
>> -                       if (!tty->read_cnt&&   (*b)[n-1] == EOF_CHAR(tty))
>> -                               n--;
>> -               }
>> +               if (L_EXTPROC(tty)&&   tty->icanon&&   is_eof&&
>> !tty->read_cnt)
>> +                       n = 0;
>>                   spin_unlock_irqrestore(&tty->read_lock, flags);
>>                   *b += n;
>>                   *nr -= n;
>>
>> thanks,
>
>


-- 
   -- Howard Chu
   CTO, Symas Corp.           http://www.symas.com
   Director, Highland Sun     http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP  http://www.openldap.org/project/

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

* Re: [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer
@ 2012-04-21 14:25         ` Howard Chu
  0 siblings, 0 replies; 10+ messages in thread
From: Howard Chu @ 2012-04-21 14:25 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Alan Cox, Emil Goode, gregkh, kernel-janitors, linux-kernel, Jiri Slaby

Howard Chu wrote:
> Jiri Slaby wrote:
>> On 04/20/2012 11:00 PM, Alan Cox wrote:
>>> It's not simple however, so can anyone work out or remember wtf the code
>>> should be doing ???
>>
>> Huh.
>>
>> The code was added by:
>> commit 26df6d13406d1a53b0bda08bd712f1924affd7cd
>> Author: hyc@symas.com<hyc@symas.com>
>> Date:   Tue Jun 22 10:14:49 2010 -0700
>>
>>       tty: Add EXTPROC support for LINEMODE
>>
>> ==
>>
>> The code is now:
>>
>> retval = copy_to_user(*b,&tty->read_buf[tty->read_tail], n);
>> n -= retval;
>> tty_audit_add_data(tty,&tty->read_buf[tty->read_tail], n);
>> spin_lock_irqsave(&tty->read_lock, flags);
>> tty->read_tail = (tty->read_tail + n)&   (N_TTY_BUF_SIZE-1);
>> tty->read_cnt -= n;
>> if (L_EXTPROC(tty)&&   tty->icanon&&   n = 1) {
>>           if (!tty->read_cnt&&   (*b)[n-1] = EOF_CHAR(tty))
>>                   n--;
>> }
>>
>> ==
>>
>> n after "n -= retval" means number of successfully copied chars. So the
>> test "n = 1" along with "!tty->read_cnt" actually should ensure we
>> copied everything and that is exactly one char. Further we test if that
>> one is EOF. If so, ignore that char by pretending we copied nothing.
>
> Correct.
>
>> However the implementation does not count with buffer wrapped like:
>> EOF..........................something
>>                                ^----- tail
>>
>> Here, the first call to copy_from_read_buf copies "something" and the
>> second one is to copy single EOF. But that would be ignored! Is this
>> expected?
>
> Hmmm, probably not expected, no. The intent was to pass the EOF character
> through if it's part of a non-empty input line. But if the EOF is the first
> character on an input line, it should be treated as an EOF and no data
> returned from the read.

Been a while since I've thought about this. Perhaps it should simply have 
checked if (tty->read_cnt = 1).

>> So to fix the user buffer dereference, the following diff should help.
>> In any case the wrapped buffer is still to be fixed... (Or ignored.)
>> --- a/drivers/tty/n_tty.c
>> +++ b/drivers/tty/n_tty.c
>> @@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
>>           int retval;
>>           size_t n;
>>           unsigned long flags;
>> +       bool is_eof;
>>
>>           retval = 0;
>>           spin_lock_irqsave(&tty->read_lock, flags);
>> @@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct
>> *tty,
>>           if (n) {
>>                   retval = copy_to_user(*b,
>> &tty->read_buf[tty->read_tail], n);
>>                   n -= retval;
>> +               is_eof = n = 1&&
>> +                       tty->read_buf[tty->read_tail] = EOF_CHAR(tty);
>>                   tty_audit_add_data(tty,&tty->read_buf[tty->read_tail], n);
>>                   spin_lock_irqsave(&tty->read_lock, flags);
>>                   tty->read_tail = (tty->read_tail + n)&   (N_TTY_BUF_SIZE-1);
>>                   tty->read_cnt -= n;
>>                   /* Turn single EOF into zero-length read */
>> -               if (L_EXTPROC(tty)&&   tty->icanon&&   n = 1) {
>> -                       if (!tty->read_cnt&&   (*b)[n-1] = EOF_CHAR(tty))
>> -                               n--;
>> -               }
>> +               if (L_EXTPROC(tty)&&   tty->icanon&&   is_eof&&
>> !tty->read_cnt)
>> +                       n = 0;
>>                   spin_unlock_irqrestore(&tty->read_lock, flags);
>>                   *b += n;
>>                   *nr -= n;
>>
>> thanks,
>
>


-- 
   -- Howard Chu
   CTO, Symas Corp.           http://www.symas.com
   Director, Highland Sun     http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP  http://www.openldap.org/project/

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

end of thread, other threads:[~2012-04-21 14:31 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-20 15:52 [PATCH] drivers/tty: Use get_user instead of dereferencing user pointer Emil Goode
2012-04-20 15:52 ` Emil Goode
2012-04-20 20:59 ` Alan Cox
2012-04-20 21:00   ` Alan Cox
2012-04-21  9:04   ` Jiri Slaby
2012-04-21  9:04     ` Jiri Slaby
2012-04-21 14:04     ` Howard Chu
2012-04-21 14:04       ` Howard Chu
2012-04-21 14:25       ` Howard Chu
2012-04-21 14:25         ` Howard Chu

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.