Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c27a5232 authored by Zekun Shen's avatar Zekun Shen Committed by Greg Kroah-Hartman
Browse files

rsi: Fix out-of-bounds read in rsi_read_pkt()



[ Upstream commit f1cb3476e48b60c450ec3a1d7da0805bffc6e43a ]

rsi_get_* functions rely on an offset variable from usb
input. The size of usb input is RSI_MAX_RX_USB_PKT_SIZE(3000),
while 2-byte offset can be up to 0xFFFF. Thus a large offset
can cause out-of-bounds read.

The patch adds a bound checking condition when rcv_pkt_len is 0,
indicating it's USB. It's unclear whether this is triggerable
from other type of bus. The following check might help in that case.
offset > rcv_pkt_len - FRAME_DESC_SZ

The bug is trigerrable with conpromised/malfunctioning USB devices.
I tested the patch with the crashing input and got no more bug report.

Attached is the KASAN report from fuzzing.

BUG: KASAN: slab-out-of-bounds in rsi_read_pkt+0x42e/0x500 [rsi_91x]
Read of size 2 at addr ffff888019439fdb by task RX-Thread/227

CPU: 0 PID: 227 Comm: RX-Thread Not tainted 5.6.0 #66
Call Trace:
 dump_stack+0x76/0xa0
 print_address_description.constprop.0+0x16/0x200
 ? rsi_read_pkt+0x42e/0x500 [rsi_91x]
 ? rsi_read_pkt+0x42e/0x500 [rsi_91x]
 __kasan_report.cold+0x37/0x7c
 ? rsi_read_pkt+0x42e/0x500 [rsi_91x]
 kasan_report+0xe/0x20
 rsi_read_pkt+0x42e/0x500 [rsi_91x]
 rsi_usb_rx_thread+0x1b1/0x2fc [rsi_usb]
 ? rsi_probe+0x16a0/0x16a0 [rsi_usb]
 ? _raw_spin_lock_irqsave+0x7b/0xd0
 ? _raw_spin_trylock_bh+0x120/0x120
 ? __wake_up_common+0x10b/0x520
 ? rsi_probe+0x16a0/0x16a0 [rsi_usb]
 kthread+0x2b5/0x3b0
 ? kthread_create_on_node+0xd0/0xd0
 ret_from_fork+0x22/0x40

Reported-by: default avatarBrendan Dolan-Gavitt <brendandg@nyu.edu>
Signed-off-by: default avatarZekun Shen <bruceshenzk@gmail.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/YXxXS4wgu2OsmlVv@10-18-43-117.dynapool.wireless.nyu.edu


Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 51ad4c44
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include "rsi_common.h"
#include "rsi_coex.h"
#include "rsi_hal.h"
#include "rsi_usb.h"

u32 rsi_zone_enabled = /* INFO_ZONE |
			INIT_ZONE |
@@ -167,6 +168,9 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
		frame_desc = &rx_pkt[index];
		actual_length = *(u16 *)&frame_desc[0];
		offset = *(u16 *)&frame_desc[2];
		if (!rcv_pkt_len && offset >
			RSI_MAX_RX_USB_PKT_SIZE - FRAME_DESC_SZ)
			goto fail;

		queueno = rsi_get_queueno(frame_desc, offset);
		length = rsi_get_length(frame_desc, offset);
+0 −1
Original line number Diff line number Diff line
@@ -320,7 +320,6 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num, gfp_t mem_flags)
	struct sk_buff *skb;
	u8 dword_align_bytes = 0;

#define RSI_MAX_RX_USB_PKT_SIZE	3000
	skb = dev_alloc_skb(RSI_MAX_RX_USB_PKT_SIZE);
	if (!skb)
		return -ENOMEM;
+2 −0
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@
#define RSI_USB_BUF_SIZE	     4096
#define RSI_USB_CTRL_BUF_SIZE	     0x04

#define RSI_MAX_RX_USB_PKT_SIZE	3000

struct rx_usb_ctrl_block {
	u8 *data;
	struct urb *rx_urb;