From 794229b5711a96a488d85dd719511a278b4a4956 Mon Sep 17 00:00:00 2001 From: Ryan Sullivan Date: Fri, 27 Jan 2023 11:25:43 -0500 Subject: [KPATCH CVE-2022-4378] kpatch fixes for CVE-2022-4378 Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-7/-/merge_requests/51 Approved-by: Yannick Cote (@ycote1) Approved-by: Joe Lawrence (@joe.lawrence) Kernels: 3.10.0-1160.76.1.el7 3.10.0-1160.80.1.el7 3.10.0-1160.81.1.el7 3.10.0-1160.83.1.el7 Changes since last build: [x86_64]: sysctl.o: changed function: __do_proc_dointvec sysctl.o: changed function: __do_proc_douintvec sysctl.o: changed function: __do_proc_doulongvec_minmax sysctl.o: changed function: proc_dostring sysctl.o: changed function: proc_get_long.constprop.13 [ppc64le]: sysctl.o: changed function: __do_proc_doulongvec_minmax sysctl.o: changed function: proc_do_cad_pid sysctl.o: changed function: proc_dointvec sysctl.o: changed function: proc_dointvec_jiffies sysctl.o: changed function: proc_dointvec_minmax sysctl.o: changed function: proc_dointvec_minmax_coredump sysctl.o: changed function: proc_dointvec_minmax_sysadmin sysctl.o: changed function: proc_dointvec_ms_jiffies sysctl.o: changed function: proc_dointvec_userhz_jiffies sysctl.o: changed function: proc_dopipe_max_size sysctl.o: changed function: proc_dostring sysctl.o: changed function: proc_dostring_coredump sysctl.o: changed function: proc_douintvec sysctl.o: changed function: proc_douintvec_minmax sysctl.o: changed function: proc_doulongvec_minmax sysctl.o: changed function: proc_doulongvec_ms_jiffies_minmax sysctl.o: changed function: proc_get_long.constprop.13 sysctl.o: changed function: sysrq_sysctl_handler sysctl.o: new function: __do_proc_dointvec --------------------------- Modifications: added '__attribute__((optimize("-fno-optimize-sibling-calls")))' to proc_dointvec_jiffies(), proc_dointvec_ms_jiffies(), proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax(), proc_dointvec_userhz_jiffies(), and proc_dointvec() definitions. commit f4f6d6bf0cd6fc3d1b88341f784b2f7e8589ff61 Author: Wander Lairson Costa Date: Tue Dec 13 08:13:31 2022 -0300 proc: avoid integer type confusion in get_proc_long Bugzilla: https://bugzilla.redhat.com/2152565 CVE: CVE-2022-4378 commit e6cfaf34be9fcd1a8285a294e18986bfc41a409c Author: Linus Torvalds Date: Mon Dec 5 11:33:40 2022 -0800 proc: avoid integer type confusion in get_proc_long proc_get_long() is passed a size_t, but then assigns it to an 'int' variable for the length. Let's not do that, even if our IO paths are limited to MAX_RW_COUNT (exactly because of these kinds of type errors). So do the proper test in the rigth type. Reported-by: Kyle Zeng Signed-off-by: Linus Torvalds Signed-off-by: Wander Lairson Costa commit c727ac3f665ed51c096edeedf039552cea6053f6 Author: Wander Lairson Costa Date: Tue Dec 13 08:12:23 2022 -0300 proc: proc_skip_spaces() shouldn't think it is working on C strings Bugzilla: https://bugzilla.redhat.com/2152565 CVE: CVE-2022-4378 Conflicts: some context hunks because we are way behind upstream. commit bce9332220bd677d83b19d21502776ad555a0e73 Author: Linus Torvalds Date: Mon Dec 5 12:09:06 2022 -0800 proc: proc_skip_spaces() shouldn't think it is working on C strings 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 Acked-by: Eric Dumazet Signed-off-by: Linus Torvalds Signed-off-by: Wander Lairson Costa Signed-off-by: Ryan Sullivan --- kernel/sysctl.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 62e2788cf09a..6f7d80afda89 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1999,13 +1999,14 @@ int proc_dostring(struct ctl_table *table, int write, (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) @@ -2074,13 +2075,12 @@ static int proc_get_long(char **buf, size_t *size, unsigned long *val, bool *neg, const char *perm_tr, unsigned perm_tr_len, char *tr) { - int len; char *p, tmp[TMPBUFLEN]; + ssize_t len = *size; - if (!*size) + if (len <= 0) return -EINVAL; - len = *size; if (len > TMPBUFLEN - 1) len = TMPBUFLEN - 1; @@ -2250,7 +2250,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, bool neg; if (write) { - left -= proc_skip_spaces(&kbuf); + proc_skip_spaces(&kbuf, &left); if (!left) break; @@ -2281,7 +2281,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, if (!write && !first && left && !err) err = proc_put_char(&buffer, &left, '\n'); if (write && !err && left) - left -= proc_skip_spaces(&kbuf); + proc_skip_spaces(&kbuf, &left); free: if (write) { free_page(page); @@ -2331,7 +2331,7 @@ static int do_proc_douintvec_w(unsigned int *tbl_data, if (IS_ERR(kbuf)) return -EINVAL; - left -= proc_skip_spaces(&p); + proc_skip_spaces(&p, &left); if (!left) { err = -EINVAL; goto out_free; @@ -2351,7 +2351,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: kfree(kbuf); @@ -2457,6 +2457,7 @@ static int do_proc_douintvec(struct ctl_table *table, int write, * * Returns 0 on success. */ +__attribute__((optimize("-fno-optimize-sibling-calls"))) int proc_dointvec(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2775,7 +2776,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int if (write) { bool neg; - left -= proc_skip_spaces(&kbuf); + proc_skip_spaces(&kbuf, &left); err = proc_get_long(&kbuf, &left, &val, &neg, proc_wspace_sep, @@ -2800,7 +2801,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int if (!write && !first && left && !err) err = proc_put_char(&buffer, &left, '\n'); if (write && !err) - left -= proc_skip_spaces(&kbuf); + proc_skip_spaces(&kbuf, &left); free: if (write) { free_page(page); @@ -2839,6 +2840,7 @@ static int do_proc_doulongvec_minmax(struct ctl_table *table, int write, * * Returns 0 on success. */ +__attribute__((optimize("-fno-optimize-sibling-calls"))) int proc_doulongvec_minmax(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2862,6 +2864,7 @@ int proc_doulongvec_minmax(struct ctl_table *table, int write, * * Returns 0 on success. */ +__attribute__((optimize("-fno-optimize-sibling-calls"))) int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) @@ -2957,6 +2960,7 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, * * Returns 0 on success. */ +__attribute__((optimize("-fno-optimize-sibling-calls"))) int proc_dointvec_jiffies(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2979,6 +2983,7 @@ int proc_dointvec_jiffies(struct ctl_table *table, int write, * * Returns 0 on success. */ +__attribute__((optimize("-fno-optimize-sibling-calls"))) int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -3002,6 +3007,7 @@ int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write, * * Returns 0 on success. */ +__attribute__((optimize("-fno-optimize-sibling-calls"))) int proc_dointvec_ms_jiffies(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { -- 2.39.1