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

Commit 700a0715 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

usb: usbtmc: Fix bug in pipe direction for control transfers



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: default avatar <syzbot+a48e3d1a875240cab5de@syzkaller.appspotmail.com>
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/YiEsYTPEE6lOCOA5@rowland.harvard.edu


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2282a6eb
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -1889,6 +1889,7 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
	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 usbtmc_device_data *data,
	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 usbtmc_device_data *data,
		}
	}

	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 usbtmc_device_data *data,
		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)