From: Linus Torvalds torvalds@linux-foundation.org
stable inclusion from stable-v5.10.157 commit 9ba389863ac63032d4b6ffad2c90a62cd78082ee category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I65TQE CVE: CVE-2022-4378
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
commit bce9332220bd677d83b19d21502776ad555a0e73 upstream.
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 Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Long Li leo.lilong@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- kernel/sysctl.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 04603d80228e..08b7811187fb 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -397,13 +397,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) @@ -635,7 +636,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; @@ -662,7 +663,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; @@ -704,7 +705,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; @@ -724,7 +725,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) @@ -1182,7 +1183,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;
@@ -1211,7 +1212,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;