From: Karl Fleischmann Date: Tue, 13 Dec 2022 08:28:54 +0000 (+0100) Subject: lib: Validate field type when matching events X-Git-Tag: 2.4.0~3281 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e5dd25c2814f2ff0627bff6f25b210267a469778;p=thirdparty%2Fdovecot%2Fcore.git lib: Validate field type when matching events This additionally requires a unit test to expect a warning. --- diff --git a/src/lib/event-filter-parser.y b/src/lib/event-filter-parser.y index 1c70f2e32b..d1fa655942 100644 --- a/src/lib/event-filter-parser.y +++ b/src/lib/event-filter-parser.y @@ -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(); } diff --git a/src/lib/event-filter-private.h b/src/lib/event-filter-private.h index 5cd47bcda1..5019674ecd 100644 --- a/src/lib/event-filter-private.h +++ b/src/lib/event-filter-private.h @@ -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, diff --git a/src/lib/event-filter.c b/src/lib/event-filter.c index ec00947b69..112a60d4df 100644 --- a/src/lib/event-filter.c +++ b/src/lib/event-filter.c @@ -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) diff --git a/src/lib/test-event-filter.c b/src/lib/test-event-filter.c index d709e67bd8..29e42f0785 100644 --- a/src/lib/test-event-filter.c +++ b/src/lib/test-event-filter.c @@ -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);