raw: annotate lockless match fields in raw_v4_match()

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: 0daf07e527 ("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>
This commit is contained in:
Runyu Xiao 2026-07-16 22:29:58 +08:00 committed by Jakub Kicinski
parent 3b536db8fb
commit 18f116931f
2 changed files with 18 additions and 9 deletions

View 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);
}

View 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);