]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] fuzzy_check: handle NULL upstream in lua_ping_storage
authorVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 25 Apr 2026 19:03:05 +0000 (20:03 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 25 Apr 2026 19:03:05 +0000 (20:03 +0100)
fuzzy_lua_ping_storage selected an upstream from rule->read_servers
without checking the result, then dereferenced the NULL pointer in
rspamd_upstream_addr_next(). With the new deferred-DNS upstream layer
this becomes reachable in normal operation (every upstream still
pending), and was already reachable before whenever the alive list
was empty.

Audit of other rspamd_upstream_get / _forced / _except / _token_bucket
call sites in C/C++ (rspamd_proxy.c, libserver/dns.c,
fuzzy_backend_redis.c, http/http_connection.c, libstat http_backend,
the other fuzzy_check sites) confirms they already guard the result
with `if (up)` or a `while (up = ...)` loop; only this site was
unchecked.

Return (false, "no fuzzy storage upstream available for rule X") to
the Lua caller instead of crashing.

src/plugins/fuzzy_check.c

index 2d29a1431f0140fcae9d13cbe28c9a882443b05d..5c95ac6e7e775d7d3ba222c23c7f162819c486a0 100644 (file)
@@ -7163,6 +7163,12 @@ fuzzy_lua_ping_storage(lua_State *L)
        else {
                struct upstream *selected = rspamd_upstream_get(rule_found->read_servers,
                                                                                                                RSPAMD_UPSTREAM_ROUND_ROBIN, NULL, 0);
+               if (selected == NULL) {
+                       lua_pushboolean(L, FALSE);
+                       lua_pushfstring(L, "no fuzzy storage upstream available for rule %s",
+                                                       rule_found->name);
+                       return 2;
+               }
                addr = rspamd_upstream_addr_next(selected);
        }