Skip to content

Commit bac76cf

Browse files
kuroa-mekuba-moo
authored andcommitted
tcp: fix forever orphan socket caused by tcp_abort
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: c1e64e2 ("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>
1 parent defd8b3 commit bac76cf

File tree

1 file changed

+11
-7
lines changed

1 file changed

+11
-7
lines changed

net/ipv4/tcp.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4637,6 +4637,13 @@ int tcp_abort(struct sock *sk, int err)
46374637
/* Don't race with userspace socket closes such as tcp_close. */
46384638
lock_sock(sk);
46394639

4640+
/* Avoid closing the same socket twice. */
4641+
if (sk->sk_state == TCP_CLOSE) {
4642+
if (!has_current_bpf_ctx())
4643+
release_sock(sk);
4644+
return -ENOENT;
4645+
}
4646+
46404647
if (sk->sk_state == TCP_LISTEN) {
46414648
tcp_set_state(sk, TCP_CLOSE);
46424649
inet_csk_listen_stop(sk);
@@ -4646,16 +4653,13 @@ int tcp_abort(struct sock *sk, int err)
46464653
local_bh_disable();
46474654
bh_lock_sock(sk);
46484655

4649-
if (!sock_flag(sk, SOCK_DEAD)) {
4650-
if (tcp_need_reset(sk->sk_state))
4651-
tcp_send_active_reset(sk, GFP_ATOMIC,
4652-
SK_RST_REASON_NOT_SPECIFIED);
4653-
tcp_done_with_error(sk, err);
4654-
}
4656+
if (tcp_need_reset(sk->sk_state))
4657+
tcp_send_active_reset(sk, GFP_ATOMIC,
4658+
SK_RST_REASON_NOT_SPECIFIED);
4659+
tcp_done_with_error(sk, err);
46554660

46564661
bh_unlock_sock(sk);
46574662
local_bh_enable();
4658-
tcp_write_queue_purge(sk);
46594663
if (!has_current_bpf_ctx())
46604664
release_sock(sk);
46614665
return 0;

0 commit comments

Comments
 (0)