]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] Filter forbidden_ids from multi-flag extra flags in v2 reply
authorVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 18 Feb 2026 15:33:02 +0000 (15:33 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 18 Feb 2026 15:33:02 +0000 (15:33 +0000)
Extract forbidden flag checks into rspamd_fuzzy_filter_forbidden_v2()
which filters both primary and extra flags. If primary is forbidden
but valid extras remain, promotes first valid extra to primary.

src/fuzzy_storage.c

index 47324a0445480f6c3e5f70f6b04a080c99cf9c47..c960ac31b5efba5277e130047b998ff77e933510 100644 (file)
@@ -615,6 +615,78 @@ enum rspamd_fuzzy_reply_flags {
        RSPAMD_FUZZY_REPLY_DELAY = 0x1u << 2u,
 };
 
+/*
+ * Check if a flag ID is forbidden by the given set or per-key set.
+ * Returns true if the flag should be suppressed.
+ */
+static bool
+rspamd_fuzzy_flag_is_forbidden(struct fuzzy_session *session,
+                                                          uint32_t flag, int reply_flags)
+{
+       khiter_t k;
+
+       k = kh_get(fuzzy_key_ids_set, session->ctx->default_forbidden_ids, flag);
+       if (k != kh_end(session->ctx->default_forbidden_ids)) {
+               return true;
+       }
+
+       if ((reply_flags & RSPAMD_FUZZY_REPLY_ENCRYPTED) &&
+               session->key && session->key->forbidden_ids) {
+               k = kh_get(fuzzy_key_ids_set, session->key->forbidden_ids, flag);
+               if (k != kh_end(session->key->forbidden_ids)) {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+/*
+ * Filter forbidden flags from a v2 reply.
+ * Removes forbidden extra flags in-place. If the primary flag is forbidden,
+ * promotes the first valid extra flag to primary; if all flags are forbidden,
+ * zeroes the entire reply.
+ */
+static void
+rspamd_fuzzy_filter_forbidden_v2(struct rspamd_fuzzy_reply_v2 *rep_v2,
+                                                                struct fuzzy_session *session,
+                                                                int reply_flags)
+{
+       /* First, filter forbidden extra flags */
+       uint8_t dst = 0;
+       for (uint8_t i = 0; i < rep_v2->n_extra_flags; i++) {
+               if (!rspamd_fuzzy_flag_is_forbidden(session,
+                                                                                       rep_v2->extra_flags[i].flag, reply_flags)) {
+                       if (dst != i) {
+                               rep_v2->extra_flags[dst] = rep_v2->extra_flags[i];
+                       }
+                       dst++;
+               }
+       }
+       rep_v2->n_extra_flags = dst;
+
+       /* Check if primary flag is forbidden */
+       if (rspamd_fuzzy_flag_is_forbidden(session, rep_v2->v1.flag, reply_flags)) {
+               if (rep_v2->n_extra_flags > 0) {
+                       /* Promote the first valid extra flag to primary */
+                       rep_v2->v1.value = rep_v2->extra_flags[0].value;
+                       rep_v2->v1.flag = rep_v2->extra_flags[0].flag;
+                       /* Shift remaining extras down */
+                       for (uint8_t i = 1; i < rep_v2->n_extra_flags; i++) {
+                               rep_v2->extra_flags[i - 1] = rep_v2->extra_flags[i];
+                       }
+                       rep_v2->n_extra_flags--;
+               }
+               else {
+                       /* All flags forbidden — suppress the entire result */
+                       rep_v2->ts = 0;
+                       rep_v2->v1.prob = 0.0f;
+                       rep_v2->v1.value = 0;
+                       rep_v2->v1.flag = 0;
+               }
+       }
+}
+
 static void
 rspamd_fuzzy_make_reply(struct rspamd_fuzzy_cmd *cmd,
                                                struct rspamd_fuzzy_reply *result,
@@ -650,32 +722,10 @@ rspamd_fuzzy_make_reply(struct rspamd_fuzzy_cmd *cmd,
                                rep_v2->v1.value = 0;
                        }
 
-                       bool default_disabled = false;
-                       {
-                               khiter_t k;
-                               k = kh_get(fuzzy_key_ids_set, session->ctx->default_forbidden_ids, rep_v2->v1.flag);
-                               if (k != kh_end(session->ctx->default_forbidden_ids)) {
-                                       default_disabled = true;
-                               }
-                       }
+                       /* Filter forbidden flags from primary and extra flags */
+                       rspamd_fuzzy_filter_forbidden_v2(rep_v2, session, flags);
 
                        if (flags & RSPAMD_FUZZY_REPLY_ENCRYPTED) {
-                               if (rep_v2->v1.prob > 0 && session->key && session->key->forbidden_ids) {
-                                       khiter_t k;
-                                       k = kh_get(fuzzy_key_ids_set, session->key->forbidden_ids, rep_v2->v1.flag);
-                                       if (k != kh_end(session->key->forbidden_ids)) {
-                                               rep_v2->ts = 0;
-                                               rep_v2->v1.prob = 0.0f;
-                                               rep_v2->v1.value = 0;
-                                               rep_v2->v1.flag = 0;
-                                       }
-                               }
-                               else if (default_disabled) {
-                                       rep_v2->ts = 0;
-                                       rep_v2->v1.prob = 0.0f;
-                                       rep_v2->v1.value = 0;
-                                       rep_v2->v1.flag = 0;
-                               }
 
                                /* Use a temporary v1 reply for stats (stats API expects rspamd_fuzzy_reply) */
                                struct rspamd_fuzzy_reply stats_rep;
@@ -709,13 +759,6 @@ rspamd_fuzzy_make_reply(struct rspamd_fuzzy_cmd *cmd,
                                                                                                        session->reply.v2.hdr.mac);
                        }
                        else {
-                               if (default_disabled) {
-                                       rep_v2->ts = 0;
-                                       rep_v2->v1.prob = 0.0f;
-                                       rep_v2->v1.value = 0;
-                                       rep_v2->v1.flag = 0;
-                               }
-
                                struct rspamd_fuzzy_reply stats_rep;
                                memset(&stats_rep, 0, sizeof(stats_rep));
                                stats_rep.v1 = rep_v2->v1;