]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: event-filter - Ensure 0 can be matched correctly in filters
authorAki Tuomi <aki.tuomi@open-xchange.com>
Tue, 15 Nov 2022 11:44:46 +0000 (13:44 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Tue, 15 Nov 2022 13:42:23 +0000 (15:42 +0200)
Allow matching fields with > 0, priorly this would have always been
treated as string equality / wildcard match, instead we now want
to match it as number. Forgotten in 61cb32860f5237c5d928a7fed8a89f783c2f9b30

This fixes a signal 11 crash with equality comparison with a
non-wildcard value. Broken in aefe4941c14c6001a9d09fbc3122aca1417d00a8

src/lib/event-filter-parser.y
src/lib/event-filter.c
src/lib/test-event-filter.c

index 61aae104771ab2018a361ecc8865ad3dfc25842e..12b7d4bbc5255e798f1220f6311d14d3c06710bf 100644 (file)
@@ -93,6 +93,7 @@ static struct event_filter_node *key_value(struct event_filter_parser_state *sta
        case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
                node->field.key = p_strdup(state->pool, a);
                node->field.value.str = p_strdup(state->pool, b);
+               node->field.value_type = EVENT_FIELD_VALUE_TYPE_STR;
 
                /* Filter currently supports only comparing strings
                   and numbers. */
@@ -100,6 +101,9 @@ static struct event_filter_node *key_value(struct event_filter_parser_state *sta
                        /* not a number - no problem
                           Either we have a string, or a number with wildcards */
                        node->field.value.intmax = INT_MIN;
+               } else {
+                       /* leave a hint that this is in fact a valid number */
+                       node->field.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX;
                }
 
                if (wildcard_is_literal(node->field.value.str))
index 35bde967a70f4a3f2f177e3b39dd9ed030eaab1c..82f5f2535baa0c4aaf126f3d920d7eaaf6ade3ed 100644 (file)
@@ -573,7 +573,7 @@ event_match_field(struct event *event, const struct event_field *wanted_field,
                else
                        return wildcard_match_icase(field->value.str, wanted_field->value.str);
        case EVENT_FIELD_VALUE_TYPE_INTMAX:
-               if (wanted_field->value.intmax > INT_MIN) {
+               if (wanted_field->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX) {
                        /* compare against an integer */
                        switch (op) {
                        case EVENT_FILTER_OP_CMP_EQ:
@@ -592,18 +592,18 @@ event_match_field(struct event *event, const struct event_field *wanted_field,
                                i_unreached();
                        }
                        i_unreached();
+               } else if (op != EVENT_FILTER_OP_CMP_EQ) {
+                       /* we only support string equality comparisons */
+                       return FALSE;
+               } else if (use_strcmp) {
+                       /* If the matched value was a number, it was already matched
+                          in the previous branch. So here we have a non-wildcard
+                          string, which can never be a match to a number. */
+                       return FALSE;
                } else {
-                       /* compare against an "integer" with wildcards */
-                       if (op != EVENT_FILTER_OP_CMP_EQ) {
-                               /* we only support string equality comparisons */
-                               return FALSE;
-                       }
                        char tmp[MAX_INT_STRLEN];
                        i_snprintf(tmp, sizeof(tmp), "%jd", field->value.intmax);
-                       if (use_strcmp)
-                               return strcasecmp(field->value.str, wanted_field->value.str) == 0;
-                       else
-                               return wildcard_match_icase(tmp, wanted_field->value.str);
+                       return wildcard_match_icase(tmp, wanted_field->value.str);
                }
        case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
                /* there's no point to support matching exact timestamps */
index cc963c0e3e3c922dda18dd8d085e6043f4120ac5..8b3626a920a667c59d60e6127ef355a3e85c5d79 100644 (file)
@@ -603,6 +603,65 @@ static void test_event_filter_duration(void)
        test_end();
 }
 
+static void test_event_filter_numbers(void)
+{
+       struct event_filter *filter;
+       const char *error;
+       const struct failure_context failure_ctx = {
+               .type = LOG_TYPE_DEBUG
+       };
+
+       test_begin("event filter: event numeric matching");
+
+       /* we check that we can actually match duration field */
+       filter = event_filter_create();
+       test_assert(event_filter_parse("number > 0", filter, &error) == 0);
+
+       struct event *e = event_create(NULL);
+       event_add_int(e, "number", 1);
+       test_assert(event_filter_match(filter, e, &failure_ctx));
+       event_add_int(e, "number", 0);
+       test_assert(!event_filter_match(filter, e, &failure_ctx));
+       event_add_int(e, "number", -1);
+       test_assert(!event_filter_match(filter, e, &failure_ctx));
+       event_filter_unref(&filter);
+
+       filter = event_filter_create();
+       test_assert(event_filter_parse("number < 0", filter, &error) == 0);
+       event_add_int(e, "number", 1);
+       test_assert(!event_filter_match(filter, e, &failure_ctx));
+       event_add_int(e, "number", 0);
+       test_assert(!event_filter_match(filter, e, &failure_ctx));
+       event_add_int(e, "number", -1);
+       test_assert(event_filter_match(filter, e, &failure_ctx));
+       event_filter_unref(&filter);
+
+       event_add_int(e, "number", 0);
+
+       filter = event_filter_create();
+       test_assert(event_filter_parse("number > *", filter, &error) == 0);
+       test_assert(!event_filter_match(filter, e, &failure_ctx));
+       event_filter_unref(&filter);
+
+       filter = event_filter_create();
+       test_assert(event_filter_parse("number=0", filter, &error) == 0);
+       test_assert(event_filter_match(filter, e, &failure_ctx));
+       event_filter_unref(&filter);
+
+       filter = event_filter_create();
+       test_assert(event_filter_parse("number=*", filter, &error) == 0);
+       test_assert(event_filter_match(filter, e, &failure_ctx));
+       event_filter_unref(&filter);
+
+       filter = event_filter_create();
+       test_assert(event_filter_parse("number=fish", filter, &error) == 0);
+       test_assert(!event_filter_match(filter, e, &failure_ctx));
+       event_filter_unref(&filter);
+
+       event_unref(&e);
+       test_end();
+}
+
 void test_event_filter(void)
 {
        test_event_filter_override_parent_fields();
@@ -618,4 +677,5 @@ void test_event_filter(void)
        test_event_filter_named_or_str();
        test_event_filter_named_separate_from_str();
        test_event_filter_duration();
+       test_event_filter_numbers();
 }