lkml.org 
[lkml]   [2020]   [Jan]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 36/78] can: can_dropped_invalid_skb(): ensure an initialized headroom in outgoing CAN sk_buffs
    Date
    From: Oliver Hartkopp <socketcan@hartkopp.net>

    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: d3b58c47d330d ("can: replace timestamp as unique skb attribute")
    Reported-by: syzbot+b02ff0707a97e4e79ebb@syzkaller.appspotmail.com
    Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
    Tested-by: Oliver Hartkopp <socketcan@hartkopp.net>
    Cc: linux-stable <stable@vger.kernel.org> # >= v4.1
    Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    include/linux/can/dev.h | 34 ++++++++++++++++++++++++++++++++++
    1 file changed, 34 insertions(+)

    --- a/include/linux/can/dev.h
    +++ b/include/linux/can/dev.h
    @@ -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_s
    } else
    goto inval_skb;

    + if (!can_skb_headroom_valid(dev, skb))
    + goto inval_skb;
    +
    return false;

    inval_skb:

    \
     
     \ /
      Last update: 2020-01-14 11:06    [W:4.054 / U:1.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site