| From e9b667a82cdcfe21d590344447d65daed52b353b Mon Sep 17 00:00:00 2001 |
| From: Alan Stern <stern@rowland.harvard.edu> |
| Date: Thu, 3 Mar 2022 16:00:17 -0500 |
| Subject: usb: usbtmc: Fix bug in pipe direction for control transfers |
| |
| From: Alan Stern <stern@rowland.harvard.edu> |
| |
| commit e9b667a82cdcfe21d590344447d65daed52b353b upstream. |
| |
| The syzbot fuzzer reported a minor bug in the usbtmc driver: |
| |
| usb 5-1: BOGUS control dir, pipe 80001e80 doesn't match bRequestType 0 |
| WARNING: CPU: 0 PID: 3813 at drivers/usb/core/urb.c:412 |
| usb_submit_urb+0x13a5/0x1970 drivers/usb/core/urb.c:410 |
| Modules linked in: |
| CPU: 0 PID: 3813 Comm: syz-executor122 Not tainted |
| 5.17.0-rc5-syzkaller-00306-g2293be58d6a1 #0 |
| ... |
| Call Trace: |
| <TASK> |
| usb_start_wait_urb+0x113/0x530 drivers/usb/core/message.c:58 |
| usb_internal_control_msg drivers/usb/core/message.c:102 [inline] |
| usb_control_msg+0x2a5/0x4b0 drivers/usb/core/message.c:153 |
| usbtmc_ioctl_request drivers/usb/class/usbtmc.c:1947 [inline] |
| |
| The problem is that usbtmc_ioctl_request() uses usb_rcvctrlpipe() for |
| all of its transfers, whether they are in or out. It's easy to fix. |
| |
| CC: <stable@vger.kernel.org> |
| Reported-and-tested-by: syzbot+a48e3d1a875240cab5de@syzkaller.appspotmail.com |
| Signed-off-by: Alan Stern <stern@rowland.harvard.edu> |
| Link: https://lore.kernel.org/r/YiEsYTPEE6lOCOA5@rowland.harvard.edu |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/usb/class/usbtmc.c | 13 ++++++++++--- |
| 1 file changed, 10 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/usb/class/usbtmc.c |
| +++ b/drivers/usb/class/usbtmc.c |
| @@ -1889,6 +1889,7 @@ static int usbtmc_ioctl_request(struct u |
| struct usbtmc_ctrlrequest request; |
| u8 *buffer = NULL; |
| int rv; |
| + unsigned int is_in, pipe; |
| unsigned long res; |
| |
| res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); |
| @@ -1898,12 +1899,14 @@ static int usbtmc_ioctl_request(struct u |
| if (request.req.wLength > USBTMC_BUFSIZE) |
| return -EMSGSIZE; |
| |
| + is_in = request.req.bRequestType & USB_DIR_IN; |
| + |
| if (request.req.wLength) { |
| buffer = kmalloc(request.req.wLength, GFP_KERNEL); |
| if (!buffer) |
| return -ENOMEM; |
| |
| - if ((request.req.bRequestType & USB_DIR_IN) == 0) { |
| + if (!is_in) { |
| /* Send control data to device */ |
| res = copy_from_user(buffer, request.data, |
| request.req.wLength); |
| @@ -1914,8 +1917,12 @@ static int usbtmc_ioctl_request(struct u |
| } |
| } |
| |
| + if (is_in) |
| + pipe = usb_rcvctrlpipe(data->usb_dev, 0); |
| + else |
| + pipe = usb_sndctrlpipe(data->usb_dev, 0); |
| rv = usb_control_msg(data->usb_dev, |
| - usb_rcvctrlpipe(data->usb_dev, 0), |
| + pipe, |
| request.req.bRequest, |
| request.req.bRequestType, |
| request.req.wValue, |
| @@ -1927,7 +1934,7 @@ static int usbtmc_ioctl_request(struct u |
| goto exit; |
| } |
| |
| - if (rv && (request.req.bRequestType & USB_DIR_IN)) { |
| + if (rv && is_in) { |
| /* Read control data from device */ |
| res = copy_to_user(request.data, buffer, rv); |
| if (res) |