Skip to content

Commit ad5dfde

Browse files
edumazetkuba-moo
authored andcommitted
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: dbca159 ("ping: convert to RCU lookups, get rid of rwlock") Signed-off-by: Eric Dumazet <[email protected]> Reviewed-by: Kuniyuki Iwashima <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 458c95d commit ad5dfde

1 file changed

Lines changed: 19 additions & 12 deletions

File tree

net/ipv4/ping.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ void ping_unhash(struct sock *sk)
148148
pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
149149
spin_lock(&ping_table.lock);
150150
if (sk_del_node_init_rcu(sk)) {
151-
isk->inet_num = 0;
151+
WRITE_ONCE(isk->inet_num, 0);
152152
isk->inet_sport = 0;
153153
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
154154
}
@@ -181,31 +181,35 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
181181
}
182182

183183
sk_for_each_rcu(sk, hslot) {
184+
int bound_dev_if;
185+
184186
if (!net_eq(sock_net(sk), net))
185187
continue;
186188
isk = inet_sk(sk);
187189

188190
pr_debug("iterate\n");
189-
if (isk->inet_num != ident)
191+
if (READ_ONCE(isk->inet_num) != ident)
190192
continue;
191193

194+
bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
192195
if (skb->protocol == htons(ETH_P_IP) &&
193196
sk->sk_family == AF_INET) {
197+
__be32 rcv_saddr = READ_ONCE(isk->inet_rcv_saddr);
198+
194199
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);
200+
ident, &rcv_saddr,
201+
bound_dev_if);
197202

198-
if (isk->inet_rcv_saddr &&
199-
isk->inet_rcv_saddr != ip_hdr(skb)->daddr)
203+
if (rcv_saddr && rcv_saddr != ip_hdr(skb)->daddr)
200204
continue;
201205
#if IS_ENABLED(CONFIG_IPV6)
202206
} else if (skb->protocol == htons(ETH_P_IPV6) &&
203207
sk->sk_family == AF_INET6) {
204208

205209
pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk,
206-
(int) isk->inet_num,
210+
ident,
207211
&sk->sk_v6_rcv_saddr,
208-
sk->sk_bound_dev_if);
212+
bound_dev_if);
209213

210214
if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) &&
211215
!ipv6_addr_equal(&sk->sk_v6_rcv_saddr,
@@ -216,8 +220,8 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
216220
continue;
217221
}
218222

219-
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif &&
220-
sk->sk_bound_dev_if != sdif)
223+
if (bound_dev_if && bound_dev_if != dif &&
224+
bound_dev_if != sdif)
221225
continue;
222226

223227
goto exit;
@@ -392,7 +396,9 @@ static void ping_set_saddr(struct sock *sk, struct sockaddr_unsized *saddr)
392396
if (saddr->sa_family == AF_INET) {
393397
struct inet_sock *isk = inet_sk(sk);
394398
struct sockaddr_in *addr = (struct sockaddr_in *) saddr;
395-
isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
399+
400+
isk->inet_saddr = addr->sin_addr.s_addr;
401+
WRITE_ONCE(isk->inet_rcv_saddr, addr->sin_addr.s_addr);
396402
#if IS_ENABLED(CONFIG_IPV6)
397403
} else if (saddr->sa_family == AF_INET6) {
398404
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr;
@@ -850,7 +856,8 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
850856
struct sk_buff *skb;
851857
int copied, err;
852858

853-
pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk, isk->inet_num);
859+
pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk,
860+
READ_ONCE(isk->inet_num));
854861

855862
err = -EOPNOTSUPP;
856863
if (flags & MSG_OOB)

0 commit comments

Comments
 (0)