Skip to content

Commit

Permalink
Merge tag 'linux-can-fixes-for-5.18-20220331' of git://git.kernel.org…
Browse files Browse the repository at this point in the history
…/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2022-03-31

The first patch is by Oliver Hartkopp and fixes MSG_PEEK feature in
the CAN ISOTP protocol (broken in net-next for v5.18 only).

Tom Rix's patch for the mcp251xfd driver fixes the propagation of an
error value in case of an error.

A patch by me for the m_can driver fixes a use-after-free in the xmit
handler for m_can IP cores v3.0.x.

Hangyu Hua contributes 3 patches fixing the same double free in the
error path of the xmit handler in the ems_usb, usb_8dev and mcba_usb
USB CAN driver.

Pavel Skripkin contributes a patch for the mcba_usb driver to properly
check the endpoint type.

The last patch is by me and fixes a mem leak in the gs_usb, which was
introduced in net-next for v5.18.

* tag 'linux-can-fixes-for-5.18-20220331' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  can: gs_usb: gs_make_candev(): fix memory leak for devices with extended bit timing configuration
  can: mcba_usb: properly check endpoint type
  can: mcba_usb: mcba_usb_start_xmit(): fix double dev_kfree_skb in error path
  can: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error path
  can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path
  can: m_can: m_can_tx_handler(): fix use after free of skb
  can: mcp251xfd: mcp251xfd_register_get_dev_id(): fix return of error value
  can: isotp: restore accidentally removed MSG_PEEK feature
====================

Link: https://lore.kernel.org/r/
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Mar 31, 2022
2 parents ff8376a + 50d34a0 commit 46b5562
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 32 deletions.
5 changes: 3 additions & 2 deletions drivers/net/can/m_can/m_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -1637,8 +1637,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
if (err)
goto out_fail;

can_put_echo_skb(skb, dev, 0, 0);

if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
cccr = m_can_read(cdev, M_CAN_CCCR);
cccr &= ~CCCR_CMR_MASK;
Expand All @@ -1655,6 +1653,9 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
m_can_write(cdev, M_CAN_CCCR, cccr);
}
m_can_write(cdev, M_CAN_TXBTIE, 0x1);

can_put_echo_skb(skb, dev, 0, 0);

m_can_write(cdev, M_CAN_TXBAR, 0x1);
/* End of xmit function for version 3.0.x */
} else {
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1786,7 +1786,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
out_kfree_buf_rx:
kfree(buf_rx);

return 0;
return err;
}

#define MCP251XFD_QUIRK_ACTIVE(quirk) \
Expand Down
1 change: 0 additions & 1 deletion drivers/net/can/usb/ems_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,6 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne

usb_unanchor_urb(urb);
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
dev_kfree_skb(skb);

atomic_dec(&dev->active_tx_urbs);

Expand Down
2 changes: 2 additions & 0 deletions drivers/net/can/usb/gs_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,8 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev->data_bt_const.brp_inc = le32_to_cpu(bt_const_extended->dbrp_inc);

dev->can.data_bittiming_const = &dev->data_bt_const;

kfree(bt_const_extended);
}

SET_NETDEV_DEV(netdev, &intf->dev);
Expand Down
27 changes: 16 additions & 11 deletions drivers/net/can/usb/mcba_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@
#define MCBA_USB_RX_BUFF_SIZE 64
#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 */
#define MBCA_CMD_RECEIVE_MESSAGE 0xE3
#define MBCA_CMD_I_AM_ALIVE_FROM_CAN 0xF5
Expand Down Expand Up @@ -83,6 +79,8 @@ struct mcba_priv {
atomic_t free_ctx_cnt;
void *rxbuf[MCBA_MAX_RX_URBS];
dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS];
int rx_pipe;
int tx_pipe;
};

/* CAN frame */
Expand Down Expand Up @@ -268,10 +266,8 @@ static netdev_tx_t mcba_usb_xmit(struct mcba_priv *priv,

memcpy(buf, usb_msg, MCBA_USB_TX_BUFF_SIZE);

usb_fill_bulk_urb(urb, priv->udev,
usb_sndbulkpipe(priv->udev, MCBA_USB_EP_OUT), buf,
MCBA_USB_TX_BUFF_SIZE, mcba_usb_write_bulk_callback,
ctx);
usb_fill_bulk_urb(urb, priv->udev, priv->tx_pipe, buf, MCBA_USB_TX_BUFF_SIZE,
mcba_usb_write_bulk_callback, ctx);

urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &priv->tx_submitted);
Expand Down Expand Up @@ -364,7 +360,6 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
xmit_failed:
can_free_echo_skb(priv->netdev, ctx->ndx, NULL);
mcba_usb_free_ctx(ctx);
dev_kfree_skb(skb);
stats->tx_dropped++;

return NETDEV_TX_OK;
Expand Down Expand Up @@ -608,7 +603,7 @@ static void mcba_usb_read_bulk_callback(struct urb *urb)
resubmit_urb:

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,
mcba_usb_read_bulk_callback, priv);

Expand Down Expand Up @@ -653,7 +648,7 @@ static int mcba_usb_start(struct mcba_priv *priv)
urb->transfer_dma = buf_dma;

usb_fill_bulk_urb(urb, priv->udev,
usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_IN),
priv->rx_pipe,
buf, MCBA_USB_RX_BUFF_SIZE,
mcba_usb_read_bulk_callback, priv);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
Expand Down Expand Up @@ -807,6 +802,13 @@ static int mcba_usb_probe(struct usb_interface *intf,
struct mcba_priv *priv;
int err;
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);
if (!netdev) {
Expand Down Expand Up @@ -852,6 +854,9 @@ static int mcba_usb_probe(struct usb_interface *intf,
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);

/* Start USB dev only if we have successfully registered CAN device */
Expand Down
30 changes: 14 additions & 16 deletions drivers/net/can/usb/usb_8dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -663,9 +663,20 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
atomic_inc(&priv->active_tx_urbs);

err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err))
goto failed;
else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
if (unlikely(err)) {
can_free_echo_skb(netdev, context->echo_index, NULL);

usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);

atomic_dec(&priv->active_tx_urbs);

if (err == -ENODEV)
netif_device_detach(netdev);
else
netdev_warn(netdev, "failed tx_urb %d\n", err);
stats->tx_dropped++;
} else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
/* Slow down tx path */
netif_stop_queue(netdev);

Expand All @@ -684,19 +695,6 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,

return NETDEV_TX_BUSY;

failed:
can_free_echo_skb(netdev, context->echo_index, NULL);

usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);

atomic_dec(&priv->active_tx_urbs);

if (err == -ENODEV)
netif_device_detach(netdev);
else
netdev_warn(netdev, "failed tx_urb %d\n", err);

nomembuf:
usb_free_urb(urb);

Expand Down
2 changes: 1 addition & 1 deletion net/can/isotp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,7 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
int noblock = flags & MSG_DONTWAIT;
int ret = 0;

if (flags & ~(MSG_DONTWAIT | MSG_TRUNC))
if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK))
return -EINVAL;

if (!so->bound)
Expand Down

0 comments on commit 46b5562

Please sign in to comment.