From: Vsevolod Stakhov Date: Tue, 13 Jan 2026 11:02:09 +0000 (+0000) Subject: [Fix] Fix fd leaks and double-free in srv_pipe error handling X-Git-Tag: 4.0.0~201^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d45972d8b96e48abb3cb893d699f3f66a2a3f544;p=thirdparty%2Frspamd.git [Fix] Fix fd leaks and double-free in srv_pipe error handling - Close attached_fd before freeing request data when sendmsg fails - Fix double-free in rspamd_srv_pipe_ctx_destroy: items in send_queue are also in the hash table, so only iterate hash to free - Close attached_fd for unsent requests during shutdown --- diff --git a/src/libserver/rspamd_control.c b/src/libserver/rspamd_control.c index 9dcba2ce58..83f275bb81 100644 --- a/src/libserver/rspamd_control.c +++ b/src/libserver/rspamd_control.c @@ -1450,12 +1450,15 @@ rspamd_srv_pipe_handler(EV_P_ ev_io *w, int revents) } msg_err("cannot write to server pipe: %s; command = %s", strerror(errno), rspamd_srv_command_to_string(rd->cmd.type)); - /* Remove from queue and hash, free */ + /* Remove from queue and hash, close fd if not transferred, free */ LL_DELETE(ctx->send_queue, rd); k = kh_get(rspamd_srv_requests, ctx->requests, rd->id); if (k != kh_end(ctx->requests)) { kh_del(rspamd_srv_requests, ctx->requests, k); } + if (rd->attached_fd != -1) { + close(rd->attached_fd); + } g_free(rd); continue; } @@ -1468,6 +1471,9 @@ rspamd_srv_pipe_handler(EV_P_ ev_io *w, int revents) if (k != kh_end(ctx->requests)) { kh_del(rspamd_srv_requests, ctx->requests, k); } + if (rd->attached_fd != -1) { + close(rd->attached_fd); + } g_free(rd); continue; } @@ -1562,7 +1568,7 @@ rspamd_srv_pipe_ctx_create(struct rspamd_worker *worker, struct ev_loop *ev_base static void rspamd_srv_pipe_ctx_destroy(struct rspamd_srv_pipe_ctx *ctx) { - struct rspamd_srv_request_data *rd, *tmp; + struct rspamd_srv_request_data *rd; khiter_t k; if (ctx == NULL) { @@ -1571,16 +1577,19 @@ rspamd_srv_pipe_ctx_destroy(struct rspamd_srv_pipe_ctx *ctx) ev_io_stop(ctx->ev_base, &ctx->io_ev); - /* Free send queue */ - LL_FOREACH_SAFE(ctx->send_queue, rd, tmp) - { - g_free(rd); - } - - /* Free pending requests */ + /* + * Free all pending requests from hash table. + * Note: items in send_queue are also in the hash, so we only iterate + * the hash to avoid double-free. For unsent items, close attached_fd + * since it was never transferred to main process. + */ for (k = kh_begin(ctx->requests); k != kh_end(ctx->requests); ++k) { if (kh_exist(ctx->requests, k)) { - g_free(kh_val(ctx->requests, k)); + rd = kh_val(ctx->requests, k); + if (!rd->sent && rd->attached_fd != -1) { + close(rd->attached_fd); + } + g_free(rd); } } kh_destroy(rspamd_srv_requests, ctx->requests);