]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
kcm: use WRITE_ONCE() when changing lower socket callbacks
authorRunyu Xiao <runyu.xiao@seu.edu.cn>
Thu, 11 Jun 2026 05:35:43 +0000 (13:35 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Sun, 14 Jun 2026 08:18:14 +0000 (10:18 +0200)
kcm_attach() replaces a live lower TCP socket's sk_data_ready and
sk_write_space callbacks with KCM handlers, and kcm_unattach() restores
them later. Those callback-pointer updates are still plain stores even
though the same fields can be read and invoked concurrently on other
CPUs.

If another CPU observes an older callback snapshot after the live field
has already been restored, callback execution can run with a mismatched
target and sk_user_data state, leading to stale or misdirected wakeups.

Use WRITE_ONCE() for the callback replacement and restore operations so
these shared callback fields follow the same visibility contract already
established by the earlier 4022 fixes.

Fixes: ab7ac4eb9832 ("kcm: Kernel Connection Multiplexor module")
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Link: https://patch.msgid.link/20260611053543.2429462-1-runyu.xiao@seu.edu.cn
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/kcm/kcmsock.c

index 3912e75079f5eb7f95405570da7a8db63a9d7b2d..a998336840c335823c2a00ad48392dca3b832c2e 100644 (file)
@@ -1304,8 +1304,8 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
        psock->save_write_space = csk->sk_write_space;
        psock->save_state_change = csk->sk_state_change;
        csk->sk_user_data = psock;
-       csk->sk_data_ready = psock_data_ready;
-       csk->sk_write_space = psock_write_space;
+       WRITE_ONCE(csk->sk_data_ready, psock_data_ready);
+       WRITE_ONCE(csk->sk_write_space, psock_write_space);
        csk->sk_state_change = psock_state_change;
 
        write_unlock_bh(&csk->sk_callback_lock);
@@ -1381,8 +1381,8 @@ static void kcm_unattach(struct kcm_psock *psock)
         */
        write_lock_bh(&csk->sk_callback_lock);
        csk->sk_user_data = NULL;
-       csk->sk_data_ready = psock->save_data_ready;
-       csk->sk_write_space = psock->save_write_space;
+       WRITE_ONCE(csk->sk_data_ready, psock->save_data_ready);
+       WRITE_ONCE(csk->sk_write_space, psock->save_write_space);
        csk->sk_state_change = psock->save_state_change;
        strp_stop(&psock->strp);