From: Vsevolod Stakhov Date: Mon, 30 Mar 2026 15:30:59 +0000 (+0100) Subject: [Feature] Add force-enable override for settings conflicts X-Git-Tag: 4.0.1~6^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a538ab90cd29cee3bc5e9e088916b181da07d2e9;p=thirdparty%2Frspamd.git [Feature] Add force-enable override for settings conflicts When merged settings explicitly enable a symbol that settings_elt has in forbidden_ids, the merged result now wins. Uses a per-task GHashTable (mempool variable "force_enabled_ids") populated during process_settings() and checked in is_allowed() before consulting the precomputed bitsets. This implements the "enable > disable, explicit > implicit" conflict resolution rule. --- diff --git a/src/libserver/symcache/symcache_item.cxx b/src/libserver/symcache/symcache_item.cxx index 77750bbb98..a96fb41164 100644 --- a/src/libserver/symcache/symcache_item.cxx +++ b/src/libserver/symcache/symcache_item.cxx @@ -362,13 +362,23 @@ auto cache_item::is_allowed(struct rspamd_task *task, bool exec_only) const -> b /* Settings checks */ if (task->settings_elt != nullptr) { if (forbidden_ids.check_id(task->settings_elt->id)) { - msg_debug_cache_task("deny %s of %s as it is forbidden for " - "settings id %ud", - what, - symbol.c_str(), - task->settings_elt->id); + /* Check if force-enabled by merged settings */ + auto *force_ht = (GHashTable *) rspamd_mempool_get_variable( + task->task_pool, "force_enabled_ids"); + if (force_ht && g_hash_table_contains(force_ht, GINT_TO_POINTER(id))) { + msg_debug_cache_task("allow %s of %s: force-enabled by merged " + "settings overriding settings_elt forbidden_ids", + what, symbol.c_str()); + } + else { + msg_debug_cache_task("deny %s of %s as it is forbidden for " + "settings id %ud", + what, + symbol.c_str(), + task->settings_elt->id); - return false; + return false; + } } if (!(flags & SYMBOL_TYPE_EXPLICIT_DISABLE)) { diff --git a/src/libserver/symcache/symcache_runtime.cxx b/src/libserver/symcache/symcache_runtime.cxx index c88514cb80..e4d8e2d0e1 100644 --- a/src/libserver/symcache/symcache_runtime.cxx +++ b/src/libserver/symcache/symcache_runtime.cxx @@ -118,6 +118,31 @@ auto symcache_runtime::process_settings(struct rspamd_task *task, const symcache const auto *enabled = ucl_object_lookup(task->settings, "symbols_enabled"); + /* + * Track force-enabled symbols: if settings_elt has a symbol in forbidden_ids + * but the merged settings explicitly enable it, we need to override the bitset + */ + auto force_enable = [&](const char *sym) { + enable_symbol(task, cache, sym); + + if (task->settings_elt) { + const auto *item = cache.get_item_by_name(sym, true); + if (item && item->forbidden_ids.check_id(task->settings_elt->id)) { + auto *force_ht = (GHashTable *) rspamd_mempool_get_variable( + task->task_pool, "force_enabled_ids"); + if (!force_ht) { + force_ht = g_hash_table_new(g_direct_hash, g_direct_equal); + rspamd_mempool_set_variable(task->task_pool, "force_enabled_ids", + force_ht, + (rspamd_mempool_destruct_t) g_hash_table_unref); + } + g_hash_table_insert(force_ht, GINT_TO_POINTER(item->id), GINT_TO_POINTER(1)); + msg_debug_cache_task("force-enable %s (id=%d) overriding settings_elt forbidden_ids", + sym, item->id); + } + } + }; + if (enabled) { msg_debug_cache_task("disable all symbols as `symbols_enabled` is found"); /* Disable all symbols but selected */ @@ -126,7 +151,7 @@ auto symcache_runtime::process_settings(struct rspamd_task *task, const symcache it = nullptr; while ((cur = ucl_iterate_object(enabled, &it, true)) != nullptr) { - enable_symbol(task, cache, ucl_object_tostring(cur)); + force_enable(ucl_object_tostring(cur)); } } @@ -136,7 +161,7 @@ auto symcache_runtime::process_settings(struct rspamd_task *task, const symcache disable_all_symbols(SYMBOL_TYPE_EXPLICIT_DISABLE); } process_group(enabled, [&](const char *sym) { - enable_symbol(task, cache, sym); + force_enable(sym); }); const auto *disabled = ucl_object_lookup(task->settings, "symbols_disabled");