From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793207662; b=nUSKowklZ5Ve+NN9XqxuFX3uG4XYAqvSVP4uCwdyaQNlCQg0taeTQSjYNgxUjVbXlyVy QeFAG50WRKkqRHzKIm6slKLnz4A60QZp5UC3loGceI01w9kvlIg2ie23VSTHg64mo5y07 zFKbjJ6KPkeotb9B4m/0SRGRfwKcCN2Ur2YeSFKTmxLccaYxuUosm8hQU4VGqcLvT1fkn +hUUpBkrrUIje+tvBTMiewN3WR0Aaw4Tdb8tH0a6qYhuWjotyIqYmxNaYaiK0+azCzKML HRvr78qAFF2g2s+8dr2Elw4jJiKz1x0mxW7ZIMF3e8ehObjRfWX+hcqmz1bRUxfqwJQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793207662; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=nTHmy4IOW3K4wTfles/75zxNSdOmjcumMZk+aPd93+E=; b=Wm6c3EqlFdENX6TfXQcFuzZfmj9Im8OY4YHNWvfCWjm7YEe2AmpVMDwtN6JquFlmyPg9 DfofmVUyXxI+njuL7UE4SpPB9vVw5nRyq9LQTq0p+fSF/j9Bly96ngsH4i7siJPv8pm3M cyk6qNNYZmSPqp7FowHv5VP66WR0N5nZahN4jxzlk5KHtEia2Owj4zHG1TRn1K1+XAkub 4E3POn5n+wmZMxiIT4Iv0u5ADZOKqXQFSel0v2JZEzHmknVjk3U/ixF2gL+f/Sm3nx5+7 W1kYj6GeKh6sLqgFPyc6O/4Vzfd/VMopoidsbrmITs3mZMpLJ3GsYcnOUgbmdy39s+g== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=yOhOeRV0; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 08FB9606A31A; Wed, 28 Oct 2026 17:14:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=yOhOeRV0 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 633951F01825; Wed, 28 Oct 2026 17:14:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1793207661; bh=nTHmy4IOW3K4wTfles/75zxNSdOmjcumMZk+aPd93+E=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=yOhOeRV0dCSyylulST5G1k6LIi8lJpJBNuU+NA6E2jOk2T+LrEfGaPxumt3Zxhuxv IJwGhdYMi5p8vaIzfyHV7fSAjzk/bEPVKSXYziFzSOoglvt/9RuuUsqVuWNp59HMfL ReXsk/A6gn1G8LkDXzvoL2DBstuWIC0981xF4zI0= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Eric Dumazet , "Xiang Mei (Microsoft)" , AutonomousCodeSecurity@microsoft.com, "Cen Zhang (Microsoft Security FORGE Labs)" , Jiayuan Chen , "Matthieu Baerts (NGI0)" , Breno Leitao , Jakub Kicinski Subject: [PATCH 6.12 096/247] tcp: fix use-after-free in do_tcp_getsockopt(TCP_CONGESTION) Date: Wed, 28 Oct 2026 17:58:19 +0100 Message-ID: <20261028165949.668648733@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028165947.349197979@linuxfoundation.org> References: <20261028165947.349197979@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: patches@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Cen Zhang (Microsoft Security FORGE Labs) commit 5271b79b7ad68dcb222e893773f92bdabf7750f3 upstream. do_tcp_getsockopt() reads icsk->icsk_ca_ops->name without holding rcu_read_lock(). Since commit 0baf26b0fcd7 ("bpf: tcp: Support tcp_congestion_ops in bpf"), icsk_ca_ops can point to dynamically allocated BPF struct_ops memory that may be freed concurrently via setsockopt(TCP_CONGESTION), leading to a use-after-free. BUG: KASAN: slab-use-after-free in _copy_to_user+0x37/0x60 Read of size 16 at addr ffff888013505260 by task exploit/149 _copy_to_user+0x37/0x60 do_tcp_getsockopt+0x158a/0x2460 (net/ipv4/tcp.c:4585) tcp_getsockopt+0x91/0xf0 __sys_getsockopt+0xf7/0x170 Fix this by holding rcu_read_lock() around the ca_ops->name access, using READ_ONCE() to load icsk_ca_ops, and copying the name to a stack buffer before releasing the lock. Also annotate the relevant icsk_ca_ops stores with WRITE_ONCE() to fix the accompanying KCSAN data-race issue. Fixes: 0baf26b0fcd7 ("bpf: tcp: Support tcp_congestion_ops in bpf") Suggested-by: Eric Dumazet Reported-by: Xiang Mei (Microsoft) Link: https://lore.kernel.org/all/20260821182449.79785-2-blbllhy@gmail.com/ Cc: AutonomousCodeSecurity@microsoft.com Cc: stable@vger.kernel.org Reviewed-by: Eric Dumazet Signed-off-by: Cen Zhang (Microsoft Security FORGE Labs) Reviewed-by: Jiayuan Chen Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Breno Leitao Link: https://patch.msgid.link/d3f97f1acbf0010898148be6e6406e4b8b4a5c84.1787870710.git.blbllhy@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 14 +++++++++++--- net/ipv4/tcp_cong.c | 4 ++-- net/ipv4/tcp_dctcp.c | 2 +- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_output.c | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -4418,16 +4418,24 @@ int do_tcp_getsockopt(struct sock *sk, i val = !inet_csk_in_pingpong_mode(sk); break; - case TCP_CONGESTION: + case TCP_CONGESTION: { + char ca_name[TCP_CA_NAME_MAX] = {}; + if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT; len = min_t(unsigned int, len, TCP_CA_NAME_MAX); if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT; - if (copy_to_sockptr(optval, icsk->icsk_ca_ops->name, len)) + + rcu_read_lock(); + memcpy(ca_name, READ_ONCE(icsk->icsk_ca_ops)->name, + sizeof(ca_name)); + rcu_read_unlock(); + + if (copy_to_sockptr(optval, ca_name, len)) return -EFAULT; return 0; - + } case TCP_ULP: if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT; --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -222,7 +222,7 @@ void tcp_assign_congestion_control(struc ca = rcu_dereference(net->ipv4.tcp_congestion_control); if (unlikely(!bpf_try_module_get(ca, ca->owner))) ca = &tcp_reno; - icsk->icsk_ca_ops = ca; + WRITE_ONCE(icsk->icsk_ca_ops, ca); rcu_read_unlock(); memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); @@ -252,7 +252,7 @@ static void tcp_reinit_congestion_contro struct inet_connection_sock *icsk = inet_csk(sk); tcp_cleanup_congestion_control(sk); - icsk->icsk_ca_ops = ca; + WRITE_ONCE(icsk->icsk_ca_ops, ca); icsk->icsk_ca_setsockopt = 1; memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -111,7 +111,7 @@ __bpf_kfunc static void dctcp_init(struc /* No ECN support? Fall back to Reno. Also need to clear * ECT from sk since it is set during 3WHS for DCTCP. */ - inet_csk(sk)->icsk_ca_ops = &dctcp_reno; + WRITE_ONCE(inet_csk(sk)->icsk_ca_ops, &dctcp_reno); INET_ECN_dontxmit(sk); } --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -468,7 +468,7 @@ void tcp_ca_openreq_child(struct sock *s ca = tcp_ca_find_key(ca_key); if (likely(ca && bpf_try_module_get(ca, ca->owner))) { icsk->icsk_ca_dst_locked = tcp_ca_dst_locked(dst); - icsk->icsk_ca_ops = ca; + WRITE_ONCE(icsk->icsk_ca_ops, ca); ca_got_dst = true; } rcu_read_unlock(); --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3888,7 +3888,7 @@ static void tcp_ca_dst_init(struct sock if (likely(ca && bpf_try_module_get(ca, ca->owner))) { bpf_module_put(icsk->icsk_ca_ops, icsk->icsk_ca_ops->owner); icsk->icsk_ca_dst_locked = tcp_ca_dst_locked(dst); - icsk->icsk_ca_ops = ca; + WRITE_ONCE(icsk->icsk_ca_ops, ca); } rcu_read_unlock(); }