can: mcba_usb: properly check endpoint type

Syzbot reported warning in usb_submit_urb() which is caused by wrong
endpoint type. We should check that in endpoint is actually present to
prevent this warning.

Found pipes are now saved to struct mcba_priv and code uses them
directly instead of making pipes in place.

Fail log:

| usb 5-1: BOGUS urb xfer, pipe 3 != type 1
| WARNING: CPU: 1 PID: 49 at drivers/usb/core/urb.c:502 usb_submit_urb+0xed2/0x18a0 drivers/usb/core/urb.c:502
| Modules linked in:
| CPU: 1 PID: 49 Comm: kworker/1:2 Not tainted 5.17.0-rc6-syzkaller-00184-g38f80f42147f #0
| Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.14.0-2 04/01/2014
| Workqueue: usb_hub_wq hub_event
| RIP: 0010:usb_submit_urb+0xed2/0x18a0 drivers/usb/core/urb.c:502
| ...
| Call Trace:
|  <TASK>
|  mcba_usb_start drivers/net/can/usb/mcba_usb.c:662 [inline]
|  mcba_usb_probe+0x8a3/0xc50 drivers/net/can/usb/mcba_usb.c:858
|  usb_probe_interface+0x315/0x7f0 drivers/usb/core/driver.c:396
|  call_driver_probe drivers/base/dd.c:517 [inline]

Fixes: 51f3baad7d ("can: mcba_usb: Add support for Microchip CAN BUS Analyzer")
Link: https://lore.kernel.org/all/20220313100903.10868-1-paskripkin@gmail.com
Reported-and-tested-by: syzbot+3bc1dce0cc0052d60fde@syzkaller.appspotmail.com
Signed-off-by: Pavel Skripkin <paskripkin@gmail.com>
Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Pavel Skripkin 2022-03-13 13:09:03 +03:00 committed by Marc Kleine-Budde
parent 04c9b00ba8
commit 136bed0bfd
1 changed files with 16 additions and 10 deletions

View File

@ -33,10 +33,6 @@
#define MCBA_USB_RX_BUFF_SIZE 64 #define MCBA_USB_RX_BUFF_SIZE 64
#define MCBA_USB_TX_BUFF_SIZE (sizeof(struct mcba_usb_msg)) #define MCBA_USB_TX_BUFF_SIZE (sizeof(struct mcba_usb_msg))
/* MCBA endpoint numbers */
#define MCBA_USB_EP_IN 1
#define MCBA_USB_EP_OUT 1
/* Microchip command id */ /* Microchip command id */
#define MBCA_CMD_RECEIVE_MESSAGE 0xE3 #define MBCA_CMD_RECEIVE_MESSAGE 0xE3
#define MBCA_CMD_I_AM_ALIVE_FROM_CAN 0xF5 #define MBCA_CMD_I_AM_ALIVE_FROM_CAN 0xF5
@ -83,6 +79,8 @@ struct mcba_priv {
atomic_t free_ctx_cnt; atomic_t free_ctx_cnt;
void *rxbuf[MCBA_MAX_RX_URBS]; void *rxbuf[MCBA_MAX_RX_URBS];
dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS]; dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS];
int rx_pipe;
int tx_pipe;
}; };
/* CAN frame */ /* CAN frame */
@ -268,10 +266,8 @@ static netdev_tx_t mcba_usb_xmit(struct mcba_priv *priv,
memcpy(buf, usb_msg, MCBA_USB_TX_BUFF_SIZE); memcpy(buf, usb_msg, MCBA_USB_TX_BUFF_SIZE);
usb_fill_bulk_urb(urb, priv->udev, usb_fill_bulk_urb(urb, priv->udev, priv->tx_pipe, buf, MCBA_USB_TX_BUFF_SIZE,
usb_sndbulkpipe(priv->udev, MCBA_USB_EP_OUT), buf, mcba_usb_write_bulk_callback, ctx);
MCBA_USB_TX_BUFF_SIZE, mcba_usb_write_bulk_callback,
ctx);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &priv->tx_submitted); usb_anchor_urb(urb, &priv->tx_submitted);
@ -607,7 +603,7 @@ static void mcba_usb_read_bulk_callback(struct urb *urb)
resubmit_urb: resubmit_urb:
usb_fill_bulk_urb(urb, priv->udev, usb_fill_bulk_urb(urb, priv->udev,
usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_OUT), priv->rx_pipe,
urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE, urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE,
mcba_usb_read_bulk_callback, priv); mcba_usb_read_bulk_callback, priv);
@ -652,7 +648,7 @@ static int mcba_usb_start(struct mcba_priv *priv)
urb->transfer_dma = buf_dma; urb->transfer_dma = buf_dma;
usb_fill_bulk_urb(urb, priv->udev, usb_fill_bulk_urb(urb, priv->udev,
usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_IN), priv->rx_pipe,
buf, MCBA_USB_RX_BUFF_SIZE, buf, MCBA_USB_RX_BUFF_SIZE,
mcba_usb_read_bulk_callback, priv); mcba_usb_read_bulk_callback, priv);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@ -806,6 +802,13 @@ static int mcba_usb_probe(struct usb_interface *intf,
struct mcba_priv *priv; struct mcba_priv *priv;
int err; int err;
struct usb_device *usbdev = interface_to_usbdev(intf); struct usb_device *usbdev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *in, *out;
err = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL, NULL);
if (err) {
dev_err(&intf->dev, "Can't find endpoints\n");
return err;
}
netdev = alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS); netdev = alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS);
if (!netdev) { if (!netdev) {
@ -851,6 +854,9 @@ static int mcba_usb_probe(struct usb_interface *intf,
goto cleanup_free_candev; goto cleanup_free_candev;
} }
priv->rx_pipe = usb_rcvbulkpipe(priv->udev, in->bEndpointAddress);
priv->tx_pipe = usb_sndbulkpipe(priv->udev, out->bEndpointAddress);
devm_can_led_init(netdev); devm_can_led_init(netdev);
/* Start USB dev only if we have successfully registered CAN device */ /* Start USB dev only if we have successfully registered CAN device */