ipv6/sit: use DEV_STATS_INC() to avoid data-races
authorEric Dumazet <edumazet@google.com>
Tue, 15 Nov 2022 08:53:56 +0000 (08:53 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Nov 2022 12:48:44 +0000 (12:48 +0000)
syzbot/KCSAN reported that multiple cpus are updating dev->stats.tx_error
concurrently.

This is because sit tunnels are NETIF_F_LLTX, meaning their ndo_start_xmit()
is not protected by a spinlock.

While original KCSAN report was about tx path, rx path has the same issue.

Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/sit.c

index 5703d3c..70d81bb 100644 (file)
@@ -694,7 +694,7 @@ static int ipip6_rcv(struct sk_buff *skb)
                skb->dev = tunnel->dev;
 
                if (packet_is_spoofed(skb, iph, tunnel)) {
-                       tunnel->dev->stats.rx_errors++;
+                       DEV_STATS_INC(tunnel->dev, rx_errors);
                        goto out;
                }
 
@@ -714,8 +714,8 @@ static int ipip6_rcv(struct sk_buff *skb)
                                net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
                                                     &iph->saddr, iph->tos);
                        if (err > 1) {
-                               ++tunnel->dev->stats.rx_frame_errors;
-                               ++tunnel->dev->stats.rx_errors;
+                               DEV_STATS_INC(tunnel->dev, rx_frame_errors);
+                               DEV_STATS_INC(tunnel->dev, rx_errors);
                                goto out;
                        }
                }
@@ -942,7 +942,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
        if (!rt) {
                rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
                if (IS_ERR(rt)) {
-                       dev->stats.tx_carrier_errors++;
+                       DEV_STATS_INC(dev, tx_carrier_errors);
                        goto tx_error_icmp;
                }
                dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr);
@@ -950,14 +950,14 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
 
        if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
                ip_rt_put(rt);
-               dev->stats.tx_carrier_errors++;
+               DEV_STATS_INC(dev, tx_carrier_errors);
                goto tx_error_icmp;
        }
        tdev = rt->dst.dev;
 
        if (tdev == dev) {
                ip_rt_put(rt);
-               dev->stats.collisions++;
+               DEV_STATS_INC(dev, collisions);
                goto tx_error;
        }
 
@@ -970,7 +970,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                mtu = dst_mtu(&rt->dst) - t_hlen;
 
                if (mtu < IPV4_MIN_MTU) {
-                       dev->stats.collisions++;
+                       DEV_STATS_INC(dev, collisions);
                        ip_rt_put(rt);
                        goto tx_error;
                }
@@ -1009,7 +1009,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
                if (!new_skb) {
                        ip_rt_put(rt);
-                       dev->stats.tx_dropped++;
+                       DEV_STATS_INC(dev, tx_dropped);
                        kfree_skb(skb);
                        return NETDEV_TX_OK;
                }
@@ -1039,7 +1039,7 @@ tx_error_icmp:
        dst_link_failure(skb);
 tx_error:
        kfree_skb(skb);
-       dev->stats.tx_errors++;
+       DEV_STATS_INC(dev, tx_errors);
        return NETDEV_TX_OK;
 }
 
@@ -1058,7 +1058,7 @@ static netdev_tx_t sit_tunnel_xmit__(struct sk_buff *skb,
        return NETDEV_TX_OK;
 tx_error:
        kfree_skb(skb);
-       dev->stats.tx_errors++;
+       DEV_STATS_INC(dev, tx_errors);
        return NETDEV_TX_OK;
 }
 
@@ -1087,7 +1087,7 @@ static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb,
        return NETDEV_TX_OK;
 
 tx_err:
-       dev->stats.tx_errors++;
+       DEV_STATS_INC(dev, tx_errors);
        kfree_skb(skb);
        return NETDEV_TX_OK;