aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2007-02-10 01:46:38 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 11:18:07 -0800
commit8d06087714b78e8921bd30b5c64202fe80c47339 (patch)
treefc55cbbf9fcdd2f9bed838b073f7828a1e78f636
parentc75fb88dbcc470e6041a20b1457b4835b9a0a48a (diff)
[PATCH] _proc_do_string(): fix short reads
If you try to read things like /proc/sys/kernel/osrelease with single-byte reads, you get just one byte and then EOF. This is because _proc_do_string() assumes that the caller is read()ing into a buffer which is large enough to fit the whole string in a single hit. Fix. Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Michael Tokarev <mjt@tls.msk.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/sysctl.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 84cab0ce44d..e0ac6cd79fc 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1686,13 +1686,12 @@ static int _proc_do_string(void* data, int maxlen, int write,
size_t len;
char __user *p;
char c;
-
- if (!data || !maxlen || !*lenp ||
- (*ppos && !write)) {
+
+ if (!data || !maxlen || !*lenp) {
*lenp = 0;
return 0;
}
-
+
if (write) {
len = 0;
p = buffer;
@@ -1713,6 +1712,15 @@ static int _proc_do_string(void* data, int maxlen, int write,
len = strlen(data);
if (len > maxlen)
len = maxlen;
+
+ if (*ppos > len) {
+ *lenp = 0;
+ return 0;
+ }
+
+ data += *ppos;
+ len -= *ppos;
+
if (len > *lenp)
len = *lenp;
if (len)