[PATCH net-next 2/2] net: annotate lockless writes to sk->sk_err

From: Quanye Yang via B4 Relay

Date: Fri Oct 02 2026 - 03:34:29 EST


From: Quanye Yang <quanyeyang@xxxxxxxxx>

do_recvmmsg() and getsockopt(SO_ERROR) clear sk_err with xchg()
without the socket lock. TCP, MPTCP and kTLS already peek the same
field with READ_ONCE() or consume it via sock_error().

sock_dequeue_err_skb() still uses plain stores. tcp_recvmsg() can
call it via MSG_ERRQUEUE before lock_sock(), so those writes race
with the annotated readers and with sock_error(). The same unmarked
stores exist in strp_abort_strp() and sk_psock_report_error(), which
run on the TCP/TLS socket.

Annotate those writers with WRITE_ONCE(). No extra ordering is
needed; this does not change who wins when ICMP error-queue entries
overwrite sk_err.

Link: https://lore.kernel.org/netdev/3d9d442f-f168-43da-87b0-010ad5a78365@xxxxxxxxxx/
Signed-off-by: Quanye Yang <quanyeyang@xxxxxxxxx>
---
include/linux/skmsg.h | 2 +-
net/core/skbuff.c | 5 +++--
net/strparser/strparser.c | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h
index d5e35f24738d..52ce45f25f5a 100644
--- a/include/linux/skmsg.h
+++ b/include/linux/skmsg.h
@@ -429,7 +429,7 @@ static inline void sk_psock_report_error(struct sk_psock *psock, int err)
{
struct sock *sk = psock->sk;

- sk->sk_err = err;
+ WRITE_ONCE(sk->sk_err, err);
sk_error_report(sk);
}

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5c4024a03e10..51e3cf1ea985 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -5535,12 +5535,13 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
if (skb && (skb_next = skb_peek(q))) {
icmp_next = is_icmp_err_skb(skb_next);
if (icmp_next)
- sk->sk_err = SKB_EXT_ERR(skb_next)->ee.ee_errno;
+ WRITE_ONCE(sk->sk_err,
+ SKB_EXT_ERR(skb_next)->ee.ee_errno);
}
spin_unlock_irqrestore(&q->lock, flags);

if (is_icmp_err_skb(skb) && !icmp_next)
- sk->sk_err = 0;
+ WRITE_ONCE(sk->sk_err, 0);

if (skb_next)
sk_error_report(sk);
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
index a23f4b4dfc67..e5d5d755e532 100644
--- a/net/strparser/strparser.c
+++ b/net/strparser/strparser.c
@@ -57,7 +57,7 @@ static void strp_abort_strp(struct strparser *strp, int err)
struct sock *sk = strp->sk;

/* Report an error on the lower socket */
- sk->sk_err = -err;
+ WRITE_ONCE(sk->sk_err, -err);
sk_error_report(sk);
}
}

--
2.55.0