From 6415bcccfce1fdaa41808f14e2aba790b9b872b0 Mon Sep 17 00:00:00 2001 From: Tomer Cabouly Date: Wed, 9 Apr 2025 06:31:52 +0000 Subject: [PATCH] issue: 4050516 Fix TCP segment leak in SYN flood Resolve race condition where TCP segments leak during SYN-RCVD timeout handling, causing "still N tcp segs in use" warnings. Root cause: When tcp_slowtmr() times out a connection stuck in SYN-RCVD state, it calls TCP_EVENT_ERR() which triggers handle_incoming_handshake_failure(). This function calls close() on the child connection, which attempts to send FIN and allocates new TCP segments. These segments were never cleaned up. Fix: Call abort_connection() before close() in handle_incoming_handshake_failure(). The tcp_abort() -> tcp_abandon() path explicitly does NOT send RST for SYN-RCVD connections (matching Linux kernel behavior), and properly purges all segments before setting state to CLOSED. This prevents segment allocation during subsequent close() call. Also enhanced destructor logging to show PCB state and queue pointers for better debugging of any remaining segment leaks. Signed-off-by: Tomer Cabouly --- src/core/sock/sockinfo_tcp.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/core/sock/sockinfo_tcp.cpp b/src/core/sock/sockinfo_tcp.cpp index 75893a08e..17f3a010c 100644 --- a/src/core/sock/sockinfo_tcp.cpp +++ b/src/core/sock/sockinfo_tcp.cpp @@ -846,7 +846,9 @@ sockinfo_tcp::~sockinfo_tcp() destructor_helper_tcp(); if (m_tcp_seg_in_use) { - si_tcp_logwarn("still %d tcp segs in use!", m_tcp_seg_in_use); + si_tcp_logwarn( + "still %d tcp segs in use! state=%d, pcb.unsent=%p, pcb.unacked=%p, pcb.seg_alloc=%p", + m_tcp_seg_in_use, get_tcp_state(&m_pcb), m_pcb.unsent, m_pcb.unacked, m_pcb.seg_alloc); } if (m_tcp_seg_list) { g_tcp_seg_pool->put_objs(m_tcp_seg_list); @@ -1956,6 +1958,11 @@ void sockinfo_tcp::handle_incoming_handshake_failure(sockinfo_tcp *child_conn) child_conn->lock_tcp_con(); + /* Abort the connection first to avoid sending RST/FIN during close(). + * tcp_abort() -> tcp_abandon() does NOT send RST for SYN_RCVD state (per Linux behavior). + * This prevents segment allocation during close() path. */ + child_conn->abort_connection(); + if (safe_mce_sys().tcp_ctl_thread != option_tcp_ctl_thread::CTL_THREAD_DELEGATE_TCP_TIMERS) { // Object destruction is expected to happen in internal thread. Unless XLIO is in late // terminating stage, in which case we don't expect to handle packets.