Commit e7153bf7 authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by Marc Kleine-Budde

can: can_dropped_invalid_skb(): ensure an initialized headroom in outgoing CAN sk_buffs

KMSAN sysbot detected a read access to an untinitialized value in the
headroom of an outgoing CAN related sk_buff. When using CAN sockets this
area is filled appropriately - but when using a packet socket this
initialization is missing.

The problematic read access occurs in the CAN receive path which can
only be triggered when the sk_buff is sent through a (virtual) CAN
interface. So we check in the sending path whether we need to perform
the missing initializations.

Fixes: d3b58c47 ("can: replace timestamp as unique skb attribute")
Reported-by: syzbot+b02ff0707a97e4e79ebb@syzkaller.appspotmail.com
Signed-off-by: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Tested-by: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Cc: linux-stable <stable@vger.kernel.org> # >= v4.1
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 93bdc0eb
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h> #include <linux/can/led.h>
#include <linux/can/netlink.h> #include <linux/can/netlink.h>
#include <linux/can/skb.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
/* /*
...@@ -91,6 +92,36 @@ struct can_priv { ...@@ -91,6 +92,36 @@ struct can_priv {
#define get_can_dlc(i) (min_t(__u8, (i), CAN_MAX_DLC)) #define get_can_dlc(i) (min_t(__u8, (i), CAN_MAX_DLC))
#define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC)) #define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC))
/* Check for outgoing skbs that have not been created by the CAN subsystem */
static inline bool can_skb_headroom_valid(struct net_device *dev,
struct sk_buff *skb)
{
/* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
return false;
/* af_packet does not apply CAN skb specific settings */
if (skb->ip_summed == CHECKSUM_NONE) {
/* init headroom */
can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;
skb->ip_summed = CHECKSUM_UNNECESSARY;
/* preform proper loopback on capable devices */
if (dev->flags & IFF_ECHO)
skb->pkt_type = PACKET_LOOPBACK;
else
skb->pkt_type = PACKET_HOST;
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
}
return true;
}
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */ /* Drop a given socketbuffer if it does not contain a valid CAN frame. */
static inline bool can_dropped_invalid_skb(struct net_device *dev, static inline bool can_dropped_invalid_skb(struct net_device *dev,
struct sk_buff *skb) struct sk_buff *skb)
...@@ -108,6 +139,9 @@ static inline bool can_dropped_invalid_skb(struct net_device *dev, ...@@ -108,6 +139,9 @@ static inline bool can_dropped_invalid_skb(struct net_device *dev,
} else } else
goto inval_skb; goto inval_skb;
if (!can_skb_headroom_valid(dev, skb))
goto inval_skb;
return false; return false;
inval_skb: inval_skb:
......
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