Commit 46b55620 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-fixes-for-5.18-20220331' of...

Merge tag 'linux-can-fixes-for-5.18-20220331' of git://git.kernel.org/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: default avatarJakub Kicinski <kuba@kernel.org>
parents ff8376ad 50d34a0d
...@@ -1637,8 +1637,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) ...@@ -1637,8 +1637,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
if (err) if (err)
goto out_fail; goto out_fail;
can_put_echo_skb(skb, dev, 0, 0);
if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) { if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
cccr = m_can_read(cdev, M_CAN_CCCR); cccr = m_can_read(cdev, M_CAN_CCCR);
cccr &= ~CCCR_CMR_MASK; cccr &= ~CCCR_CMR_MASK;
...@@ -1655,6 +1653,9 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) ...@@ -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_CCCR, cccr);
} }
m_can_write(cdev, M_CAN_TXBTIE, 0x1); m_can_write(cdev, M_CAN_TXBTIE, 0x1);
can_put_echo_skb(skb, dev, 0, 0);
m_can_write(cdev, M_CAN_TXBAR, 0x1); m_can_write(cdev, M_CAN_TXBAR, 0x1);
/* End of xmit function for version 3.0.x */ /* End of xmit function for version 3.0.x */
} else { } else {
......
...@@ -1786,7 +1786,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id, ...@@ -1786,7 +1786,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
out_kfree_buf_rx: out_kfree_buf_rx:
kfree(buf_rx); kfree(buf_rx);
return 0; return err;
} }
#define MCP251XFD_QUIRK_ACTIVE(quirk) \ #define MCP251XFD_QUIRK_ACTIVE(quirk) \
......
...@@ -819,7 +819,6 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne ...@@ -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_unanchor_urb(urb);
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
dev_kfree_skb(skb);
atomic_dec(&dev->active_tx_urbs); atomic_dec(&dev->active_tx_urbs);
......
...@@ -1092,6 +1092,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, ...@@ -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->data_bt_const.brp_inc = le32_to_cpu(bt_const_extended->dbrp_inc);
dev->can.data_bittiming_const = &dev->data_bt_const; dev->can.data_bittiming_const = &dev->data_bt_const;
kfree(bt_const_extended);
} }
SET_NETDEV_DEV(netdev, &intf->dev); SET_NETDEV_DEV(netdev, &intf->dev);
......
...@@ -33,10 +33,6 @@ ...@@ -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 { ...@@ -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, ...@@ -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);
...@@ -364,7 +360,6 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb, ...@@ -364,7 +360,6 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
xmit_failed: xmit_failed:
can_free_echo_skb(priv->netdev, ctx->ndx, NULL); can_free_echo_skb(priv->netdev, ctx->ndx, NULL);
mcba_usb_free_ctx(ctx); mcba_usb_free_ctx(ctx);
dev_kfree_skb(skb);
stats->tx_dropped++; stats->tx_dropped++;
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -608,7 +603,7 @@ static void mcba_usb_read_bulk_callback(struct urb *urb) ...@@ -608,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);
...@@ -653,7 +648,7 @@ static int mcba_usb_start(struct mcba_priv *priv) ...@@ -653,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;
...@@ -807,6 +802,13 @@ static int mcba_usb_probe(struct usb_interface *intf, ...@@ -807,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) {
...@@ -852,6 +854,9 @@ static int mcba_usb_probe(struct usb_interface *intf, ...@@ -852,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 */
......
...@@ -663,9 +663,20 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, ...@@ -663,9 +663,20 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
atomic_inc(&priv->active_tx_urbs); atomic_inc(&priv->active_tx_urbs);
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err)) if (unlikely(err)) {
goto failed; can_free_echo_skb(netdev, context->echo_index, NULL);
else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
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 */ /* Slow down tx path */
netif_stop_queue(netdev); netif_stop_queue(netdev);
...@@ -684,19 +695,6 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, ...@@ -684,19 +695,6 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY; 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: nomembuf:
usb_free_urb(urb); usb_free_urb(urb);
......
...@@ -1050,7 +1050,7 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, ...@@ -1050,7 +1050,7 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
int noblock = flags & MSG_DONTWAIT; int noblock = flags & MSG_DONTWAIT;
int ret = 0; int ret = 0;
if (flags & ~(MSG_DONTWAIT | MSG_TRUNC)) if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK))
return -EINVAL; return -EINVAL;
if (!so->bound) if (!so->bound)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment