]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] re_cache: stop timer during async operations to prevent re-entry
authorVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 29 Jan 2026 16:49:20 +0000 (16:49 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 29 Jan 2026 16:49:20 +0000 (16:49 +0000)
Stop the timer before calling exists_async and save_async to prevent
the timer from firing multiple times while an async callback is pending.
Without this, the repeating timer (0.1s interval) could fire again before
the async operation completes, causing multiple concurrent async calls
for the same re_class. This led to race conditions and use-after-free
crashes when callbacks completed out of order.

src/libserver/re_cache.c

index a7a3b2c699a6d02696f483e12ba0558bc0827719..cf8289c858065d6fcfaf3e3b0d8e2c20a82a92fa 100644 (file)
@@ -2424,6 +2424,12 @@ rspamd_re_cache_compile_timer_cb(EV_P_ ev_timer *w, int revents)
                        rspamd_snprintf(entity_name, sizeof(entity_name), "re_class:%s",
                                                        rspamd_re_cache_type_to_string(re_class->type));
                }
+               /*
+                * Stop timer while async operation is pending to prevent
+                * multiple concurrent exists_async calls for the same class.
+                * The callback will restart the timer with ev_timer_again.
+                */
+               ev_timer_stop(EV_A_ w);
                REF_RETAIN(cbdata);
                rspamd_hs_cache_lua_exists_async(re_class->hash, entity_name, rspamd_re_cache_exists_cb, ctx);
                return;
@@ -2667,6 +2673,12 @@ rspamd_re_cache_compile_timer_cb(EV_P_ ev_timer *w, int revents)
                        rspamd_snprintf(entity_name, sizeof(entity_name), "re_class:%s",
                                                        rspamd_re_cache_type_to_string(re_class->type));
                }
+               /*
+                * Stop timer while async save is pending to prevent
+                * re-entry into the compilation state machine.
+                * The callback will restart the timer with ev_timer_again.
+                */
+               ev_timer_stop(EV_A_ w);
                REF_RETAIN(cbdata);
                rspamd_hs_cache_lua_save_async(re_class->hash, entity_name, combined, total_len, rspamd_re_cache_save_cb, ctx);