From: Aki Tuomi Date: Tue, 15 Nov 2022 11:44:46 +0000 (+0200) Subject: lib: event-filter - Ensure 0 can be matched correctly in filters X-Git-Tag: 2.4.0~3432 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aa18c1b1196203b3586ed8fa665e9ca4b98e66c0;p=thirdparty%2Fdovecot%2Fcore.git lib: event-filter - Ensure 0 can be matched correctly in filters 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 --- diff --git a/src/lib/event-filter-parser.y b/src/lib/event-filter-parser.y index 61aae10477..12b7d4bbc5 100644 --- a/src/lib/event-filter-parser.y +++ b/src/lib/event-filter-parser.y @@ -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)) diff --git a/src/lib/event-filter.c b/src/lib/event-filter.c index 35bde967a7..82f5f2535b 100644 --- a/src/lib/event-filter.c +++ b/src/lib/event-filter.c @@ -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 */ diff --git a/src/lib/test-event-filter.c b/src/lib/test-event-filter.c index cc963c0e3e..8b3626a920 100644 --- a/src/lib/test-event-filter.c +++ b/src/lib/test-event-filter.c @@ -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(); }