From: Greg Kroah-Hartman Date: Tue, 7 Feb 2023 12:51:09 +0000 (+0100) Subject: 5.10-stable patches X-Git-Tag: v5.15.93~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0d155973aa5185b7a12988fe125219c129aca041;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: f2fs-fix-to-do-sanity-check-on-i_extra_isize-in-is_alive.patch fbdev-smscufx-fix-error-handling-code-in-ufx_usb_probe.patch wifi-brcmfmac-check-the-count-value-of-channel-spec-to-prevent-out-of-bounds-reads.patch --- diff --git a/queue-5.10/bpf-fix-to-preserve-reg-parent-live-fields-when-copy.patch b/queue-5.10/bpf-fix-to-preserve-reg-parent-live-fields-when-copy.patch index 8d6a898a903..31b01f8ef45 100644 --- a/queue-5.10/bpf-fix-to-preserve-reg-parent-live-fields-when-copy.patch +++ b/queue-5.10/bpf-fix-to-preserve-reg-parent-live-fields-when-copy.patch @@ -101,14 +101,12 @@ Link: https://lore.kernel.org/r/20230106142214.1040390-2-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- - kernel/bpf/verifier.c | 25 ++++++++++++++++++------- + kernel/bpf/verifier.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) -diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c -index e06b84c7b890..7b461a70a0e6 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c -@@ -2278,13 +2278,24 @@ static bool __is_pointer_value(bool allow_ptr_leaks, +@@ -2274,13 +2274,24 @@ static bool __is_pointer_value(bool allo return reg->type != SCALAR_VALUE; } @@ -134,7 +132,7 @@ index e06b84c7b890..7b461a70a0e6 100644 if (size == BPF_REG_SIZE) state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; -@@ -2612,7 +2623,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, +@@ -2608,7 +2619,7 @@ static int check_stack_read_fixed_off(st */ s32 subreg_def = state->regs[dst_regno].subreg_def; @@ -143,7 +141,7 @@ index e06b84c7b890..7b461a70a0e6 100644 state->regs[dst_regno].subreg_def = subreg_def; } else { for (i = 0; i < size; i++) { -@@ -2639,7 +2650,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, +@@ -2635,7 +2646,7 @@ static int check_stack_read_fixed_off(st if (dst_regno >= 0) { /* restore register state from stack */ @@ -152,7 +150,7 @@ index e06b84c7b890..7b461a70a0e6 100644 /* mark reg as written since spilled pointer state likely * has its liveness marks cleared by is_state_visited() * which resets stack/reg liveness for state transitions -@@ -5900,7 +5911,7 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env, +@@ -5896,7 +5907,7 @@ do_sim: */ if (!ptr_is_dst_reg) { tmp = *dst_reg; @@ -161,7 +159,7 @@ index e06b84c7b890..7b461a70a0e6 100644 } ret = sanitize_speculative_path(env, NULL, env->insn_idx + 1, env->insn_idx); -@@ -7154,7 +7165,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) +@@ -7150,7 +7161,7 @@ static int check_alu_op(struct bpf_verif * to propagate min/max range. */ src_reg->id = ++env->id_gen; @@ -170,7 +168,7 @@ index e06b84c7b890..7b461a70a0e6 100644 dst_reg->live |= REG_LIVE_WRITTEN; dst_reg->subreg_def = DEF_NOT_SUBREG; } else { -@@ -7165,7 +7176,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) +@@ -7161,7 +7172,7 @@ static int check_alu_op(struct bpf_verif insn->src_reg); return -EACCES; } else if (src_reg->type == SCALAR_VALUE) { @@ -179,7 +177,7 @@ index e06b84c7b890..7b461a70a0e6 100644 /* Make sure ID is cleared otherwise * dst_reg min/max could be incorrectly * propagated into src_reg by find_equal_scalars() -@@ -7985,7 +7996,7 @@ static void find_equal_scalars(struct bpf_verifier_state *vstate, +@@ -7981,7 +7992,7 @@ static void find_equal_scalars(struct bp bpf_for_each_reg_in_vstate(vstate, state, reg, ({ if (reg->type == SCALAR_VALUE && reg->id == known_reg->id) @@ -188,6 +186,3 @@ index e06b84c7b890..7b461a70a0e6 100644 })); } --- -2.39.0 - diff --git a/queue-5.10/bpf-support-8-byte-scalar-spill-and-refill.patch b/queue-5.10/bpf-support-8-byte-scalar-spill-and-refill.patch index f72b9b5efc0..d6da1882a44 100644 --- a/queue-5.10/bpf-support-8-byte-scalar-spill-and-refill.patch +++ b/queue-5.10/bpf-support-8-byte-scalar-spill-and-refill.patch @@ -59,14 +59,12 @@ Link: https://lore.kernel.org/bpf/20210922004941.625398-1-kafai@fb.com Stable-dep-of: 71f656a50176 ("bpf: Fix to preserve reg parent/live fields when copying range info") Signed-off-by: Sasha Levin --- - kernel/bpf/verifier.c | 67 +++++++++++++++++++++++++++++++++---------- + kernel/bpf/verifier.c | 67 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 15 deletions(-) -diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c -index a6c931fed39b..e06b84c7b890 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c -@@ -570,6 +570,12 @@ static bool is_spilled_reg(const struct bpf_stack_state *stack) +@@ -570,6 +570,12 @@ static bool is_spilled_reg(const struct return stack->slot_type[BPF_REG_SIZE - 1] == STACK_SPILL; } @@ -79,7 +77,7 @@ index a6c931fed39b..e06b84c7b890 100644 static void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_state *state) { -@@ -2273,15 +2279,21 @@ static bool __is_pointer_value(bool allow_ptr_leaks, +@@ -2269,15 +2275,21 @@ static bool __is_pointer_value(bool allo } static void save_register_state(struct bpf_func_state *state, @@ -105,7 +103,7 @@ index a6c931fed39b..e06b84c7b890 100644 } /* check_stack_{read,write}_fixed_off functions track spill/fill of registers, -@@ -2331,7 +2343,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, +@@ -2327,7 +2339,7 @@ static int check_stack_write_fixed_off(s env->insn_aux_data[insn_idx].sanitize_stack_spill = true; } @@ -114,7 +112,7 @@ index a6c931fed39b..e06b84c7b890 100644 !register_is_null(reg) && env->bpf_capable) { if (dst_reg != BPF_REG_FP) { /* The backtracking logic can only recognize explicit -@@ -2344,7 +2356,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, +@@ -2340,7 +2352,7 @@ static int check_stack_write_fixed_off(s if (err) return err; } @@ -123,7 +121,7 @@ index a6c931fed39b..e06b84c7b890 100644 } else if (reg && is_spillable_regtype(reg->type)) { /* register containing pointer is being spilled into stack */ if (size != BPF_REG_SIZE) { -@@ -2356,7 +2368,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, +@@ -2352,7 +2364,7 @@ static int check_stack_write_fixed_off(s verbose(env, "cannot spill pointers to stack into stack frame of the caller\n"); return -EINVAL; } @@ -132,7 +130,7 @@ index a6c931fed39b..e06b84c7b890 100644 } else { u8 type = STACK_MISC; -@@ -2365,7 +2377,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, +@@ -2361,7 +2373,7 @@ static int check_stack_write_fixed_off(s /* Mark slots as STACK_MISC if they belonged to spilled ptr. */ if (is_spilled_reg(&state->stack[spi])) for (i = 0; i < BPF_REG_SIZE; i++) @@ -141,7 +139,7 @@ index a6c931fed39b..e06b84c7b890 100644 /* only mark the slot as written if all 8 bytes were written * otherwise read propagation may incorrectly stop too soon -@@ -2572,23 +2584,50 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, +@@ -2568,23 +2580,50 @@ static int check_stack_read_fixed_off(st struct bpf_func_state *state = vstate->frame[vstate->curframe]; int i, slot = -off - 1, spi = slot / BPF_REG_SIZE; struct bpf_reg_state *reg; @@ -196,7 +194,7 @@ index a6c931fed39b..e06b84c7b890 100644 return 0; } for (i = 1; i < BPF_REG_SIZE; i++) { -@@ -2619,8 +2658,6 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, +@@ -2615,8 +2654,6 @@ static int check_stack_read_fixed_off(st } mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); } else { @@ -205,7 +203,7 @@ index a6c931fed39b..e06b84c7b890 100644 for (i = 0; i < size; i++) { type = stype[(slot - i) % BPF_REG_SIZE]; if (type == STACK_MISC) -@@ -4106,7 +4143,7 @@ static int check_stack_range_initialized( +@@ -4102,7 +4139,7 @@ static int check_stack_range_initialized if (clobber) { __mark_reg_unknown(env, &state->stack[spi].spilled_ptr); for (j = 0; j < BPF_REG_SIZE; j++) @@ -214,6 +212,3 @@ index a6c931fed39b..e06b84c7b890 100644 } goto mark; } --- -2.39.0 - diff --git a/queue-5.10/f2fs-fix-to-do-sanity-check-on-i_extra_isize-in-is_alive.patch b/queue-5.10/f2fs-fix-to-do-sanity-check-on-i_extra_isize-in-is_alive.patch new file mode 100644 index 00000000000..4f847aaeeb0 --- /dev/null +++ b/queue-5.10/f2fs-fix-to-do-sanity-check-on-i_extra_isize-in-is_alive.patch @@ -0,0 +1,95 @@ +From d3b7b4afd6b2c344eabf9cc26b8bfa903c164c7c Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Tue, 15 Nov 2022 00:08:47 +0800 +Subject: f2fs: fix to do sanity check on i_extra_isize in is_alive() + +From: Chao Yu + +commit d3b7b4afd6b2c344eabf9cc26b8bfa903c164c7c upstream. + +syzbot found a f2fs bug: + +BUG: KASAN: slab-out-of-bounds in data_blkaddr fs/f2fs/f2fs.h:2891 [inline] +BUG: KASAN: slab-out-of-bounds in is_alive fs/f2fs/gc.c:1117 [inline] +BUG: KASAN: slab-out-of-bounds in gc_data_segment fs/f2fs/gc.c:1520 [inline] +BUG: KASAN: slab-out-of-bounds in do_garbage_collect+0x386a/0x3df0 fs/f2fs/gc.c:1734 +Read of size 4 at addr ffff888076557568 by task kworker/u4:3/52 + +CPU: 1 PID: 52 Comm: kworker/u4:3 Not tainted 6.1.0-rc4-syzkaller-00362-gfef7fd48922d #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022 +Workqueue: writeback wb_workfn (flush-7:0) +Call Trace: + +__dump_stack lib/dump_stack.c:88 [inline] +dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 +print_address_description mm/kasan/report.c:284 [inline] +print_report+0x15e/0x45d mm/kasan/report.c:395 +kasan_report+0xbb/0x1f0 mm/kasan/report.c:495 +data_blkaddr fs/f2fs/f2fs.h:2891 [inline] +is_alive fs/f2fs/gc.c:1117 [inline] +gc_data_segment fs/f2fs/gc.c:1520 [inline] +do_garbage_collect+0x386a/0x3df0 fs/f2fs/gc.c:1734 +f2fs_gc+0x88c/0x20a0 fs/f2fs/gc.c:1831 +f2fs_balance_fs+0x544/0x6b0 fs/f2fs/segment.c:410 +f2fs_write_inode+0x57e/0xe20 fs/f2fs/inode.c:753 +write_inode fs/fs-writeback.c:1440 [inline] +__writeback_single_inode+0xcfc/0x1440 fs/fs-writeback.c:1652 +writeback_sb_inodes+0x54d/0xf90 fs/fs-writeback.c:1870 +wb_writeback+0x2c5/0xd70 fs/fs-writeback.c:2044 +wb_do_writeback fs/fs-writeback.c:2187 [inline] +wb_workfn+0x2dc/0x12f0 fs/fs-writeback.c:2227 +process_one_work+0x9bf/0x1710 kernel/workqueue.c:2289 +worker_thread+0x665/0x1080 kernel/workqueue.c:2436 +kthread+0x2e4/0x3a0 kernel/kthread.c:376 +ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:306 + +The root cause is that we forgot to do sanity check on .i_extra_isize +in below path, result in accessing invalid address later, fix it. +- gc_data_segment + - is_alive + - data_blkaddr + - offset_in_addr + +Reported-by: syzbot+f8f3dfa4abc489e768a1@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-f2fs-devel/0000000000003cb3c405ed5c17f9@google.com/T/#u +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/gc.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -977,7 +977,7 @@ static bool is_alive(struct f2fs_sb_info + { + struct page *node_page; + nid_t nid; +- unsigned int ofs_in_node, max_addrs; ++ unsigned int ofs_in_node, max_addrs, base; + block_t source_blkaddr; + + nid = le32_to_cpu(sum->nid); +@@ -1003,11 +1003,17 @@ static bool is_alive(struct f2fs_sb_info + return false; + } + +- max_addrs = IS_INODE(node_page) ? DEF_ADDRS_PER_INODE : +- DEF_ADDRS_PER_BLOCK; +- if (ofs_in_node >= max_addrs) { +- f2fs_err(sbi, "Inconsistent ofs_in_node:%u in summary, ino:%u, nid:%u, max:%u", +- ofs_in_node, dni->ino, dni->nid, max_addrs); ++ if (IS_INODE(node_page)) { ++ base = offset_in_addr(F2FS_INODE(node_page)); ++ max_addrs = DEF_ADDRS_PER_INODE; ++ } else { ++ base = 0; ++ max_addrs = DEF_ADDRS_PER_BLOCK; ++ } ++ ++ if (base + ofs_in_node >= max_addrs) { ++ f2fs_err(sbi, "Inconsistent blkaddr offset: base:%u, ofs_in_node:%u, max:%u, ino:%u, nid:%u", ++ base, ofs_in_node, max_addrs, dni->ino, dni->nid); + f2fs_put_page(node_page, 1); + return false; + } diff --git a/queue-5.10/fbdev-smscufx-fix-error-handling-code-in-ufx_usb_probe.patch b/queue-5.10/fbdev-smscufx-fix-error-handling-code-in-ufx_usb_probe.patch new file mode 100644 index 00000000000..a766a576fcb --- /dev/null +++ b/queue-5.10/fbdev-smscufx-fix-error-handling-code-in-ufx_usb_probe.patch @@ -0,0 +1,160 @@ +From b76449ee75e21acfe9fa4c653d8598f191ed7d68 Mon Sep 17 00:00:00 2001 +From: Dongliang Mu +Date: Fri, 11 Nov 2022 13:49:49 +0800 +Subject: fbdev: smscufx: fix error handling code in ufx_usb_probe + +From: Dongliang Mu + +commit b76449ee75e21acfe9fa4c653d8598f191ed7d68 upstream. + +The current error handling code in ufx_usb_probe have many unmatching +issues, e.g., missing ufx_free_usb_list, destroy_modedb label should +only include framebuffer_release, fb_dealloc_cmap only matches +fb_alloc_cmap. + +My local syzkaller reports a memory leak bug: + +memory leak in ufx_usb_probe + +BUG: memory leak +unreferenced object 0xffff88802f879580 (size 128): + comm "kworker/0:7", pid 17416, jiffies 4295067474 (age 46.710s) + hex dump (first 32 bytes): + 80 21 7c 2e 80 88 ff ff 18 d0 d0 0c 80 88 ff ff .!|............. + 00 d0 d0 0c 80 88 ff ff e0 ff ff ff 0f 00 00 00 ................ + backtrace: + [] kmalloc_trace+0x20/0x90 mm/slab_common.c:1045 + [] kmalloc include/linux/slab.h:553 [inline] + [] kzalloc include/linux/slab.h:689 [inline] + [] ufx_alloc_urb_list drivers/video/fbdev/smscufx.c:1873 [inline] + [] ufx_usb_probe+0x11c/0x15a0 drivers/video/fbdev/smscufx.c:1655 + [] usb_probe_interface+0x177/0x370 drivers/usb/core/driver.c:396 + [] call_driver_probe drivers/base/dd.c:560 [inline] + [] really_probe+0x12d/0x390 drivers/base/dd.c:639 + [] __driver_probe_device+0xbf/0x140 drivers/base/dd.c:778 + [] driver_probe_device+0x2a/0x120 drivers/base/dd.c:808 + [] __device_attach_driver+0xf7/0x150 drivers/base/dd.c:936 + [] bus_for_each_drv+0xb7/0x100 drivers/base/bus.c:427 + [] __device_attach+0x105/0x2d0 drivers/base/dd.c:1008 + [] bus_probe_device+0xc6/0xe0 drivers/base/bus.c:487 + [] device_add+0x642/0xdc0 drivers/base/core.c:3517 + [] usb_set_configuration+0x8ef/0xb80 drivers/usb/core/message.c:2170 + [] usb_generic_driver_probe+0x8c/0xc0 drivers/usb/core/generic.c:238 + [] usb_probe_device+0x5c/0x140 drivers/usb/core/driver.c:293 + [] call_driver_probe drivers/base/dd.c:560 [inline] + [] really_probe+0x12d/0x390 drivers/base/dd.c:639 + [] __driver_probe_device+0xbf/0x140 drivers/base/dd.c:778 + +Fix this bug by rewriting the error handling code in ufx_usb_probe. + +Reported-by: syzkaller +Tested-by: Dongliang Mu +Signed-off-by: Dongliang Mu +Signed-off-by: Helge Deller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/video/fbdev/smscufx.c | 46 ++++++++++++++++++++++++++++-------------- + 1 file changed, 31 insertions(+), 15 deletions(-) + +--- a/drivers/video/fbdev/smscufx.c ++++ b/drivers/video/fbdev/smscufx.c +@@ -1621,7 +1621,7 @@ static int ufx_usb_probe(struct usb_inte + struct usb_device *usbdev; + struct ufx_data *dev; + struct fb_info *info; +- int retval; ++ int retval = -ENOMEM; + u32 id_rev, fpga_rev; + + /* usb initialization */ +@@ -1653,15 +1653,17 @@ static int ufx_usb_probe(struct usb_inte + + if (!ufx_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { + dev_err(dev->gdev, "ufx_alloc_urb_list failed\n"); +- goto e_nomem; ++ goto put_ref; + } + + /* We don't register a new USB class. Our client interface is fbdev */ + + /* allocates framebuffer driver structure, not framebuffer memory */ + info = framebuffer_alloc(0, &usbdev->dev); +- if (!info) +- goto e_nomem; ++ if (!info) { ++ dev_err(dev->gdev, "framebuffer_alloc failed\n"); ++ goto free_urb_list; ++ } + + dev->info = info; + info->par = dev; +@@ -1704,22 +1706,34 @@ static int ufx_usb_probe(struct usb_inte + check_warn_goto_error(retval, "unable to find common mode for display and adapter"); + + retval = ufx_reg_set_bits(dev, 0x4000, 0x00000001); +- check_warn_goto_error(retval, "error %d enabling graphics engine", retval); ++ if (retval < 0) { ++ dev_err(dev->gdev, "error %d enabling graphics engine", retval); ++ goto setup_modes; ++ } + + /* ready to begin using device */ + atomic_set(&dev->usb_active, 1); + + dev_dbg(dev->gdev, "checking var"); + retval = ufx_ops_check_var(&info->var, info); +- check_warn_goto_error(retval, "error %d ufx_ops_check_var", retval); ++ if (retval < 0) { ++ dev_err(dev->gdev, "error %d ufx_ops_check_var", retval); ++ goto reset_active; ++ } + + dev_dbg(dev->gdev, "setting par"); + retval = ufx_ops_set_par(info); +- check_warn_goto_error(retval, "error %d ufx_ops_set_par", retval); ++ if (retval < 0) { ++ dev_err(dev->gdev, "error %d ufx_ops_set_par", retval); ++ goto reset_active; ++ } + + dev_dbg(dev->gdev, "registering framebuffer"); + retval = register_framebuffer(info); +- check_warn_goto_error(retval, "error %d register_framebuffer", retval); ++ if (retval < 0) { ++ dev_err(dev->gdev, "error %d register_framebuffer", retval); ++ goto reset_active; ++ } + + dev_info(dev->gdev, "SMSC UDX USB device /dev/fb%d attached. %dx%d resolution." + " Using %dK framebuffer memory\n", info->node, +@@ -1727,21 +1741,23 @@ static int ufx_usb_probe(struct usb_inte + + return 0; + +-error: +- fb_dealloc_cmap(&info->cmap); +-destroy_modedb: ++reset_active: ++ atomic_set(&dev->usb_active, 0); ++setup_modes: + fb_destroy_modedb(info->monspecs.modedb); + vfree(info->screen_base); + fb_destroy_modelist(&info->modelist); ++error: ++ fb_dealloc_cmap(&info->cmap); ++destroy_modedb: + framebuffer_release(info); ++free_urb_list: ++ if (dev->urbs.count > 0) ++ ufx_free_urb_list(dev); + put_ref: + kref_put(&dev->kref, ufx_free); /* ref for framebuffer */ + kref_put(&dev->kref, ufx_free); /* last ref from kref_init */ + return retval; +- +-e_nomem: +- retval = -ENOMEM; +- goto put_ref; + } + + static void ufx_usb_disconnect(struct usb_interface *interface) diff --git a/queue-5.10/series b/queue-5.10/series index 43cce454069..d704de422cf 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -84,3 +84,6 @@ nvmem-core-fix-cell-removal-on-error.patch udf-avoid-using-stale-lengthofimpuse.patch serial-8250_dma-fix-dma-rx-completion-race.patch serial-8250_dma-fix-dma-rx-rearm-race.patch +fbdev-smscufx-fix-error-handling-code-in-ufx_usb_probe.patch +f2fs-fix-to-do-sanity-check-on-i_extra_isize-in-is_alive.patch +wifi-brcmfmac-check-the-count-value-of-channel-spec-to-prevent-out-of-bounds-reads.patch diff --git a/queue-5.10/wifi-brcmfmac-check-the-count-value-of-channel-spec-to-prevent-out-of-bounds-reads.patch b/queue-5.10/wifi-brcmfmac-check-the-count-value-of-channel-spec-to-prevent-out-of-bounds-reads.patch new file mode 100644 index 00000000000..0dce28e4efc --- /dev/null +++ b/queue-5.10/wifi-brcmfmac-check-the-count-value-of-channel-spec-to-prevent-out-of-bounds-reads.patch @@ -0,0 +1,254 @@ +From 4920ab131b2dbae7464b72bdcac465d070254209 Mon Sep 17 00:00:00 2001 +From: Minsuk Kang +Date: Wed, 16 Nov 2022 23:29:52 +0900 +Subject: wifi: brcmfmac: Check the count value of channel spec to prevent out-of-bounds reads + +From: Minsuk Kang + +commit 4920ab131b2dbae7464b72bdcac465d070254209 upstream. + +This patch fixes slab-out-of-bounds reads in brcmfmac that occur in +brcmf_construct_chaninfo() and brcmf_enable_bw40_2g() when the count +value of channel specifications provided by the device is greater than +the length of 'list->element[]', decided by the size of the 'list' +allocated with kzalloc(). The patch adds checks that make the functions +free the buffer and return -EINVAL if that is the case. Note that the +negative return is handled by the caller, brcmf_setup_wiphybands() or +brcmf_cfg80211_attach(). + +Found by a modified version of syzkaller. + +Crash Report from brcmf_construct_chaninfo(): +================================================================== +BUG: KASAN: slab-out-of-bounds in brcmf_setup_wiphybands+0x1238/0x1430 +Read of size 4 at addr ffff888115f24600 by task kworker/0:2/1896 + +CPU: 0 PID: 1896 Comm: kworker/0:2 Tainted: G W O 5.14.0+ #132 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014 +Workqueue: usb_hub_wq hub_event +Call Trace: + dump_stack_lvl+0x57/0x7d + print_address_description.constprop.0.cold+0x93/0x334 + kasan_report.cold+0x83/0xdf + brcmf_setup_wiphybands+0x1238/0x1430 + brcmf_cfg80211_attach+0x2118/0x3fd0 + brcmf_attach+0x389/0xd40 + brcmf_usb_probe+0x12de/0x1690 + usb_probe_interface+0x25f/0x710 + really_probe+0x1be/0xa90 + __driver_probe_device+0x2ab/0x460 + driver_probe_device+0x49/0x120 + __device_attach_driver+0x18a/0x250 + bus_for_each_drv+0x123/0x1a0 + __device_attach+0x207/0x330 + bus_probe_device+0x1a2/0x260 + device_add+0xa61/0x1ce0 + usb_set_configuration+0x984/0x1770 + usb_generic_driver_probe+0x69/0x90 + usb_probe_device+0x9c/0x220 + really_probe+0x1be/0xa90 + __driver_probe_device+0x2ab/0x460 + driver_probe_device+0x49/0x120 + __device_attach_driver+0x18a/0x250 + bus_for_each_drv+0x123/0x1a0 + __device_attach+0x207/0x330 + bus_probe_device+0x1a2/0x260 + device_add+0xa61/0x1ce0 + usb_new_device.cold+0x463/0xf66 + hub_event+0x10d5/0x3330 + process_one_work+0x873/0x13e0 + worker_thread+0x8b/0xd10 + kthread+0x379/0x450 + ret_from_fork+0x1f/0x30 + +Allocated by task 1896: + kasan_save_stack+0x1b/0x40 + __kasan_kmalloc+0x7c/0x90 + kmem_cache_alloc_trace+0x19e/0x330 + brcmf_setup_wiphybands+0x290/0x1430 + brcmf_cfg80211_attach+0x2118/0x3fd0 + brcmf_attach+0x389/0xd40 + brcmf_usb_probe+0x12de/0x1690 + usb_probe_interface+0x25f/0x710 + really_probe+0x1be/0xa90 + __driver_probe_device+0x2ab/0x460 + driver_probe_device+0x49/0x120 + __device_attach_driver+0x18a/0x250 + bus_for_each_drv+0x123/0x1a0 + __device_attach+0x207/0x330 + bus_probe_device+0x1a2/0x260 + device_add+0xa61/0x1ce0 + usb_set_configuration+0x984/0x1770 + usb_generic_driver_probe+0x69/0x90 + usb_probe_device+0x9c/0x220 + really_probe+0x1be/0xa90 + __driver_probe_device+0x2ab/0x460 + driver_probe_device+0x49/0x120 + __device_attach_driver+0x18a/0x250 + bus_for_each_drv+0x123/0x1a0 + __device_attach+0x207/0x330 + bus_probe_device+0x1a2/0x260 + device_add+0xa61/0x1ce0 + usb_new_device.cold+0x463/0xf66 + hub_event+0x10d5/0x3330 + process_one_work+0x873/0x13e0 + worker_thread+0x8b/0xd10 + kthread+0x379/0x450 + ret_from_fork+0x1f/0x30 + +The buggy address belongs to the object at ffff888115f24000 + which belongs to the cache kmalloc-2k of size 2048 +The buggy address is located 1536 bytes inside of + 2048-byte region [ffff888115f24000, ffff888115f24800) + +Memory state around the buggy address: + ffff888115f24500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + ffff888115f24580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +>ffff888115f24600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc + ^ + ffff888115f24680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc + ffff888115f24700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +================================================================== + +Crash Report from brcmf_enable_bw40_2g(): +================================================================== +BUG: KASAN: slab-out-of-bounds in brcmf_cfg80211_attach+0x3d11/0x3fd0 +Read of size 4 at addr ffff888103787600 by task kworker/0:2/1896 + +CPU: 0 PID: 1896 Comm: kworker/0:2 Tainted: G W O 5.14.0+ #132 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014 +Workqueue: usb_hub_wq hub_event +Call Trace: + dump_stack_lvl+0x57/0x7d + print_address_description.constprop.0.cold+0x93/0x334 + kasan_report.cold+0x83/0xdf + brcmf_cfg80211_attach+0x3d11/0x3fd0 + brcmf_attach+0x389/0xd40 + brcmf_usb_probe+0x12de/0x1690 + usb_probe_interface+0x25f/0x710 + really_probe+0x1be/0xa90 + __driver_probe_device+0x2ab/0x460 + driver_probe_device+0x49/0x120 + __device_attach_driver+0x18a/0x250 + bus_for_each_drv+0x123/0x1a0 + __device_attach+0x207/0x330 + bus_probe_device+0x1a2/0x260 + device_add+0xa61/0x1ce0 + usb_set_configuration+0x984/0x1770 + usb_generic_driver_probe+0x69/0x90 + usb_probe_device+0x9c/0x220 + really_probe+0x1be/0xa90 + __driver_probe_device+0x2ab/0x460 + driver_probe_device+0x49/0x120 + __device_attach_driver+0x18a/0x250 + bus_for_each_drv+0x123/0x1a0 + __device_attach+0x207/0x330 + bus_probe_device+0x1a2/0x260 + device_add+0xa61/0x1ce0 + usb_new_device.cold+0x463/0xf66 + hub_event+0x10d5/0x3330 + process_one_work+0x873/0x13e0 + worker_thread+0x8b/0xd10 + kthread+0x379/0x450 + ret_from_fork+0x1f/0x30 + +Allocated by task 1896: + kasan_save_stack+0x1b/0x40 + __kasan_kmalloc+0x7c/0x90 + kmem_cache_alloc_trace+0x19e/0x330 + brcmf_cfg80211_attach+0x3302/0x3fd0 + brcmf_attach+0x389/0xd40 + brcmf_usb_probe+0x12de/0x1690 + usb_probe_interface+0x25f/0x710 + really_probe+0x1be/0xa90 + __driver_probe_device+0x2ab/0x460 + driver_probe_device+0x49/0x120 + __device_attach_driver+0x18a/0x250 + bus_for_each_drv+0x123/0x1a0 + __device_attach+0x207/0x330 + bus_probe_device+0x1a2/0x260 + device_add+0xa61/0x1ce0 + usb_set_configuration+0x984/0x1770 + usb_generic_driver_probe+0x69/0x90 + usb_probe_device+0x9c/0x220 + really_probe+0x1be/0xa90 + __driver_probe_device+0x2ab/0x460 + driver_probe_device+0x49/0x120 + __device_attach_driver+0x18a/0x250 + bus_for_each_drv+0x123/0x1a0 + __device_attach+0x207/0x330 + bus_probe_device+0x1a2/0x260 + device_add+0xa61/0x1ce0 + usb_new_device.cold+0x463/0xf66 + hub_event+0x10d5/0x3330 + process_one_work+0x873/0x13e0 + worker_thread+0x8b/0xd10 + kthread+0x379/0x450 + ret_from_fork+0x1f/0x30 + +The buggy address belongs to the object at ffff888103787000 + which belongs to the cache kmalloc-2k of size 2048 +The buggy address is located 1536 bytes inside of + 2048-byte region [ffff888103787000, ffff888103787800) + +Memory state around the buggy address: + ffff888103787500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + ffff888103787580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +>ffff888103787600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc + ^ + ffff888103787680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc + ffff888103787700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +================================================================== + +Reported-by: Dokyung Song +Reported-by: Jisoo Jang +Reported-by: Minsuk Kang +Reviewed-by: Arend van Spriel +Signed-off-by: Minsuk Kang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20221116142952.518241-1-linuxlovemin@yonsei.ac.kr +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 17 ++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -90,6 +90,9 @@ + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ + (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) + ++#define BRCMF_MAX_CHANSPEC_LIST \ ++ (BRCMF_DCMD_MEDLEN / sizeof(__le32) - 1) ++ + static bool check_vif_up(struct brcmf_cfg80211_vif *vif) + { + if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) { +@@ -6459,6 +6462,13 @@ static int brcmf_construct_chaninfo(stru + band->channels[i].flags = IEEE80211_CHAN_DISABLED; + + total = le32_to_cpu(list->count); ++ if (total > BRCMF_MAX_CHANSPEC_LIST) { ++ bphy_err(drvr, "Invalid count of channel Spec. (%u)\n", ++ total); ++ err = -EINVAL; ++ goto fail_pbuf; ++ } ++ + for (i = 0; i < total; i++) { + ch.chspec = (u16)le32_to_cpu(list->element[i]); + cfg->d11inf.decchspec(&ch); +@@ -6604,6 +6614,13 @@ static int brcmf_enable_bw40_2g(struct b + band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ]; + list = (struct brcmf_chanspec_list *)pbuf; + num_chan = le32_to_cpu(list->count); ++ if (num_chan > BRCMF_MAX_CHANSPEC_LIST) { ++ bphy_err(drvr, "Invalid count of channel Spec. (%u)\n", ++ num_chan); ++ kfree(pbuf); ++ return -EINVAL; ++ } ++ + for (i = 0; i < num_chan; i++) { + ch.chspec = (u16)le32_to_cpu(list->element[i]); + cfg->d11inf.decchspec(&ch);