From 6b599e44111b855c7c7a76d337079a61940b0d28 Mon Sep 17 00:00:00 2001 From: Narate Taerat Date: Wed, 17 Jan 2024 17:16:48 -0600 Subject: [PATCH] Fix zap_sock rejected endpoint leak The incoming-connection-request endpoint that got rejected by the application did not yet have a thread to process its events. As a result, when the remote peer disconnected after receiving REJECTED message, the passive side would not get EPOLLHUP event (which will drop corresponding references and clean up endpoint resources) because the endpoint was not in any thread's epoll. The rejected endpoint was left dangling, leaking endpoint resources including socket file descriptor. This patch fixes the issue by dropping the corresponding endpoint references to clean up rejected endpoint resources. The rejected endpoint does not need to get a zap thread assigned to handle this. NOTE: This bug is introduced by Rail implementation. The RAIL implementation modified `zap_sock` to use the thread of the listening endpoint to process connection request instead of assigning it a new thread right away. The behavior BEFORE Rail was to assign a thread to the incoming endpoint right away. This bug does not affect OVIS-4.4.x. --- lib/src/zap/sock/zap_sock.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/src/zap/sock/zap_sock.c b/lib/src/zap/sock/zap_sock.c index 008a5eca93..3bdf6d26ad 100644 --- a/lib/src/zap/sock/zap_sock.c +++ b/lib/src/zap/sock/zap_sock.c @@ -1992,7 +1992,8 @@ static void z_sock_destroy(zap_ep_t ep) DEBUG_LOG(sep, "%ld z_sock_destroy(%p)\n", GETTID(), sep); - zap_io_thread_ep_remove(ep); + if (ep->thread) + zap_io_thread_ep_remove(ep); while (!TAILQ_EMPTY(&sep->sq)) { wr = TAILQ_FIRST(&sep->sq); @@ -2063,7 +2064,13 @@ static zap_err_t z_sock_reject(zap_ep_t ep, char *data, size_t data_len) zerr = __sock_send(sep, SOCK_MSG_REJECTED, data, data_len); if (zerr) goto err; + /* move to error state before we terminate it */ + sep->ep.state = ZAP_EP_ERROR; + pthread_mutex_unlock(&sep->ep.lock); + ref_put(&ep->ref, "accept/connect"); /* from __z_sock_conn_request() */ + zap_free(ep); + /* The caller never touched ep after reject */ return ZAP_ERR_OK; err: sep->ep.state = ZAP_EP_ERROR;