proc_dostring() bug (hope this isn't repetitive)

Greg Alexander (galexand@sietch.bloomington.in.us)
Thu, 19 Mar 1998 23:03:15 -0500 (EST)


When I do echo hello > /proc/sys/kernel/modprobe, my bash calls write twice:
write(1, "hello", 5) = 5
write(1, "\n", 1) = 1

There's a check in proc_dostring() to bail if filp->f_pos && !write, leading
me to believe that it was intended for filp->f_pos to be handled if (write).
It wasn't, meaning that the second write() overwrote the first. oops. I
just fixed it so that it now uses filp->f_pos correctly. I've tested this
somewhat on my system, but it's fairly simple.
I also made it return somewhat reasonable errors when appropriate --
otherwise a lot of software (i.e.) bash will simply loop until success, very
annoying.

P.S. I just now upgraded to 2.1.90 from 2.0.33 (I last touched base with 2.1
around 2.1.53) and I am very impressed with a lot of aspects of the /proc
layout and many other things that have changed. Good going everyone!

Greg Alexander - also <gralexan@indiana.edu> - http://sietch.home.ml.org/
----
"Any sufficiently advanced bug is indistinguishable from a feature."
-- Rich Kulawiec
-----------------------------------------------------------------------
--- sysctl.c.orig Thu Mar 19 21:37:11 1998
+++ sysctl.c Thu Mar 19 22:59:22 1998
@@ -593,13 +593,20 @@
int len;
char *p, c;

- if (!table->data || !table->maxlen || !*lenp ||
- (filp->f_pos && !write)) {
+ if (!*lenp)
+ return *lenp;
+ if (!table->data || !table->maxlen ||
+ (filp->f_pos && !write)) { /* gives an error on write to avoid looping */
*lenp = 0;
- return 0;
+ return (write)?-ENOSPC:0; /* is this the right error? */
}
-
+
if (write) {
+ if (filp->f_pos >= table->maxlen) {
+ *lenp=0;
+ return -EFBIG; /* is this the right error? */
+ }
+
len = 0;
p = buffer;
while (len < *lenp) {
@@ -609,11 +616,13 @@
break;
len++;
}
- if (len >= table->maxlen)
- len = table->maxlen-1;
- if(copy_from_user(table->data, buffer, len))
+ if (len + filp->f_pos >= table->maxlen)
+ len = table->maxlen - filp->f_pos - 1;
+ if (!len)
+ return 0;
+ if(copy_from_user(((char *)table->data) + filp->f_pos, buffer, len))
return -EFAULT;
- ((char *) table->data)[len] = 0;
+ ((char *) table->data)[len + filp->f_pos] = 0;
filp->f_pos += *lenp;
} else {
len = strlen(table->data);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu