]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Validate field type when matching events
authorKarl Fleischmann <karl.fleischmann@open-xchange.com>
Tue, 13 Dec 2022 08:28:54 +0000 (09:28 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 16 Dec 2022 08:16:44 +0000 (08:16 +0000)
This additionally requires a unit test to expect a warning.

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

index 1c70f2e32b6dac5233cece0a8943a9f1eba708b3..d1fa655942db5e0e822f0c514f82bc4744430d38 100644 (file)
@@ -54,6 +54,7 @@ static struct event_filter_node *key_value(struct event_filter_parser_state *sta
        node = p_new(state->pool, struct event_filter_node, 1);
        node->type = type;
        node->op = op;
+       node->warned_type_mismatch = FALSE;
 
        switch (type) {
        case EVENT_FILTER_NODE_TYPE_LOGIC:
@@ -101,6 +102,7 @@ static struct event_filter_node *key_value(struct event_filter_parser_state *sta
                if (str_to_intmax(b, &node->field.value.intmax) == 0) {
                        /* Leave a hint that this is in fact a valid number. */
                        node->field.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX;
+                       node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
                } else {
                        /* This field contains no valid number.
                           Either this is a string that contains a size unit, a
@@ -130,13 +132,17 @@ static struct event_filter_node *key_value(struct event_filter_parser_state *sta
                                node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
                                break;
                        }
+
+                       if (wildcard_is_literal(node->field.value.str))
+                               node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
+                       else if (strspn(b, "0123456789*?") == strlen(b))
+                               node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD;
                }
 
-               if (wildcard_is_literal(node->field.value.str))
-                       node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
                break;
        case EVENT_FILTER_NODE_TYPE_EVENT_NAME_EXACT:
        case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
+       case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
                i_unreached();
        }
 
index 5cd47bcda1bbae2a6d78e11077297faf0497de00..5019674ecd95f19283c12ab243b4d7a3ae0c4fe9 100644 (file)
@@ -39,6 +39,7 @@ enum event_filter_node_type {
        EVENT_FILTER_NODE_TYPE_EVENT_CATEGORY, /* cat */
        EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT, /* field */
        EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD, /* field */
+       EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD, /* field */
 };
 
 enum event_filter_log_type {
@@ -83,6 +84,8 @@ struct event_filter_node {
                struct event_category *ptr;
        } category;
        struct event_field field;
+
+       bool warned_type_mismatch:1;
 };
 
 bool event_filter_category_to_log_type(const char *name,
index ec00947b698f3e4a8c39597975f0bab2d99220a0..112a60d4dfb1e1488fb56d966e27188ee2f9ca37 100644 (file)
@@ -251,6 +251,7 @@ clone_expr(pool_t pool, struct event_filter_node *old)
        new->field.value.str = p_strdup(pool, old->field.value.str);
        new->field.value.intmax = old->field.value.intmax;
        new->field.value.timeval = old->field.value.timeval;
+       new->warned_type_mismatch = old->warned_type_mismatch;
 
        return new;
 }
@@ -387,6 +388,7 @@ event_filter_export_query_expr(const struct event_filter_query_internal *query,
                break;
        case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
        case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
+       case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
                str_append_c(dest, '"');
                event_filter_append_escaped(dest, node->field.key);
                str_append_c(dest, '"');
@@ -598,7 +600,21 @@ event_match_field(struct event *event, struct event_filter_node *node,
                else
                        return wildcard_match_icase(field->value.str, wanted_field->value.str);
        case EVENT_FIELD_VALUE_TYPE_INTMAX:
-               if (wanted_field->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX) {
+               if ((wanted_field->value_type != EVENT_FIELD_VALUE_TYPE_INTMAX) &&
+                   (node->type != EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD)) {
+                       if (!node->warned_type_mismatch) {
+                               const char *name = event->sending_name;
+                               /* Use i_warning to prevent event filter recursions. */
+                               i_warning("Event filter matches integer field "
+                                         "'%s' against non-integer value '%s'. "
+                                         "(event=%s)",
+                                         wanted_field->key,
+                                         wanted_field->value.str,
+                                         name != NULL ? name : "");
+                               node->warned_type_mismatch = TRUE;
+                       }
+                       return FALSE;
+               } else if (wanted_field->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX) {
                        /* compare against an integer */
                        return event_filter_handle_numeric_operation(
                                node->op, field->value.intmax, wanted_field->value.intmax);
@@ -659,6 +675,7 @@ event_filter_query_match_cmp(struct event_filter_node *node,
                case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
                        return event_match_field(event, node, TRUE);
                case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
+               case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
                        return event_match_field(event, node, FALSE);
        }
 
@@ -830,6 +847,7 @@ event_filter_query_update_category(struct event_filter_query_internal *query,
        case EVENT_FILTER_NODE_TYPE_EVENT_SOURCE_LOCATION:
        case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
        case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
+       case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
                break;
        case EVENT_FILTER_NODE_TYPE_EVENT_CATEGORY:
                if (node->category.name == NULL)
index d709e67bd801d5cf0680a441cfe75508c6681729..29e42f07851e5d8181ba6a18da0876e9f1ac2d37 100644 (file)
@@ -655,7 +655,10 @@ static void test_event_filter_numbers(void)
 
        filter = event_filter_create();
        test_assert(event_filter_parse("number=fish", filter, &error) == 0);
+       test_expect_error_string("Event filter matches integer field 'number' "
+                                "against non-integer value 'fish'");
        test_assert(!event_filter_match(filter, e, &failure_ctx));
+       test_expect_no_more_errors();
        event_filter_unref(&filter);
 
        event_unref(&e);