| From 31e0456de5be379b10fea0fa94a681057114a96e Mon Sep 17 00:00:00 2001 |
| From: Alan Stern <stern@rowland.harvard.edu> |
| Date: Tue, 7 May 2019 12:39:47 -0400 |
| Subject: media: usb: siano: Fix general protection fault in smsusb |
| |
| From: Alan Stern <stern@rowland.harvard.edu> |
| |
| commit 31e0456de5be379b10fea0fa94a681057114a96e upstream. |
| |
| The syzkaller USB fuzzer found a general-protection-fault bug in the |
| smsusb part of the Siano DVB driver. The fault occurs during probe |
| because the driver assumes without checking that the device has both |
| IN and OUT endpoints and the IN endpoint is ep1. |
| |
| By slightly rearranging the driver's initialization code, we can make |
| the appropriate checks early on and thus avoid the problem. If the |
| expected endpoints aren't present, the new code safely returns -ENODEV |
| from the probe routine. |
| |
| Signed-off-by: Alan Stern <stern@rowland.harvard.edu> |
| Reported-and-tested-by: syzbot+53f029db71c19a47325a@syzkaller.appspotmail.com |
| CC: <stable@vger.kernel.org> |
| Reviewed-by: Johan Hovold <johan@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/media/usb/siano/smsusb.c | 33 ++++++++++++++++++++------------- |
| 1 file changed, 20 insertions(+), 13 deletions(-) |
| |
| --- a/drivers/media/usb/siano/smsusb.c |
| +++ b/drivers/media/usb/siano/smsusb.c |
| @@ -401,6 +401,7 @@ static int smsusb_init_device(struct usb |
| struct smsusb_device_t *dev; |
| void *mdev; |
| int i, rc; |
| + int in_maxp; |
| |
| /* create device object */ |
| dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL); |
| @@ -412,6 +413,24 @@ static int smsusb_init_device(struct usb |
| dev->udev = interface_to_usbdev(intf); |
| dev->state = SMSUSB_DISCONNECTED; |
| |
| + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { |
| + struct usb_endpoint_descriptor *desc = |
| + &intf->cur_altsetting->endpoint[i].desc; |
| + |
| + if (desc->bEndpointAddress & USB_DIR_IN) { |
| + dev->in_ep = desc->bEndpointAddress; |
| + in_maxp = usb_endpoint_maxp(desc); |
| + } else { |
| + dev->out_ep = desc->bEndpointAddress; |
| + } |
| + } |
| + |
| + pr_debug("in_ep = %02x, out_ep = %02x\n", dev->in_ep, dev->out_ep); |
| + if (!dev->in_ep || !dev->out_ep) { /* Missing endpoints? */ |
| + smsusb_term_device(intf); |
| + return -ENODEV; |
| + } |
| + |
| params.device_type = sms_get_board(board_id)->type; |
| |
| switch (params.device_type) { |
| @@ -426,24 +445,12 @@ static int smsusb_init_device(struct usb |
| /* fall-thru */ |
| default: |
| dev->buffer_size = USB2_BUFFER_SIZE; |
| - dev->response_alignment = |
| - le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - |
| - sizeof(struct sms_msg_hdr); |
| + dev->response_alignment = in_maxp - sizeof(struct sms_msg_hdr); |
| |
| params.flags |= SMS_DEVICE_FAMILY2; |
| break; |
| } |
| |
| - for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { |
| - if (intf->cur_altsetting->endpoint[i].desc. bEndpointAddress & USB_DIR_IN) |
| - dev->in_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress; |
| - else |
| - dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress; |
| - } |
| - |
| - pr_debug("in_ep = %02x, out_ep = %02x\n", |
| - dev->in_ep, dev->out_ep); |
| - |
| params.device = &dev->udev->dev; |
| params.usb_device = dev->udev; |
| params.buffer_size = dev->buffer_size; |