Skip to content

Commit bc6b892

Browse files
jkivilinlinvjw
authored andcommitted
rtlwifi: usb: allocate URB control message setup_packet and data buffer separately
rtlwifi allocates both setup_packet and data buffer of control message urb, using shared kmalloc in _usbctrl_vendorreq_async_write. Structure used for allocating is: struct { u8 data[254]; struct usb_ctrlrequest dr; }; Because 'struct usb_ctrlrequest' is __packed, setup packet is unaligned and DMA mapping of both 'data' and 'dr' confuses ARM/sunxi, leading to memory corruptions and freezes. Patch changes setup packet to be allocated separately. [v2]: - Use WARN_ON_ONCE instead of WARN_ON Cc: <stable@vger.kernel.org> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
1 parent a5f3905 commit bc6b892

File tree

1 file changed

+28
-16
lines changed
  • drivers/net/wireless/rtlwifi

1 file changed

+28
-16
lines changed

drivers/net/wireless/rtlwifi/usb.c

+28-16
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,12 @@
4242

4343
static void usbctrl_async_callback(struct urb *urb)
4444
{
45-
if (urb)
46-
kfree(urb->context);
45+
if (urb) {
46+
/* free dr */
47+
kfree(urb->setup_packet);
48+
/* free databuf */
49+
kfree(urb->transfer_buffer);
50+
}
4751
}
4852

4953
static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
@@ -55,39 +59,47 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
5559
u8 reqtype;
5660
struct usb_ctrlrequest *dr;
5761
struct urb *urb;
58-
struct rtl819x_async_write_data {
59-
u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE];
60-
struct usb_ctrlrequest dr;
61-
} *buf;
62+
const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE;
63+
u8 *databuf;
64+
65+
if (WARN_ON_ONCE(len > databuf_maxlen))
66+
len = databuf_maxlen;
6267

6368
pipe = usb_sndctrlpipe(udev, 0); /* write_out */
6469
reqtype = REALTEK_USB_VENQT_WRITE;
6570

66-
buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
67-
if (!buf)
71+
dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
72+
if (!dr)
6873
return -ENOMEM;
6974

75+
databuf = kmalloc(databuf_maxlen, GFP_ATOMIC);
76+
if (!databuf) {
77+
kfree(dr);
78+
return -ENOMEM;
79+
}
80+
7081
urb = usb_alloc_urb(0, GFP_ATOMIC);
7182
if (!urb) {
72-
kfree(buf);
83+
kfree(databuf);
84+
kfree(dr);
7385
return -ENOMEM;
7486
}
7587

76-
dr = &buf->dr;
77-
7888
dr->bRequestType = reqtype;
7989
dr->bRequest = request;
8090
dr->wValue = cpu_to_le16(value);
8191
dr->wIndex = cpu_to_le16(index);
8292
dr->wLength = cpu_to_le16(len);
8393
/* data are already in little-endian order */
84-
memcpy(buf, pdata, len);
94+
memcpy(databuf, pdata, len);
8595
usb_fill_control_urb(urb, udev, pipe,
86-
(unsigned char *)dr, buf, len,
87-
usbctrl_async_callback, buf);
96+
(unsigned char *)dr, databuf, len,
97+
usbctrl_async_callback, NULL);
8898
rc = usb_submit_urb(urb, GFP_ATOMIC);
89-
if (rc < 0)
90-
kfree(buf);
99+
if (rc < 0) {
100+
kfree(databuf);
101+
kfree(dr);
102+
}
91103
usb_free_urb(urb);
92104
return rc;
93105
}

0 commit comments

Comments
 (0)