From: Eric Dumazet Date: Wed, 10 Jun 2026 17:14:58 +0000 (+0000) Subject: ip6_tunnel: annotate data-races around t->err_count and t->err_time X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f6033078a9e671e3c8b83d387b91591a6f6a54e7;p=thirdparty%2Fkernel%2Flinux.git ip6_tunnel: annotate data-races around t->err_count and t->err_time ip6_tnl_xmit() and ipip6_tunnel_xmit() run locklessly (dev->lltx == true). ip6gre_err() and ipip6_err() also run locklessly. We need to add READ_ONCE() and WRITE_ONCE() annotations around t->err_count and t->err_time. Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Link: https://patch.msgid.link/20260610171458.1359630-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 48039f00b4bc4..795be59946f72 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -445,11 +445,11 @@ static int ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return 0; } - if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO)) - t->err_count++; + if (time_before(jiffies, READ_ONCE(t->err_time) + IP6TUNNEL_ERR_TIMEO)) + WRITE_ONCE(t->err_count, READ_ONCE(t->err_count) + 1); else - t->err_count = 1; - t->err_time = jiffies; + WRITE_ONCE(t->err_count, 1); + WRITE_ONCE(t->err_time, jiffies); return 0; } diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index bf5cd5d4adcdf..73fc5a0b8203a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1104,7 +1104,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, struct ipv6_tel_txoption opt; struct dst_entry *dst = NULL, *ndst = NULL; struct net_device *tdev; - int mtu; + int err_count, mtu; unsigned int eth_hlen = t->dev->type == ARPHRD_ETHER ? ETH_HLEN : 0; unsigned int psh_hlen = sizeof(struct ipv6hdr) + t->encap_hlen; unsigned int max_headroom = psh_hlen; @@ -1214,14 +1214,15 @@ route_lookup: goto tx_err_dst_release; } - if (t->err_count > 0) { + err_count = READ_ONCE(t->err_count); + if (err_count > 0) { if (time_before(jiffies, - t->err_time + IP6TUNNEL_ERR_TIMEO)) { - t->err_count--; + READ_ONCE(t->err_time) + IP6TUNNEL_ERR_TIMEO)) { + WRITE_ONCE(t->err_count, err_count - 1); dst_link_failure(skb); } else { - t->err_count = 0; + WRITE_ONCE(t->err_count, 0); } } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index b41e231a669be..64f0d1b622d3f 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -595,11 +595,11 @@ static int ipip6_err(struct sk_buff *skb, u32 info) if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) goto out; - if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) - t->err_count++; + if (time_before(jiffies, READ_ONCE(t->err_time) + IPTUNNEL_ERR_TIMEO)) + WRITE_ONCE(t->err_count, READ_ONCE(t->err_count) + 1); else - t->err_count = 1; - t->err_time = jiffies; + WRITE_ONCE(t->err_count, 1); + WRITE_ONCE(t->err_time, jiffies); out: return err; } @@ -909,8 +909,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *tdev; /* Device to other host */ unsigned int max_headroom; /* The extra header space needed */ __be32 dst = tiph->daddr; + int err_count, mtu; struct flowi4 fl4; - int mtu; u8 ttl; u8 protocol = IPPROTO_IPV6; int t_hlen = tunnel->hlen + sizeof(struct iphdr); @@ -987,13 +987,15 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, } } - if (tunnel->err_count > 0) { + err_count = READ_ONCE(tunnel->err_count); + if (err_count > 0) { if (time_before(jiffies, - tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { - tunnel->err_count--; + READ_ONCE(tunnel->err_time) + IPTUNNEL_ERR_TIMEO)) { + WRITE_ONCE(tunnel->err_count, err_count - 1); dst_link_failure(skb); - } else - tunnel->err_count = 0; + } else { + WRITE_ONCE(tunnel->err_count, 0); + } } /*