[PATCH net] raw: annotate data-races in raw_v6_match()

Runyu Xiao posted 1 patch 6 days, 21 hours ago
net/ipv6/raw.c | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
[PATCH net] raw: annotate data-races in raw_v6_match()
Posted by Runyu Xiao 6 days, 21 hours ago
raw_v6_match() is a lockless match helper under sk_for_each_rcu()
and still reads inet_sk(sk)->inet_num, sk->sk_bound_dev_if,
sk->sk_v6_daddr and sk->sk_v6_rcv_saddr with plain loads.

Add READ_ONCE() annotations for these fields.

Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 net/ipv6/raw.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 3cc58698cbbd..7160d5513742 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -64,20 +64,37 @@
 struct raw_hashinfo raw_v6_hashinfo;
 EXPORT_SYMBOL_GPL(raw_v6_hashinfo);
 
+static void raw_v6_addr_snapshot(struct in6_addr *dst,
+				 const struct in6_addr *src)
+{
+	dst->s6_addr32[0] = READ_ONCE(src->s6_addr32[0]);
+	dst->s6_addr32[1] = READ_ONCE(src->s6_addr32[1]);
+	dst->s6_addr32[2] = READ_ONCE(src->s6_addr32[2]);
+	dst->s6_addr32[3] = READ_ONCE(src->s6_addr32[3]);
+}
+
 bool raw_v6_match(struct net *net, const struct sock *sk, unsigned short num,
 		  const struct in6_addr *loc_addr,
 		  const struct in6_addr *rmt_addr, int dif, int sdif)
 {
-	if (inet_sk(sk)->inet_num != num ||
+	unsigned short match_num = READ_ONCE(inet_sk(sk)->inet_num);
+	int match_bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
+	struct in6_addr match_daddr;
+	struct in6_addr match_rcv_saddr;
+
+	raw_v6_addr_snapshot(&match_daddr, &sk->sk_v6_daddr);
+	raw_v6_addr_snapshot(&match_rcv_saddr, &sk->sk_v6_rcv_saddr);
+
+	if (match_num != num ||
 	    !net_eq(sock_net(sk), net) ||
-	    (!ipv6_addr_any(&sk->sk_v6_daddr) &&
-	     !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) ||
-	    !raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if,
+	    (!ipv6_addr_any(&match_daddr) &&
+	     !ipv6_addr_equal(&match_daddr, rmt_addr)) ||
+	    !raw_sk_bound_dev_eq(net, match_bound_dev_if,
 				 dif, sdif))
 		return false;
 
-	if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) ||
-	    ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr) ||
+	if (ipv6_addr_any(&match_rcv_saddr) ||
+	    ipv6_addr_equal(&match_rcv_saddr, loc_addr) ||
 	    (ipv6_addr_is_multicast(loc_addr) &&
 	     inet6_mc_check(sk, loc_addr, rmt_addr)))
 		return true;
-- 
2.34.1
Re: [PATCH net] raw: annotate data-races in raw_v6_match()
Posted by Eric Dumazet 6 days, 21 hours ago
On Mon, Jun 1, 2026 at 12:42 AM Runyu Xiao <runyu.xiao@seu.edu.cn> wrote:
>
> raw_v6_match() is a lockless match helper under sk_for_each_rcu()
> and still reads inet_sk(sk)->inet_num, sk->sk_bound_dev_if,
> sk->sk_v6_daddr and sk->sk_v6_rcv_saddr with plain loads.
>
> Add READ_ONCE() annotations for these fields.
>
> Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
> ---
>  net/ipv6/raw.c | 29 +++++++++++++++++++++++------
>  1 file changed, 23 insertions(+), 6 deletions(-)
>
> diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
> index 3cc58698cbbd..7160d5513742 100644
> --- a/net/ipv6/raw.c
> +++ b/net/ipv6/raw.c
> @@ -64,20 +64,37 @@
>  struct raw_hashinfo raw_v6_hashinfo;
>  EXPORT_SYMBOL_GPL(raw_v6_hashinfo);
>
> +static void raw_v6_addr_snapshot(struct in6_addr *dst,
> +                                const struct in6_addr *src)
> +{
> +       dst->s6_addr32[0] = READ_ONCE(src->s6_addr32[0]);
> +       dst->s6_addr32[1] = READ_ONCE(src->s6_addr32[1]);
> +       dst->s6_addr32[2] = READ_ONCE(src->s6_addr32[2]);
> +       dst->s6_addr32[3] = READ_ONCE(src->s6_addr32[3]);
> +}

I do not think we want to incur an extra cost for such a minor race.

Note that your patch does not solve the race, since writers do not
update these fields atomically anyway.