linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] rsi: fix oob in rsi_prepare_skb
@ 2021-12-27 13:54 Zekun Shen
  2022-02-01 12:10 ` Kalle Valo
  0 siblings, 1 reply; 3+ messages in thread
From: Zekun Shen @ 2021-12-27 13:54 UTC (permalink / raw)
  To: bruceshenzk
  Cc: Amitkumar Karwar, Siva Rebbagondla, Kalle Valo, David S. Miller,
	Jakub Kicinski, linux-wireless, netdev, linux-kernel, brendandg

We found this bug while fuzzing the rsi_usb driver.
rsi_prepare_skb does not check for OOB memcpy. We
add the check in the caller to fix.

Although rsi_prepare_skb checks if length is larger
than (4 * RSI_RCV_BUFFER_LEN), it really can't because
length is 0xfff maximum. So the check in patch is sufficient.

This patch is created upon ath-next branch. It is
NOT tested with real device, but with QEMU emulator.

Following is the bug report

BUG: KASAN: use-after-free in rsi_read_pkt
(/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
Read of size 3815 at addr ffff888031da736d by task RX-Thread/204

CPU: 0 PID: 204 Comm: RX-Thread Not tainted 5.6.0 #5
Call Trace:
dump_stack (/linux/lib/dump_stack.c:120)
 ? rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
 print_address_description.constprop.6 (/linux/mm/kasan/report.c:377)
 ? rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
 ? rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
 __kasan_report.cold.9 (/linux/mm/kasan/report.c:510)
 ? syscall_return_via_sysret (/linux/arch/x86/entry/entry_64.S:253)
 ? rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
 kasan_report (/linux/arch/x86/include/asm/smap.h:69 /linux/mm/kasan/common.c:644)
 check_memory_region (/linux/mm/kasan/generic.c:186 /linux/mm/kasan/generic.c:192)
 memcpy (/linux/mm/kasan/common.c:130)
 rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
 ? skb_dequeue (/linux/net/core/skbuff.c:3042)
 rsi_usb_rx_thread (/linux/drivers/net/wireless/rsi/rsi_91x_usb_ops.c:47) rsi_usb

Reported-by: Brendan Dolan-Gavitt <brendandg@nyu.edu>
Signed-off-by: Zekun Shen <bruceshenzk@gmail.com>
---
 drivers/net/wireless/rsi/rsi_91x_main.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 5d1490fc3..41d3c12e0 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -193,6 +193,10 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
 			break;
 
 		case RSI_WIFI_DATA_Q:
+			if (!rcv_pkt_len && offset + length >
+				RSI_MAX_RX_USB_PKT_SIZE)
+				goto fail;
+
 			skb = rsi_prepare_skb(common,
 					      (frame_desc + offset),
 					      length,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] rsi: fix oob in rsi_prepare_skb
  2021-12-27 13:54 [PATCH] rsi: fix oob in rsi_prepare_skb Zekun Shen
@ 2022-02-01 12:10 ` Kalle Valo
  2022-02-01 13:52   ` Zekun Shen
  0 siblings, 1 reply; 3+ messages in thread
From: Kalle Valo @ 2022-02-01 12:10 UTC (permalink / raw)
  To: Zekun Shen
  Cc: Amitkumar Karwar, Siva Rebbagondla, David S. Miller,
	Jakub Kicinski, linux-wireless, netdev, linux-kernel, brendandg

Zekun Shen <bruceshenzk@gmail.com> writes:

> We found this bug while fuzzing the rsi_usb driver.
> rsi_prepare_skb does not check for OOB memcpy. We
> add the check in the caller to fix.
>
> Although rsi_prepare_skb checks if length is larger
> than (4 * RSI_RCV_BUFFER_LEN), it really can't because
> length is 0xfff maximum. So the check in patch is sufficient.
>
> This patch is created upon ath-next branch. It is
> NOT tested with real device, but with QEMU emulator.
>
> Following is the bug report
>
> BUG: KASAN: use-after-free in rsi_read_pkt
> (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
> Read of size 3815 at addr ffff888031da736d by task RX-Thread/204
>
> CPU: 0 PID: 204 Comm: RX-Thread Not tainted 5.6.0 #5
> Call Trace:
> dump_stack (/linux/lib/dump_stack.c:120)
>  ? rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
>  print_address_description.constprop.6 (/linux/mm/kasan/report.c:377)
>  ? rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
>  ? rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
>  __kasan_report.cold.9 (/linux/mm/kasan/report.c:510)
>  ? syscall_return_via_sysret (/linux/arch/x86/entry/entry_64.S:253)
>  ? rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
>  kasan_report (/linux/arch/x86/include/asm/smap.h:69 /linux/mm/kasan/common.c:644)
>  check_memory_region (/linux/mm/kasan/generic.c:186 /linux/mm/kasan/generic.c:192)
>  memcpy (/linux/mm/kasan/common.c:130)
>  rsi_read_pkt (/linux/drivers/net/wireless/rsi/rsi_91x_main.c:206) rsi_91x
>  ? skb_dequeue (/linux/net/core/skbuff.c:3042)
>  rsi_usb_rx_thread (/linux/drivers/net/wireless/rsi/rsi_91x_usb_ops.c:47) rsi_usb
>
> Reported-by: Brendan Dolan-Gavitt <brendandg@nyu.edu>
> Signed-off-by: Zekun Shen <bruceshenzk@gmail.com>
> ---
>  drivers/net/wireless/rsi/rsi_91x_main.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
> index 5d1490fc3..41d3c12e0 100644
> --- a/drivers/net/wireless/rsi/rsi_91x_main.c
> +++ b/drivers/net/wireless/rsi/rsi_91x_main.c
> @@ -193,6 +193,10 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
>  			break;
>  
>  		case RSI_WIFI_DATA_Q:
> +			if (!rcv_pkt_len && offset + length >
> +				RSI_MAX_RX_USB_PKT_SIZE)
> +				goto fail;
> +
>  			skb = rsi_prepare_skb(common,
>  					      (frame_desc + offset),
>  					      length,

Why are you doing the check here? In the beginning of the function we
have:

		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;

Wouldn't it make more sense to fix that check?

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] rsi: fix oob in rsi_prepare_skb
  2022-02-01 12:10 ` Kalle Valo
@ 2022-02-01 13:52   ` Zekun Shen
  0 siblings, 0 replies; 3+ messages in thread
From: Zekun Shen @ 2022-02-01 13:52 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Amitkumar Karwar, Siva Rebbagondla, David S. Miller,
	Jakub Kicinski, linux-wireless, netdev, linux-kernel, brendandg

The maximum length allowed (and without overflow) depends on
the queueno in the switch statement. I don't know the exact format
of the inputs, but there could be a universal and stricter length
restriction in the protocol

It is possible to fix the problem at the previous check you propose,
we just need to add input parsing for length and queueno there.

The code here seems prone to overflow, since function arguments
only include a single buffer pointer without a remaining byte count.
Moreover, some of the lengths are dynamic and encoded in the
buffer.

For this reason, I think it's easier and more maintainable to add the
check after existing parsing code and before read/write the buffer.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-02-01 13:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-27 13:54 [PATCH] rsi: fix oob in rsi_prepare_skb Zekun Shen
2022-02-01 12:10 ` Kalle Valo
2022-02-01 13:52   ` Zekun Shen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).