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=1793210065; b=fhYzNDL99mbvZlmdX8c9zeuPYS1qr6+W3+WjFZ6Bg1dECM/4JJhNR2vsF8D8nyNfkn1n 1jgQOmPOpdhHb3vvhSKSNZ9xkhAxZrEYbOhFxXMNgPOiNXn35SaJ0yBGGh7EcxNFxWCGG oFNrlLFgq/Pc4oj1s9KdW8Ra+qVjhyU/1fH5NB3+JfwmfY45UNe+yDUoropr/sMYJvWqn kC71jEVFcBOqB3D7E7suMl6O7WZj43ZqOU0ea7kx/KysPcB18npyT5+5hG5sAXPSDwY8U f7R4sPBDZLF8Ll1cfUyB6/9MkZ/3kBpSPhNBXRiB1+6vuDMgeJvrLVDFX4a8xiIQyQg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793210065; 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=egwfZ/BvzoH21F/VLPuJZhVUk7xWhwsuo8z70oEBl0k=; b=RDYEPruQnZOujzbbJ/7Kwd/DkwAXhc2cVk0hWNuwJEUOM3rWnRAbvSxqWjUx9iAPFLEG Vdo7mWLykekR6RAPeeGLaAfQpPPXvD3pS+jPBk+AQBc0Gg3us+NCiyy6LW8vRuKRttOYN Pv0gDTQ62QRX2rg6/Kn6ZJk6Ng686OiOpDX612RmCo2R7FKOouIUsBpveVZEXduqwprUL mys8xF35eepJAaiYUT1ZT8otkndxmuR2oAKI5L5D8EVT5Nh57ki9b5z4aPI10vC0BDSQq KNI27IS0QIrVP+NP3axBMW3ju1lrwGi1iR8agURCETtEM6W45DMIdwVSds4kMTeXAKA== 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=YXWDhHMb; 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 ECD56606A31A; Wed, 28 Oct 2026 17:54:24 +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=YXWDhHMb Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4F6AA1F01825; Wed, 28 Oct 2026 17:54:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1793210064; bh=egwfZ/BvzoH21F/VLPuJZhVUk7xWhwsuo8z70oEBl0k=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=YXWDhHMbBgkqkl7ydjJvQedou/wkMOWAdGIXbzbrHytLXPYdOSu2Wg3mnI95zfO+h ZXO6IvR1U9m4hHQuXZEITWAg6Q/affy0ZwZQ1/2/C+PpWc5M/cHKcrHARxaIDFAkkc e/8l4Y+wQ3uhR3DaHOsLmAs0fhrJusMPnxbYajpA= 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.6 065/168] tcp: fix use-after-free in do_tcp_getsockopt(TCP_CONGESTION) Date: Wed, 28 Oct 2026 18:00:01 +0100 Message-ID: <20261028165944.623553288@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028165943.089486480@linuxfoundation.org> References: <20261028165943.089486480@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.6-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 @@ -4104,16 +4104,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 @@ -225,7 +225,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)); @@ -255,7 +255,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 @@ -450,7 +450,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 @@ -3782,7 +3782,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(); }