]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
raw: annotate lockless match fields in raw_v4_match()
authorRunyu Xiao <runyu.xiao@seu.edu.cn>
Thu, 16 Jul 2026 14:29:58 +0000 (22:29 +0800)
committerJakub Kicinski <kuba@kernel.org>
Thu, 23 Jul 2026 14:46:12 +0000 (07:46 -0700)
raw_v4_match() is a lockless match helper under sk_for_each_rcu(). It
still reads inet->inet_daddr, inet->inet_rcv_saddr and
sk->sk_bound_dev_if with plain loads while bind, connect and
bind-to-device paths can update the same match fields concurrently.

Annotate only those mutable match fields in raw_v4_match(), and do so
at the point of use instead of hoisting the bound-device read before
the earlier short-circuit tests.

Also annotate the raw bind writer and the shared IPv4 datagram connect
writer used by raw sockets, so the address fields updated on bind and
connect match explicit WRITE_ONCE() updates.

This version intentionally leaves the shared disconnect-side IPv4
writers to follow-up cleanup and limits the writer changes here to the
raw bind path and the datagram connect path directly exercised by raw
sockets.

Fixes: 0daf07e52709 ("raw: convert raw sockets to RCU")
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Link: https://patch.msgid.link/20260716142958.3064224-1-runyu.xiao@seu.edu.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/datagram.c
net/ipv4/raw.c

index 1614593b6d727000adb9b0ab9a136b4aac050317..7d25519a6cdd3ff7e3cc476e3c0b8314972cbd19 100644 (file)
@@ -63,12 +63,12 @@ int __ip4_datagram_connect(struct sock *sk, struct sockaddr_unsized *uaddr, int
        }
 
        /* Update addresses before rehashing */
-       inet->inet_daddr = fl4->daddr;
+       WRITE_ONCE(inet->inet_daddr, fl4->daddr);
        inet->inet_dport = usin->sin_port;
        if (!inet->inet_saddr)
                inet->inet_saddr = fl4->saddr;
        if (!inet->inet_rcv_saddr) {
-               inet->inet_rcv_saddr = fl4->saddr;
+               WRITE_ONCE(inet->inet_rcv_saddr, fl4->saddr);
                if (sk->sk_prot->rehash)
                        sk->sk_prot->rehash(sk);
        }
index e9fbab6ad9146315bf5fd8fd7968483c8d41bd8c..7f74d8b95a3737657dc0044186960380af2f02de 100644 (file)
@@ -118,13 +118,21 @@ bool raw_v4_match(struct net *net, const struct sock *sk, unsigned short num,
                  __be32 raddr, __be32 laddr, int dif, int sdif)
 {
        const struct inet_sock *inet = inet_sk(sk);
+       __be32 daddr, rcv_saddr;
 
-       if (net_eq(sock_net(sk), net) && inet->inet_num == num  &&
-           !(inet->inet_daddr && inet->inet_daddr != raddr)    &&
-           !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
-           raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif))
-               return true;
-       return false;
+       if (!net_eq(sock_net(sk), net) || inet->inet_num != num)
+               return false;
+
+       daddr = READ_ONCE(inet->inet_daddr);
+       if (daddr && daddr != raddr)
+               return false;
+
+       rcv_saddr = READ_ONCE(inet->inet_rcv_saddr);
+       if (rcv_saddr && rcv_saddr != laddr)
+               return false;
+
+       return raw_sk_bound_dev_eq(net, READ_ONCE(sk->sk_bound_dev_if),
+                                  dif, sdif);
 }
 EXPORT_SYMBOL_GPL(raw_v4_match);
 
@@ -722,7 +730,8 @@ static int raw_bind(struct sock *sk, struct sockaddr_unsized *uaddr,
                                         chk_addr_ret))
                goto out;
 
-       inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr;
+       inet->inet_saddr = addr->sin_addr.s_addr;
+       WRITE_ONCE(inet->inet_rcv_saddr, addr->sin_addr.s_addr);
        if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
                inet->inet_saddr = 0;  /* Use device */
        sk_dst_reset(sk);