Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ping: annotate data-races in ping_lookup()

isk->inet_num, isk->inet_rcv_saddr and sk->sk_bound_dev_if
are read locklessly in ping_lookup().

Add READ_ONCE()/WRITE_ONCE() annotations.

The race on isk->inet_rcv_saddr is probably coming from IPv6 support,
but does not deserve a specific backport.

Fixes: dbca1596bbb0 ("ping: convert to RCU lookups, get rid of rwlock")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260216100149.3319315-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
ad5dfde2 458c95de

+20 -13
+20 -13
net/ipv4/ping.c
··· 148 148 pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); 149 149 spin_lock(&ping_table.lock); 150 150 if (sk_del_node_init_rcu(sk)) { 151 - isk->inet_num = 0; 151 + WRITE_ONCE(isk->inet_num, 0); 152 152 isk->inet_sport = 0; 153 153 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 154 154 } ··· 181 181 } 182 182 183 183 sk_for_each_rcu(sk, hslot) { 184 + int bound_dev_if; 185 + 184 186 if (!net_eq(sock_net(sk), net)) 185 187 continue; 186 188 isk = inet_sk(sk); 187 189 188 190 pr_debug("iterate\n"); 189 - if (isk->inet_num != ident) 191 + if (READ_ONCE(isk->inet_num) != ident) 190 192 continue; 191 193 194 + bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); 192 195 if (skb->protocol == htons(ETH_P_IP) && 193 196 sk->sk_family == AF_INET) { 194 - pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d\n", sk, 195 - (int) isk->inet_num, &isk->inet_rcv_saddr, 196 - sk->sk_bound_dev_if); 197 + __be32 rcv_saddr = READ_ONCE(isk->inet_rcv_saddr); 197 198 198 - if (isk->inet_rcv_saddr && 199 - isk->inet_rcv_saddr != ip_hdr(skb)->daddr) 199 + pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d\n", sk, 200 + ident, &rcv_saddr, 201 + bound_dev_if); 202 + 203 + if (rcv_saddr && rcv_saddr != ip_hdr(skb)->daddr) 200 204 continue; 201 205 #if IS_ENABLED(CONFIG_IPV6) 202 206 } else if (skb->protocol == htons(ETH_P_IPV6) && 203 207 sk->sk_family == AF_INET6) { 204 208 205 209 pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk, 206 - (int) isk->inet_num, 210 + ident, 207 211 &sk->sk_v6_rcv_saddr, 208 - sk->sk_bound_dev_if); 212 + bound_dev_if); 209 213 210 214 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) && 211 215 !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, ··· 220 216 continue; 221 217 } 222 218 223 - if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif && 224 - sk->sk_bound_dev_if != sdif) 219 + if (bound_dev_if && bound_dev_if != dif && 220 + bound_dev_if != sdif) 225 221 continue; 226 222 227 223 goto exit; ··· 396 392 if (saddr->sa_family == AF_INET) { 397 393 struct inet_sock *isk = inet_sk(sk); 398 394 struct sockaddr_in *addr = (struct sockaddr_in *) saddr; 399 - isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr; 395 + 396 + isk->inet_saddr = addr->sin_addr.s_addr; 397 + WRITE_ONCE(isk->inet_rcv_saddr, addr->sin_addr.s_addr); 400 398 #if IS_ENABLED(CONFIG_IPV6) 401 399 } else if (saddr->sa_family == AF_INET6) { 402 400 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr; ··· 856 850 struct sk_buff *skb; 857 851 int copied, err; 858 852 859 - pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk, isk->inet_num); 853 + pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk, 854 + READ_ONCE(isk->inet_num)); 860 855 861 856 err = -EOPNOTSUPP; 862 857 if (flags & MSG_OOB)