--- /dev/null
+From bac76cf89816bff06c4ec2f3df97dc34e150a1c4 Mon Sep 17 00:00:00 2001
+From: Xueming Feng <kuro@kuroa.me>
+Date: Mon, 26 Aug 2024 18:23:27 +0800
+Subject: tcp: fix forever orphan socket caused by tcp_abort
+
+From: Xueming Feng <kuro@kuroa.me>
+
+commit bac76cf89816bff06c4ec2f3df97dc34e150a1c4 upstream.
+
+We have some problem closing zero-window fin-wait-1 tcp sockets in our
+environment. This patch come from the investigation.
+
+Previously tcp_abort only sends out reset and calls tcp_done when the
+socket is not SOCK_DEAD, aka orphan. For orphan socket, it will only
+purging the write queue, but not close the socket and left it to the
+timer.
+
+While purging the write queue, tp->packets_out and sk->sk_write_queue
+is cleared along the way. However tcp_retransmit_timer have early
+return based on !tp->packets_out and tcp_probe_timer have early
+return based on !sk->sk_write_queue.
+
+This caused ICSK_TIME_RETRANS and ICSK_TIME_PROBE0 not being resched
+and socket not being killed by the timers, converting a zero-windowed
+orphan into a forever orphan.
+
+This patch removes the SOCK_DEAD check in tcp_abort, making it send
+reset to peer and close the socket accordingly. Preventing the
+timer-less orphan from happening.
+
+According to Lorenzo's email in the v1 thread, the check was there to
+prevent force-closing the same socket twice. That situation is handled
+by testing for TCP_CLOSE inside lock, and returning -ENOENT if it is
+already closed.
+
+The -ENOENT code comes from the associate patch Lorenzo made for
+iproute2-ss; link attached below, which also conform to RFC 9293.
+
+At the end of the patch, tcp_write_queue_purge(sk) is removed because it
+was already called in tcp_done_with_error().
+
+p.s. This is the same patch with v2. Resent due to mis-labeled "changes
+requested" on patchwork.kernel.org.
+
+Link: https://patchwork.ozlabs.org/project/netdev/patch/1450773094-7978-3-git-send-email-lorenzo@google.com/
+Fixes: c1e64e298b8c ("net: diag: Support destroying TCP sockets.")
+Signed-off-by: Xueming Feng <kuro@kuroa.me>
+Tested-by: Lorenzo Colitti <lorenzo@google.com>
+Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20240826102327.1461482-1-kuro@kuroa.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Link: https://lore.kernel.org/lkml/Z9OZS%2Fhc+v5og6%2FU@perf/
+[youngmin: Resolved minor conflict in net/ipv4/tcp.c]
+Signed-off-by: Youngmin Nam <youngmin.nam@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/tcp.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -4620,6 +4620,13 @@ int tcp_abort(struct sock *sk, int err)
+ /* Don't race with userspace socket closes such as tcp_close. */
+ lock_sock(sk);
+
++ /* Avoid closing the same socket twice. */
++ if (sk->sk_state == TCP_CLOSE) {
++ if (!has_current_bpf_ctx())
++ release_sock(sk);
++ return -ENOENT;
++ }
++
+ if (sk->sk_state == TCP_LISTEN) {
+ tcp_set_state(sk, TCP_CLOSE);
+ inet_csk_listen_stop(sk);
+@@ -4629,15 +4636,12 @@ int tcp_abort(struct sock *sk, int err)
+ local_bh_disable();
+ bh_lock_sock(sk);
+
+- if (!sock_flag(sk, SOCK_DEAD)) {
+- if (tcp_need_reset(sk->sk_state))
+- tcp_send_active_reset(sk, GFP_ATOMIC);
+- tcp_done_with_error(sk, err);
+- }
++ if (tcp_need_reset(sk->sk_state))
++ tcp_send_active_reset(sk, GFP_ATOMIC);
++ tcp_done_with_error(sk, err);
+
+ bh_unlock_sock(sk);
+ local_bh_enable();
+- tcp_write_queue_purge(sk);
+ if (!has_current_bpf_ctx())
+ release_sock(sk);
+ return 0;
--- /dev/null
+From 5ce4645c23cf5f048eb8e9ce49e514bababdee85 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet@google.com>
+Date: Tue, 28 May 2024 12:52:52 +0000
+Subject: tcp: fix races in tcp_abort()
+
+From: Eric Dumazet <edumazet@google.com>
+
+commit 5ce4645c23cf5f048eb8e9ce49e514bababdee85 upstream.
+
+tcp_abort() has the same issue than the one fixed in the prior patch
+in tcp_write_err().
+
+In order to get consistent results from tcp_poll(), we must call
+sk_error_report() after tcp_done().
+
+We can use tcp_done_with_error() to centralize this logic.
+
+Fixes: c1e64e298b8c ("net: diag: Support destroying TCP sockets.")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Acked-by: Neal Cardwell <ncardwell@google.com>
+Link: https://lore.kernel.org/r/20240528125253.1966136-4-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[youngmin: Resolved minor conflict in net/ipv4/tcp.c]
+Signed-off-by: Youngmin Nam <youngmin.nam@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/tcp.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -4630,13 +4630,9 @@ int tcp_abort(struct sock *sk, int err)
+ bh_lock_sock(sk);
+
+ if (!sock_flag(sk, SOCK_DEAD)) {
+- WRITE_ONCE(sk->sk_err, err);
+- /* This barrier is coupled with smp_rmb() in tcp_poll() */
+- smp_wmb();
+- sk_error_report(sk);
+ if (tcp_need_reset(sk->sk_state))
+ tcp_send_active_reset(sk, GFP_ATOMIC);
+- tcp_done(sk);
++ tcp_done_with_error(sk, err);
+ }
+
+ bh_unlock_sock(sk);