1 From e7153bf70c3496bac00e7e4f395bb8d8394ac0ea Mon Sep 17 00:00:00 2001
2 From: Oliver Hartkopp <socketcan@hartkopp.net>
3 Date: Sat, 7 Dec 2019 19:34:18 +0100
4 Subject: can: can_dropped_invalid_skb(): ensure an initialized headroom in outgoing CAN sk_buffs
6 From: Oliver Hartkopp <socketcan@hartkopp.net>
8 commit e7153bf70c3496bac00e7e4f395bb8d8394ac0ea upstream.
10 KMSAN sysbot detected a read access to an untinitialized value in the
11 headroom of an outgoing CAN related sk_buff. When using CAN sockets this
12 area is filled appropriately - but when using a packet socket this
13 initialization is missing.
15 The problematic read access occurs in the CAN receive path which can
16 only be triggered when the sk_buff is sent through a (virtual) CAN
17 interface. So we check in the sending path whether we need to perform
18 the missing initializations.
20 Fixes: d3b58c47d330d ("can: replace timestamp as unique skb attribute")
21 Reported-by: syzbot+b02ff0707a97e4e79ebb@syzkaller.appspotmail.com
22 Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
23 Tested-by: Oliver Hartkopp <socketcan@hartkopp.net>
24 Cc: linux-stable <stable@vger.kernel.org> # >= v4.1
25 Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
26 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
29 include/linux/can/dev.h | 34 ++++++++++++++++++++++++++++++++++
30 1 file changed, 34 insertions(+)
32 --- a/include/linux/can/dev.h
33 +++ b/include/linux/can/dev.h
35 #include <linux/can/error.h>
36 #include <linux/can/led.h>
37 #include <linux/can/netlink.h>
38 +#include <linux/can/skb.h>
39 #include <linux/netdevice.h>
42 @@ -91,6 +92,36 @@ struct can_priv {
43 #define get_can_dlc(i) (min_t(__u8, (i), CAN_MAX_DLC))
44 #define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC))
46 +/* Check for outgoing skbs that have not been created by the CAN subsystem */
47 +static inline bool can_skb_headroom_valid(struct net_device *dev,
48 + struct sk_buff *skb)
50 + /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
51 + if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
54 + /* af_packet does not apply CAN skb specific settings */
55 + if (skb->ip_summed == CHECKSUM_NONE) {
57 + can_skb_prv(skb)->ifindex = dev->ifindex;
58 + can_skb_prv(skb)->skbcnt = 0;
60 + skb->ip_summed = CHECKSUM_UNNECESSARY;
62 + /* preform proper loopback on capable devices */
63 + if (dev->flags & IFF_ECHO)
64 + skb->pkt_type = PACKET_LOOPBACK;
66 + skb->pkt_type = PACKET_HOST;
68 + skb_reset_mac_header(skb);
69 + skb_reset_network_header(skb);
70 + skb_reset_transport_header(skb);
76 /* Drop a given socketbuffer if it does not contain a valid CAN frame. */
77 static inline bool can_dropped_invalid_skb(struct net_device *dev,
79 @@ -108,6 +139,9 @@ static inline bool can_dropped_invalid_s
83 + if (!can_skb_headroom_valid(dev, skb))