Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8bd6980a authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by Greg Kroah-Hartman
Browse files

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



commit e7153bf70c3496bac00e7e4f395bb8d8394ac0ea upstream.

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: default avatar <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>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 67e3a9f3
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/can/netlink.h>
#include <linux/can/skb.h>
#include <linux/netdevice.h>

/*
@@ -91,6 +92,36 @@ struct can_priv {
#define get_can_dlc(i)		(min_t(__u8, (i), CAN_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. */
static inline bool can_dropped_invalid_skb(struct net_device *dev,
					  struct sk_buff *skb)
@@ -108,6 +139,9 @@ static inline bool can_dropped_invalid_skb(struct net_device *dev,
	} else
		goto inval_skb;

	if (!can_skb_headroom_valid(dev, skb))
		goto inval_skb;

	return false;

inval_skb: