[PATCH net-next 04/14] ipv6: annotate data-races around icmpv6 reply sysctls

From: Jiayuan Chen

Date: Sun Nov 08 2026 - 21:59:19 EST


icmpv6_echo_ignore_all, icmpv6_echo_ignore_multicast,
icmpv6_echo_ignore_anycast, anycast_src_echo_reply and fwmark_reflect are
read without any lock while their sysctl handlers update them with
WRITE_ONCE(). Add READ_ONCE() to the readers.

KCSAN reports it when net.ipv6.icmp.echo_ignore_all is changed while
ICMPv6 echo requests are received:

BUG: KCSAN: data-race in icmpv6_rcv / proc_dou8vec_minmax

write (marked) to 0xffffffff8ee2940d of 1 bytes by task 504 on cpu 0:
proc_dou8vec_minmax+0x1ab/0x1f0
proc_sys_call_handler+0x282/0x3a0
proc_sys_write+0x13/0x20
...

read to 0xffffffff8ee2940d of 1 bytes by interrupt on cpu 3:
icmpv6_rcv+0x99d/0xd40
ip6_protocol_deliver_rcu+0x787/0x9a0
ip6_input_finish+0xb0/0x1b0
ip6_input+0xa8/0x250
ipv6_rcv+0x14b/0x1c0
__netif_receive_skb_one_core+0x8f/0xe0
...

value changed: 0x01 -> 0x00

Signed-off-by: Jiayuan Chen <jiayuan.chen@xxxxxxxxx>
---
include/net/ipv6.h | 2 +-
net/ipv6/icmp.c | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 579df1516d251..b77dc5c3ea268 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -199,7 +199,7 @@ struct sk_buff *ip6_frag_next(struct sk_buff *skb,
struct ip6_frag_state *state);

#define IP6_REPLY_MARK(net, mark) \
- ((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0)
+ (READ_ONCE((net)->ipv6.sysctl.fwmark_reflect) ? (mark) : 0)

#include <net/sock.h>

diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index a95b0351824f3..3e95b1191c4f2 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -938,17 +938,17 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
u8 type;

if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) &&
- net->ipv6.sysctl.icmpv6_echo_ignore_multicast)
+ READ_ONCE(net->ipv6.sysctl.icmpv6_echo_ignore_multicast))
return reason;

saddr = &ipv6_hdr(skb)->daddr;

acast = ipv6_anycast_destination(skb_dst(skb), saddr);
- if (acast && net->ipv6.sysctl.icmpv6_echo_ignore_anycast)
+ if (acast && READ_ONCE(net->ipv6.sysctl.icmpv6_echo_ignore_anycast))
return reason;

if (!ipv6_unicast_destination(skb) &&
- !(net->ipv6.sysctl.anycast_src_echo_reply && acast))
+ !(READ_ONCE(net->ipv6.sysctl.anycast_src_echo_reply) && acast))
saddr = NULL;

if (icmph->icmp6_type == ICMPV6_EXT_ECHO_REQUEST)
@@ -1152,11 +1152,11 @@ static int icmpv6_rcv(struct sk_buff *skb)

switch (type) {
case ICMPV6_ECHO_REQUEST:
- if (!net->ipv6.sysctl.icmpv6_echo_ignore_all)
+ if (!READ_ONCE(net->ipv6.sysctl.icmpv6_echo_ignore_all))
reason = icmpv6_echo_reply(skb);
break;
case ICMPV6_EXT_ECHO_REQUEST:
- if (!net->ipv6.sysctl.icmpv6_echo_ignore_all &&
+ if (!READ_ONCE(net->ipv6.sysctl.icmpv6_echo_ignore_all) &&
READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe))
reason = icmpv6_echo_reply(skb);
break;
--
2.43.0