[PATCH net-next 07/14] mptcp: annotate data-races around pernet sysctls

From: Jiayuan Chen

Date: Sun Nov 08 2026 - 22:04:28 EST


enabled, add_addr_timeout, checksum_enabled, allow_join_initial_addr_port,
stale_loss_cnt, close_timeout, pm_type and syn_retrans_before_tcp_fallback
are read by their ctrl.c helpers without any lock while the sysctl
handlers update them with WRITE_ONCE(), and the path_manager handler
stores pm_type with a plain write. Add READ_ONCE() to the readers and
WRITE_ONCE() to that handler.

KCSAN reports it when net.mptcp.enabled is changed while MPTCP sockets
are being created:

BUG: KCSAN: data-race in mptcp_is_enabled / proc_dou8vec_minmax

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

read to 0xffff8d724248abc9 of 1 bytes by task 735 on cpu 1:
mptcp_is_enabled+0x33/0x50
mptcp_init_sock+0x35/0x300
inet_create+0x4a6/0x8e0
...

value changed: 0x00 -> 0x01

Signed-off-by: Jiayuan Chen <jiayuan.chen@xxxxxxxxx>
---
net/mptcp/ctrl.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c
index 63c5747f0f63c..164f79b9deb0e 100644
--- a/net/mptcp/ctrl.c
+++ b/net/mptcp/ctrl.c
@@ -50,39 +50,39 @@ static struct mptcp_pernet *mptcp_get_pernet(const struct net *net)

int mptcp_is_enabled(const struct net *net)
{
- return mptcp_get_pernet(net)->mptcp_enabled;
+ return READ_ONCE(mptcp_get_pernet(net)->mptcp_enabled);
}

unsigned int mptcp_get_add_addr_timeout(const struct net *net)
{
- return mptcp_get_pernet(net)->add_addr_timeout;
+ return READ_ONCE(mptcp_get_pernet(net)->add_addr_timeout);
}

int mptcp_is_checksum_enabled(const struct net *net)
{
- return mptcp_get_pernet(net)->checksum_enabled;
+ return READ_ONCE(mptcp_get_pernet(net)->checksum_enabled);
}

int mptcp_allow_join_id0(const struct net *net)
{
- return mptcp_get_pernet(net)->allow_join_initial_addr_port;
+ return READ_ONCE(mptcp_get_pernet(net)->allow_join_initial_addr_port);
}

unsigned int mptcp_stale_loss_cnt(const struct net *net)
{
- return mptcp_get_pernet(net)->stale_loss_cnt;
+ return READ_ONCE(mptcp_get_pernet(net)->stale_loss_cnt);
}

unsigned int mptcp_close_timeout(const struct sock *sk)
{
if (sock_flag(sk, SOCK_DEAD))
return TCP_TIMEWAIT_LEN;
- return mptcp_get_pernet(sock_net(sk))->close_timeout;
+ return READ_ONCE(mptcp_get_pernet(sock_net(sk))->close_timeout);
}

int mptcp_get_pm_type(const struct net *net)
{
- return mptcp_get_pernet(net)->pm_type;
+ return READ_ONCE(mptcp_get_pernet(net)->pm_type);
}

const char *mptcp_get_path_manager(const struct net *net)
@@ -230,7 +230,7 @@ static int proc_path_manager(const struct ctl_table *ctl, int write,
pm_type = MPTCP_PM_TYPE_KERNEL;
else if (strncmp(pm_name, "userspace", MPTCP_PM_NAME_MAX) == 0)
pm_type = MPTCP_PM_TYPE_USERSPACE;
- pernet->pm_type = pm_type;
+ WRITE_ONCE(pernet->pm_type, pm_type);
}
}

@@ -551,7 +551,7 @@ void mptcp_active_detect_blackhole(struct sock *ssk, bool expired)

net = sock_net(ssk);
timeouts = inet_csk(ssk)->icsk_retransmits;
- to_max = mptcp_get_pernet(net)->syn_retrans_before_tcp_fallback;
+ to_max = READ_ONCE(mptcp_get_pernet(net)->syn_retrans_before_tcp_fallback);

if (timeouts == to_max || (timeouts < to_max && expired)) {
subflow->mpc_drop = 1;
--
2.43.0