OSDN Git Service

rsi: Fix use-after-free in rsi_rx_done_handler()
authorZekun Shen <bruceshenzk@gmail.com>
Fri, 29 Oct 2021 19:49:03 +0000 (15:49 -0400)
committerKalle Valo <kvalo@codeaurora.org>
Mon, 29 Nov 2021 10:43:15 +0000 (12:43 +0200)
When freeing rx_cb->rx_skb, the pointer is not set to NULL,
a later rsi_rx_done_handler call will try to read the freed
address.
This bug will very likley lead to double free, although
detected early as use-after-free bug.

The bug is triggerable with a compromised/malfunctional usb
device. After applying the patch, the same input no longer
triggers the use-after-free.

Attached is the kasan report from fuzzing.

BUG: KASAN: use-after-free in rsi_rx_done_handler+0x354/0x430 [rsi_usb]
Read of size 4 at addr ffff8880188e5930 by task modprobe/231
Call Trace:
 <IRQ>
 dump_stack+0x76/0xa0
 print_address_description.constprop.0+0x16/0x200
 ? rsi_rx_done_handler+0x354/0x430 [rsi_usb]
 ? rsi_rx_done_handler+0x354/0x430 [rsi_usb]
 __kasan_report.cold+0x37/0x7c
 ? dma_direct_unmap_page+0x90/0x110
 ? rsi_rx_done_handler+0x354/0x430 [rsi_usb]
 kasan_report+0xe/0x20
 rsi_rx_done_handler+0x354/0x430 [rsi_usb]
 __usb_hcd_giveback_urb+0x1e4/0x380
 usb_giveback_urb_bh+0x241/0x4f0
 ? __usb_hcd_giveback_urb+0x380/0x380
 ? apic_timer_interrupt+0xa/0x20
 tasklet_action_common.isra.0+0x135/0x330
 __do_softirq+0x18c/0x634
 ? handle_irq_event+0xcd/0x157
 ? handle_edge_irq+0x1eb/0x7b0
 irq_exit+0x114/0x140
 do_IRQ+0x91/0x1e0
 common_interrupt+0xf/0xf
 </IRQ>

Reported-by: Brendan Dolan-Gavitt <brendandg@nyu.edu>
Signed-off-by: Zekun Shen <bruceshenzk@gmail.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/YXxQL/vIiYcZUu/j@10-18-43-117.dynapool.wireless.nyu.edu
drivers/net/wireless/rsi/rsi_91x_usb.c

index 6821ea9..3cca182 100644 (file)
@@ -269,8 +269,12 @@ static void rsi_rx_done_handler(struct urb *urb)
        struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)rx_cb->data;
        int status = -EINVAL;
 
+       if (!rx_cb->rx_skb)
+               return;
+
        if (urb->status) {
                dev_kfree_skb(rx_cb->rx_skb);
+               rx_cb->rx_skb = NULL;
                return;
        }
 
@@ -294,8 +298,10 @@ out:
        if (rsi_rx_urb_submit(dev->priv, rx_cb->ep_num, GFP_ATOMIC))
                rsi_dbg(ERR_ZONE, "%s: Failed in urb submission", __func__);
 
-       if (status)
+       if (status) {
                dev_kfree_skb(rx_cb->rx_skb);
+               rx_cb->rx_skb = NULL;
+       }
 }
 
 static void rsi_rx_urb_kill(struct rsi_hw *adapter, u8 ep_num)