proc: proc_skip_spaces() shouldn't think it is working on C strings
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 5 Dec 2022 20:09:06 +0000 (12:09 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 5 Dec 2022 20:09:06 +0000 (12:09 -0800)
proc_skip_spaces() seems to think it is working on C strings, and ends
up being just a wrapper around skip_spaces() with a really odd calling
convention.

Instead of basing it on skip_spaces(), it should have looked more like
proc_skip_char(), which really is the exact same function (except it
skips a particular character, rather than whitespace).  So use that as
inspiration, odd coding and all.

Now the calling convention actually makes sense and works for the
intended purpose.

Reported-and-tested-by: Kyle Zeng <zengyhkyle@gmail.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
kernel/sysctl.c

index 8898dde..c6d9dec 100644 (file)
@@ -267,13 +267,14 @@ int proc_dostring(struct ctl_table *table, int write,
                        ppos);
 }
 
-static size_t proc_skip_spaces(char **buf)
+static void proc_skip_spaces(char **buf, size_t *size)
 {
-       size_t ret;
-       char *tmp = skip_spaces(*buf);
-       ret = tmp - *buf;
-       *buf = tmp;
-       return ret;
+       while (*size) {
+               if (!isspace(**buf))
+                       break;
+               (*size)--;
+               (*buf)++;
+       }
 }
 
 static void proc_skip_char(char **buf, size_t *size, const char v)
@@ -520,7 +521,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
                bool neg;
 
                if (write) {
-                       left -= proc_skip_spaces(&p);
+                       proc_skip_spaces(&p, &left);
 
                        if (!left)
                                break;
@@ -547,7 +548,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
        if (!write && !first && left && !err)
                proc_put_char(&buffer, &left, '\n');
        if (write && !err && left)
-               left -= proc_skip_spaces(&p);
+               proc_skip_spaces(&p, &left);
        if (write && first)
                return err ? : -EINVAL;
        *lenp -= left;
@@ -589,7 +590,7 @@ static int do_proc_douintvec_w(unsigned int *tbl_data,
        if (left > PAGE_SIZE - 1)
                left = PAGE_SIZE - 1;
 
-       left -= proc_skip_spaces(&p);
+       proc_skip_spaces(&p, &left);
        if (!left) {
                err = -EINVAL;
                goto out_free;
@@ -609,7 +610,7 @@ static int do_proc_douintvec_w(unsigned int *tbl_data,
        }
 
        if (!err && left)
-               left -= proc_skip_spaces(&p);
+               proc_skip_spaces(&p, &left);
 
 out_free:
        if (err)
@@ -1074,7 +1075,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
                if (write) {
                        bool neg;
 
-                       left -= proc_skip_spaces(&p);
+                       proc_skip_spaces(&p, &left);
                        if (!left)
                                break;
 
@@ -1103,7 +1104,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
        if (!write && !first && left && !err)
                proc_put_char(&buffer, &left, '\n');
        if (write && !err)
-               left -= proc_skip_spaces(&p);
+               proc_skip_spaces(&p, &left);
        if (write && first)
                return err ? : -EINVAL;
        *lenp -= left;