Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: dev: fix skb drop check

In commit a6d190f8c767 ("can: skb: drop tx skb if in listen only
mode") the priv->ctrlmode element is read even on virtual CAN
interfaces that do not create the struct can_priv at startup. This
out-of-bounds read may lead to CAN frame drops for virtual CAN
interfaces like vcan and vxcan.

This patch mainly reverts the original commit and adds a new helper
for CAN interface drivers that provide the required information in
struct can_priv.

Fixes: a6d190f8c767 ("can: skb: drop tx skb if in listen only mode")
Reported-by: Dariusz Stojaczyk <Dariusz.Stojaczyk@opensynergy.com>
Cc: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Cc: Max Staudt <max@enpas.org>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Acked-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://lore.kernel.org/all/20221102095431.36831-1-socketcan@hartkopp.net
Cc: stable@vger.kernel.org # 6.0.x
[mkl: patch pch_can, too]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
ae64438b 3eb3d283

+51 -43
+1 -1
drivers/net/can/at91_can.c
··· 452 452 unsigned int mb, prio; 453 453 u32 reg_mid, reg_mcr; 454 454 455 - if (can_dropped_invalid_skb(dev, skb)) 455 + if (can_dev_dropped_skb(dev, skb)) 456 456 return NETDEV_TX_OK; 457 457 458 458 mb = get_tx_next_mb(priv);
+1 -1
drivers/net/can/c_can/c_can_main.c
··· 457 457 struct c_can_tx_ring *tx_ring = &priv->tx; 458 458 u32 idx, obj, cmd = IF_COMM_TX; 459 459 460 - if (can_dropped_invalid_skb(dev, skb)) 460 + if (can_dev_dropped_skb(dev, skb)) 461 461 return NETDEV_TX_OK; 462 462 463 463 if (c_can_tx_busy(priv, tx_ring))
+1 -1
drivers/net/can/can327.c
··· 813 813 struct can327 *elm = netdev_priv(dev); 814 814 struct can_frame *frame = (struct can_frame *)skb->data; 815 815 816 - if (can_dropped_invalid_skb(dev, skb)) 816 + if (can_dev_dropped_skb(dev, skb)) 817 817 return NETDEV_TX_OK; 818 818 819 819 /* We shouldn't get here after a hardware fault:
+1 -1
drivers/net/can/cc770/cc770.c
··· 429 429 struct cc770_priv *priv = netdev_priv(dev); 430 430 unsigned int mo = obj2msgobj(CC770_OBJ_TX); 431 431 432 - if (can_dropped_invalid_skb(dev, skb)) 432 + if (can_dev_dropped_skb(dev, skb)) 433 433 return NETDEV_TX_OK; 434 434 435 435 netif_stop_queue(dev);
+1 -1
drivers/net/can/ctucanfd/ctucanfd_base.c
··· 600 600 bool ok; 601 601 unsigned long flags; 602 602 603 - if (can_dropped_invalid_skb(ndev, skb)) 603 + if (can_dev_dropped_skb(ndev, skb)) 604 604 return NETDEV_TX_OK; 605 605 606 606 if (unlikely(!CTU_CAN_FD_TXTNF(priv))) {
+1 -9
drivers/net/can/dev/skb.c
··· 5 5 */ 6 6 7 7 #include <linux/can/dev.h> 8 - #include <linux/can/netlink.h> 9 8 #include <linux/module.h> 10 9 11 10 #define MOD_DESC "CAN device driver interface" ··· 336 337 /* Drop a given socketbuffer if it does not contain a valid CAN frame. */ 337 338 bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb) 338 339 { 339 - struct can_priv *priv = netdev_priv(dev); 340 - 341 340 switch (ntohs(skb->protocol)) { 342 341 case ETH_P_CAN: 343 342 if (!can_is_can_skb(skb)) ··· 356 359 goto inval_skb; 357 360 } 358 361 359 - if (!can_skb_headroom_valid(dev, skb)) { 362 + if (!can_skb_headroom_valid(dev, skb)) 360 363 goto inval_skb; 361 - } else if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) { 362 - netdev_info_once(dev, 363 - "interface in listen only mode, dropping skb\n"); 364 - goto inval_skb; 365 - } 366 364 367 365 return false; 368 366
+1 -1
drivers/net/can/flexcan/flexcan-core.c
··· 742 742 u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_fd_len2dlc(cfd->len)) << 16); 743 743 int i; 744 744 745 - if (can_dropped_invalid_skb(dev, skb)) 745 + if (can_dev_dropped_skb(dev, skb)) 746 746 return NETDEV_TX_OK; 747 747 748 748 netif_stop_queue(dev);
+1 -1
drivers/net/can/grcan.c
··· 1345 1345 unsigned long flags; 1346 1346 u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT; 1347 1347 1348 - if (can_dropped_invalid_skb(dev, skb)) 1348 + if (can_dev_dropped_skb(dev, skb)) 1349 1349 return NETDEV_TX_OK; 1350 1350 1351 1351 /* Trying to transmit in silent mode will generate error interrupts, but
+1 -1
drivers/net/can/ifi_canfd/ifi_canfd.c
··· 860 860 u32 txst, txid, txdlc; 861 861 int i; 862 862 863 - if (can_dropped_invalid_skb(ndev, skb)) 863 + if (can_dev_dropped_skb(ndev, skb)) 864 864 return NETDEV_TX_OK; 865 865 866 866 /* Check if the TX buffer is full */
+1 -1
drivers/net/can/janz-ican3.c
··· 1693 1693 void __iomem *desc_addr; 1694 1694 unsigned long flags; 1695 1695 1696 - if (can_dropped_invalid_skb(ndev, skb)) 1696 + if (can_dev_dropped_skb(ndev, skb)) 1697 1697 return NETDEV_TX_OK; 1698 1698 1699 1699 spin_lock_irqsave(&mod->lock, flags);
+1 -1
drivers/net/can/kvaser_pciefd.c
··· 772 772 int nwords; 773 773 u8 count; 774 774 775 - if (can_dropped_invalid_skb(netdev, skb)) 775 + if (can_dev_dropped_skb(netdev, skb)) 776 776 return NETDEV_TX_OK; 777 777 778 778 nwords = kvaser_pciefd_prepare_tx_packet(&packet, can, skb);
+1 -1
drivers/net/can/m_can/m_can.c
··· 1721 1721 { 1722 1722 struct m_can_classdev *cdev = netdev_priv(dev); 1723 1723 1724 - if (can_dropped_invalid_skb(dev, skb)) 1724 + if (can_dev_dropped_skb(dev, skb)) 1725 1725 return NETDEV_TX_OK; 1726 1726 1727 1727 if (cdev->is_peripheral) {
+1 -1
drivers/net/can/mscan/mscan.c
··· 191 191 int i, rtr, buf_id; 192 192 u32 can_id; 193 193 194 - if (can_dropped_invalid_skb(dev, skb)) 194 + if (can_dev_dropped_skb(dev, skb)) 195 195 return NETDEV_TX_OK; 196 196 197 197 out_8(&regs->cantier, 0);
+1 -1
drivers/net/can/pch_can.c
··· 882 882 int i; 883 883 u32 id2; 884 884 885 - if (can_dropped_invalid_skb(ndev, skb)) 885 + if (can_dev_dropped_skb(ndev, skb)) 886 886 return NETDEV_TX_OK; 887 887 888 888 tx_obj_no = priv->tx_obj;
+1 -1
drivers/net/can/peak_canfd/peak_canfd.c
··· 651 651 int room_left; 652 652 u8 len; 653 653 654 - if (can_dropped_invalid_skb(ndev, skb)) 654 + if (can_dev_dropped_skb(ndev, skb)) 655 655 return NETDEV_TX_OK; 656 656 657 657 msg_size = ALIGN(sizeof(*msg) + cf->len, 4);
+1 -1
drivers/net/can/rcar/rcar_can.c
··· 590 590 struct can_frame *cf = (struct can_frame *)skb->data; 591 591 u32 data, i; 592 592 593 - if (can_dropped_invalid_skb(ndev, skb)) 593 + if (can_dev_dropped_skb(ndev, skb)) 594 594 return NETDEV_TX_OK; 595 595 596 596 if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
+1 -1
drivers/net/can/rcar/rcar_canfd.c
··· 1481 1481 unsigned long flags; 1482 1482 u32 ch = priv->channel; 1483 1483 1484 - if (can_dropped_invalid_skb(ndev, skb)) 1484 + if (can_dev_dropped_skb(ndev, skb)) 1485 1485 return NETDEV_TX_OK; 1486 1486 1487 1487 if (cf->can_id & CAN_EFF_FLAG) {
+1 -1
drivers/net/can/sja1000/sja1000.c
··· 291 291 u8 cmd_reg_val = 0x00; 292 292 int i; 293 293 294 - if (can_dropped_invalid_skb(dev, skb)) 294 + if (can_dev_dropped_skb(dev, skb)) 295 295 return NETDEV_TX_OK; 296 296 297 297 netif_stop_queue(dev);
+1 -1
drivers/net/can/slcan/slcan-core.c
··· 594 594 { 595 595 struct slcan *sl = netdev_priv(dev); 596 596 597 - if (can_dropped_invalid_skb(dev, skb)) 597 + if (can_dev_dropped_skb(dev, skb)) 598 598 return NETDEV_TX_OK; 599 599 600 600 spin_lock(&sl->lock);
+1 -1
drivers/net/can/softing/softing_main.c
··· 60 60 struct can_frame *cf = (struct can_frame *)skb->data; 61 61 uint8_t buf[DPRAM_TX_SIZE]; 62 62 63 - if (can_dropped_invalid_skb(dev, skb)) 63 + if (can_dev_dropped_skb(dev, skb)) 64 64 return NETDEV_TX_OK; 65 65 66 66 spin_lock(&card->spin);
+1 -1
drivers/net/can/spi/hi311x.c
··· 373 373 return NETDEV_TX_BUSY; 374 374 } 375 375 376 - if (can_dropped_invalid_skb(net, skb)) 376 + if (can_dev_dropped_skb(net, skb)) 377 377 return NETDEV_TX_OK; 378 378 379 379 netif_stop_queue(net);
+1 -1
drivers/net/can/spi/mcp251x.c
··· 789 789 return NETDEV_TX_BUSY; 790 790 } 791 791 792 - if (can_dropped_invalid_skb(net, skb)) 792 + if (can_dev_dropped_skb(net, skb)) 793 793 return NETDEV_TX_OK; 794 794 795 795 netif_stop_queue(net);
+1 -1
drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c
··· 172 172 u8 tx_head; 173 173 int err; 174 174 175 - if (can_dropped_invalid_skb(ndev, skb)) 175 + if (can_dev_dropped_skb(ndev, skb)) 176 176 return NETDEV_TX_OK; 177 177 178 178 if (mcp251xfd_tx_busy(priv, tx_ring))
+1 -1
drivers/net/can/sun4i_can.c
··· 429 429 canid_t id; 430 430 int i; 431 431 432 - if (can_dropped_invalid_skb(dev, skb)) 432 + if (can_dev_dropped_skb(dev, skb)) 433 433 return NETDEV_TX_OK; 434 434 435 435 netif_stop_queue(dev);
+1 -1
drivers/net/can/ti_hecc.c
··· 470 470 u32 mbxno, mbx_mask, data; 471 471 unsigned long flags; 472 472 473 - if (can_dropped_invalid_skb(ndev, skb)) 473 + if (can_dev_dropped_skb(ndev, skb)) 474 474 return NETDEV_TX_OK; 475 475 476 476 mbxno = get_tx_head_mb(priv);
+1 -1
drivers/net/can/usb/ems_usb.c
··· 747 747 size_t size = CPC_HEADER_SIZE + CPC_MSG_HEADER_LEN 748 748 + sizeof(struct cpc_can_msg); 749 749 750 - if (can_dropped_invalid_skb(netdev, skb)) 750 + if (can_dev_dropped_skb(netdev, skb)) 751 751 return NETDEV_TX_OK; 752 752 753 753 /* create a URB, and a buffer for it, and copy the data to the URB */
+1 -1
drivers/net/can/usb/esd_usb.c
··· 725 725 int ret = NETDEV_TX_OK; 726 726 size_t size = sizeof(struct esd_usb_msg); 727 727 728 - if (can_dropped_invalid_skb(netdev, skb)) 728 + if (can_dev_dropped_skb(netdev, skb)) 729 729 return NETDEV_TX_OK; 730 730 731 731 /* create a URB, and a buffer for it, and copy the data to the URB */
+1 -1
drivers/net/can/usb/etas_es58x/es58x_core.c
··· 1913 1913 unsigned int frame_len; 1914 1914 int ret; 1915 1915 1916 - if (can_dropped_invalid_skb(netdev, skb)) { 1916 + if (can_dev_dropped_skb(netdev, skb)) { 1917 1917 if (priv->tx_urb) 1918 1918 goto xmit_commit; 1919 1919 return NETDEV_TX_OK;
+1 -1
drivers/net/can/usb/gs_usb.c
··· 723 723 unsigned int idx; 724 724 struct gs_tx_context *txc; 725 725 726 - if (can_dropped_invalid_skb(netdev, skb)) 726 + if (can_dev_dropped_skb(netdev, skb)) 727 727 return NETDEV_TX_OK; 728 728 729 729 /* find an empty context to keep track of transmission */
+1 -1
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
··· 570 570 unsigned int i; 571 571 unsigned long flags; 572 572 573 - if (can_dropped_invalid_skb(netdev, skb)) 573 + if (can_dev_dropped_skb(netdev, skb)) 574 574 return NETDEV_TX_OK; 575 575 576 576 urb = usb_alloc_urb(0, GFP_ATOMIC);
+1 -1
drivers/net/can/usb/mcba_usb.c
··· 311 311 .cmd_id = MBCA_CMD_TRANSMIT_MESSAGE_EV 312 312 }; 313 313 314 - if (can_dropped_invalid_skb(netdev, skb)) 314 + if (can_dev_dropped_skb(netdev, skb)) 315 315 return NETDEV_TX_OK; 316 316 317 317 ctx = mcba_usb_get_free_ctx(priv, cf);
+1 -1
drivers/net/can/usb/peak_usb/pcan_usb_core.c
··· 351 351 int i, err; 352 352 size_t size = dev->adapter->tx_buffer_size; 353 353 354 - if (can_dropped_invalid_skb(netdev, skb)) 354 + if (can_dev_dropped_skb(netdev, skb)) 355 355 return NETDEV_TX_OK; 356 356 357 357 for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++)
+1 -1
drivers/net/can/usb/ucan.c
··· 1120 1120 struct can_frame *cf = (struct can_frame *)skb->data; 1121 1121 1122 1122 /* check skb */ 1123 - if (can_dropped_invalid_skb(netdev, skb)) 1123 + if (can_dev_dropped_skb(netdev, skb)) 1124 1124 return NETDEV_TX_OK; 1125 1125 1126 1126 /* allocate a context and slow down tx path, if fifo state is low */
+1 -1
drivers/net/can/usb/usb_8dev.c
··· 602 602 int i, err; 603 603 size_t size = sizeof(struct usb_8dev_tx_msg); 604 604 605 - if (can_dropped_invalid_skb(netdev, skb)) 605 + if (can_dev_dropped_skb(netdev, skb)) 606 606 return NETDEV_TX_OK; 607 607 608 608 /* create a URB, and a buffer for it, and copy the data to the URB */
+1 -1
drivers/net/can/xilinx_can.c
··· 743 743 struct xcan_priv *priv = netdev_priv(ndev); 744 744 int ret; 745 745 746 - if (can_dropped_invalid_skb(ndev, skb)) 746 + if (can_dev_dropped_skb(ndev, skb)) 747 747 return NETDEV_TX_OK; 748 748 749 749 if (priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES)
+16
include/linux/can/dev.h
··· 152 152 return (mtu >= CANXL_MIN_MTU && mtu <= CANXL_MAX_MTU); 153 153 } 154 154 155 + /* drop skb if it does not contain a valid CAN frame for sending */ 156 + static inline bool can_dev_dropped_skb(struct net_device *dev, struct sk_buff *skb) 157 + { 158 + struct can_priv *priv = netdev_priv(dev); 159 + 160 + if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) { 161 + netdev_info_once(dev, 162 + "interface in listen only mode, dropping skb\n"); 163 + kfree_skb(skb); 164 + dev->stats.tx_dropped++; 165 + return true; 166 + } 167 + 168 + return can_dropped_invalid_skb(dev, skb); 169 + } 170 + 155 171 void can_setup(struct net_device *dev); 156 172 157 173 struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,