Re: [PATCH] sunrpc - fixup userspace buffer possible overrun v2

Previous thread: [PATCH] sunrpc - fixup user buffer overrun on 'transports' statistics by Cyrill Gorcunov on Sunday, August 31, 2008 - 2:37 am. (2 messages)

Next thread: 2.6.26 (x86 vs. x86_64) different /sys directory structure for md? by Justin Piszcz on Sunday, August 31, 2008 - 3:56 am. (1 message)
From: Cyrill Gorcunov
Date: Sunday, August 31, 2008 - 3:08 am

Vegard Nossum reported

David Wagner added (among other things) that copy_to_user could be
probably used here.

The conclusion is that proc_do_xprt doesn't check for userside buffer
size indeed so fix. Also set lenp to number of bytes were really written.

Reported-by: Vegard Nossum <vegard.nossum@gmail.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
CC: David Wagner <daw@cs.berkeley.edu>
---

Please review.

Index: linux-2.6.git/net/sunrpc/sysctl.c
===================================================================
--- linux-2.6.git.orig/net/sunrpc/sysctl.c	2008-08-31 13:43:46.000000000 +0400
+++ linux-2.6.git/net/sunrpc/sysctl.c	2008-08-31 13:58:14.000000000 +0400
@@ -60,23 +60,26 @@ static int proc_do_xprt(ctl_table *table
 			void __user *buffer, size_t *lenp, loff_t *ppos)
 {
 	char tmpbuf[256];
-	int len;
+	size_t len;
+
 	if ((*ppos && !write) || !*lenp) {
 		*lenp = 0;
 		return 0;
 	}
+
 	if (write)
 		return -EINVAL;
 	else {
 		len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
-		if (!access_ok(VERIFY_WRITE, buffer, len))
-			return -EFAULT;
-
-		if (__copy_to_user(buffer, tmpbuf, len))
+		if (len > *lenp)
+			len = *lenp;
+		if (copy_to_user(buffer, tmpbuf, len))
 			return -EFAULT;
 	}
-	*lenp -= len;
+
+	*lenp = len;
 	*ppos += len;
+
 	return 0;
 }
 
--

From: Vegard Nossum
Date: Sunday, August 31, 2008 - 3:35 am

read() returns the correct number of bytes written in to the buffer.
read() does not overwrite the buffer past the length that the user supplied.
Too small buffer results in a partial data.

But trying to call read() twice results in first a partial buffer, then EOF:

open("/proc/sys/sunrpc/transports", O_RDONLY) = 3
read(3, "tc", 2)                        = 2
read(3, "", 2)                          = 0

Maybe this can be fixed later.

Tested-by: Vegard Nossum <vegard.nossum@gmail.com>


Vegard

-- 
"The animistic metaphor of the bug that maliciously sneaked in while
the programmer was not looking is intellectually dishonest as it
disguises that the error is the programmer's own creation."
	-- E. W. Dijkstra, EWD1036
--

From: Ingo Oeser
Date: Sunday, August 31, 2008 - 7:09 am

Hi Cyrill,


Why not use  simple_read_from_buffer() for the read case and

        len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
	ret = simple_read_from_buffer(buffer, ppos, tmpbuf, len);
	if (ret >= 0) {
		*lenp = ret;
		ret = 0;
	}

	return ret;
   }


Best Regards

Ingo Oeser
--

From: Cyrill Gorcunov
Date: Sunday, August 31, 2008 - 7:41 am

[Ingo Oeser - Sun, Aug 31, 2008 at 04:09:10PM +0200]
| Hi Cyrill,
| 
| On Sunday 31 August 2008, Cyrill Gorcunov wrote:
| > The conclusion is that proc_do_xprt doesn't check for userside buffer
| > size indeed so fix. Also set lenp to number of bytes were really written.
| 
| Why not use  simple_read_from_buffer() for the read case and
| keep the -EINVAL for the write case.

Ah, thanks Ingo - good idea. Btw does libfs.c depends
on anything?

| 
| > Reported-by: Vegard Nossum <vegard.nossum@gmail.com>
| > Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
| > CC: David Wagner <daw@cs.berkeley.edu>
| > ---
| > 
| > Please review.
| > 
| > Index: linux-2.6.git/net/sunrpc/sysctl.c
| > ===================================================================
| > --- linux-2.6.git.orig/net/sunrpc/sysctl.c	2008-08-31 13:43:46.000000000 +0400
| > +++ linux-2.6.git/net/sunrpc/sysctl.c	2008-08-31 13:58:14.000000000 +0400
| > @@ -60,23 +60,26 @@ static int proc_do_xprt(ctl_table *table
| >  			void __user *buffer, size_t *lenp, loff_t *ppos)
| >  {
| >  	char tmpbuf[256];
| > -	int len;
| > +	size_t len;
| > +
| + ssize_t ret;
| >  	if ((*ppos && !write) || !*lenp) {
| >  		*lenp = 0;
| >  		return 0;
| >  	}
| > +
| >  	if (write)
| >  		return -EINVAL;
| 
|         len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
| 	ret = simple_read_from_buffer(buffer, ppos, tmpbuf, len);
| 	if (ret >= 0) {
| 		*lenp = ret;
| 		ret = 0;
| 	}
| 
| 	return ret;
|    }
| 
| 
| Best Regards
| 
| Ingo Oeser
| 
		- Cyrill -
--

From: Cyrill Gorcunov
Date: Sunday, August 31, 2008 - 7:44 am

[Cyrill Gorcunov - Sun, Aug 31, 2008 at 06:41:29PM +0400]
| [Ingo Oeser - Sun, Aug 31, 2008 at 04:09:10PM +0200]
| | Hi Cyrill,
| | 
| | On Sunday 31 August 2008, Cyrill Gorcunov wrote:
| | > The conclusion is that proc_do_xprt doesn't check for userside buffer
| | > size indeed so fix. Also set lenp to number of bytes were really written.
| | 
| | Why not use  simple_read_from_buffer() for the read case and
| | keep the -EINVAL for the write case.
| 
| Ah, thanks Ingo - good idea. Btw does libfs.c depends
| on anything?
|
...

yes, it's always compiled in.
 
		- Cyrill -
--

Previous thread: [PATCH] sunrpc - fixup user buffer overrun on 'transports' statistics by Cyrill Gorcunov on Sunday, August 31, 2008 - 2:37 am. (2 messages)

Next thread: 2.6.26 (x86 vs. x86_64) different /sys directory structure for md? by Justin Piszcz on Sunday, August 31, 2008 - 3:56 am. (1 message)