From bce9332220bd677d83b19d21502776ad555a0e73 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Mon, 5 Dec 2022 12:09:06 -0800
Subject: [PATCH] proc: proc_skip_spaces() shouldn't think it is working on C strings
Git-commit: bce9332220bd677d83b19d21502776ad555a0e73
Patch-mainline: v6.1
References: CVE-2022-4378 bsc#1206207
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>
Acked-by: Takashi Iwai <tiwai@suse.de>
---
kernel/sysctl.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2169,13 +2169,14 @@ int proc_dostring(struct ctl_table *tabl
(char __user *)buffer, lenp, 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)
@@ -2412,7 +2413,7 @@ static int __do_proc_dointvec(void *tbl_
bool neg;
if (write) {
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (!left)
break;
@@ -2443,7 +2444,7 @@ static int __do_proc_dointvec(void *tbl_
if (!write && !first && left && !err)
err = proc_put_char(&buffer, &left, '\n');
if (write && !err && left)
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (write) {
kfree(kbuf);
if (first)
@@ -2492,7 +2493,7 @@ static int do_proc_douintvec_w(unsigned
if (IS_ERR(kbuf))
return -EINVAL;
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (!left) {
err = -EINVAL;
goto out_free;
@@ -2512,7 +2513,7 @@ static int do_proc_douintvec_w(unsigned
}
if (!err && left)
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
out_free:
kfree(kbuf);
@@ -2926,7 +2927,7 @@ static int __do_proc_doulongvec_minmax(v
if (write) {
bool neg;
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (!left)
break;
@@ -2959,7 +2960,7 @@ static int __do_proc_doulongvec_minmax(v
if (!write && !first && left && !err)
err = proc_put_char(&buffer, &left, '\n');
if (write && !err)
- left -= proc_skip_spaces(&p);
+ proc_skip_spaces(&p, &left);
if (write) {
kfree(kbuf);
if (first)