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=1792774960; b=LsAhYsMjEwQPJmBSSyeQcEI8GI7PHgieTVymSNkLJ30rjj8XmzTxQjK4vfBhvs1twvsd 7vWeMxd4wcq5x+g/jO0BLMEdJfRjER0yR3MbzdjF+gOw0Wvi91+xGEG2GgsZV9kk2nVt1 EIlPC7E8ZGDn8UClVKIG1e6nSM+Cmgc3Hl3svOAasFZq8VgygIXGkZGirn7Jxg1Icq15n kFqFSv69BTtmREOuSQlcSDv/rmhZ2A7rqOSnfBzokANsnCqtpYrkhaL3d+ULG4Oah4vNm gAr7kBjAMlCtJiTSaNFwtNN7SN2r8qqv7R3lkRsC/j/ocKLruClE/6z13TgvnKXdjDQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792774960; 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=WQBrc+5SIVL4JwCgDW43/a7Dk6/SNHh2n/ykL0p5NtI=; b=0diWJWFf291qi39v0tsoQf+XPd3X/iX7xwlR6LEZepUK/IhseS88L5kl6826R7bIKP3B BQRRPFnC8RA1WyXVpEyTdRT+SR254WMTwc/714T9eJPq/0N1SAO/gyOuK3qoHE+A8B1Ed XhEFsKIgxLww3nMVPFlMfVvB0mSeviSaRr1VT1+T/7nvkjnQiyfro2eV0PJuWIBoan4wM QWeQk1ZKgHFj9nIuALqrDwafJtljTcP7NzYHiNcdRCwJ2kKk9uF4gyIPrN2lduakE/Gl6 y6t2j7alh6TYfZvt9BN7sHBy6DqK2lF8EClzvDvbyrtQpsCPaUa7dm1OhZmSlHqrlcg== 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="AHHF4qM/"; 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 A02FC606A31D; Fri, 23 Oct 2026 17:02:40 +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=AHHF4qM/ Received: by smtp.kernel.org (Postfix) with ESMTPSA id EA2FA1F01825; Fri, 23 Oct 2026 17:02:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1792774960; bh=WQBrc+5SIVL4JwCgDW43/a7Dk6/SNHh2n/ykL0p5NtI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=AHHF4qM/MSmg4Nknh2RddnH3LaRdiHHlyEjmd5OjWXnbo7ItnhygFUXG6x2sJgDnZ 1b4kxb8xVP+xTa7zcqcZKAE8bgUVGO4nZf+ojW1MNAWdK5A3+ELYiCLv8cL8LB6JJb zlv4915LxL+N2PBViFoOXrScZxoca5K1F4+yNwN0= 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 7.2 177/242] tcp: fix use-after-free in do_tcp_getsockopt(TCP_CONGESTION) Date: Fri, 23 Oct 2026 18:40:19 +0200 Message-ID: <20261023163717.970203049@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261023163713.816071858@linuxfoundation.org> References: <20261023163713.816071858@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 7.2-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 @@ -4577,16 +4577,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 @@ -223,7 +223,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)); @@ -253,7 +253,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 @@ -507,7 +507,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 @@ -4095,7 +4095,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(); }