From: Aki Tuomi Date: Mon, 17 Feb 2025 09:47:52 +0000 (+0200) Subject: lib-var-expand: Validate UTF-8 input X-Git-Tag: 2.4.1~190 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=07838de2f838fce4f23c45059242e2bd4be23e73;p=thirdparty%2Fdovecot%2Fcore.git lib-var-expand: Validate UTF-8 input --- diff --git a/src/lib-var-expand/test-var-expand.c b/src/lib-var-expand/test-var-expand.c index 6c227df567..3f3327f1b3 100644 --- a/src/lib-var-expand/test-var-expand.c +++ b/src/lib-var-expand/test-var-expand.c @@ -89,6 +89,7 @@ static void test_var_expand_builtin_filters(void) { { .key = "multivalue", .value = "one\ttwo\tthree" }, { .key = "uidvalidity", .value = "1727121943" }, { .key = "empty", .value = "" }, + { .key = "\xce\xb8", .value = "is theta" }, { .key = "null", .value = NULL }, VAR_EXPAND_TABLE_END }; @@ -242,6 +243,8 @@ static void test_var_expand_builtin_filters(void) { { .in = "%{first | md5 % 30 | hex(2) }", .out = "16", .ret = 0 }, { .in = "%{first | md5 % 30 | hex(4) }", .out = "0016", .ret = 0 }, { .in = "%{first | md5 % 30 | hex(-4) }", .out = "1600", .ret = 0 }, + { .in = "%{\xce\xb8}", .out = "is theta", .ret = 0 }, + { .in = "%{\xff\xfe\xff}", .out = "Invalid UTF-8 string", .ret = -1 }, }; const struct var_expand_params params = { diff --git a/src/lib-var-expand/var-expand-lexer.l b/src/lib-var-expand/var-expand-lexer.l index 64e0cc2794..0b8433ab91 100644 --- a/src/lib-var-expand/var-expand-lexer.l +++ b/src/lib-var-expand/var-expand-lexer.l @@ -14,6 +14,7 @@ %{ #include "lib.h" +#include "unichar.h" #include "str.h" #include "var-expand-private.h" #include "var-expand-parser-private.h" @@ -47,6 +48,11 @@ static size_t input_proc(char *buf, size_t size, yyscan_t scanner); } STMT_END static int scanner_error(void *yyscanner, const char *msg); +static bool append_valid_utf8(void *yyscanner, YYSTYPE *state, const char *value); +#define append_valid_utf8(state, value) \ + if (!append_valid_utf8(yyscanner, (state), (value))) { \ + return VAR_EXPAND_PARSER_error; \ + } %} %x stringsq @@ -83,20 +89,20 @@ static int scanner_error(void *yyscanner, const char *msg); { [\\] { yy_push_state(quote, yyscanner); } ["] { yy_pop_state(yyscanner); return VALUE; } - [^"\\]* { str_append(yylval->str, yytext); } + [^"\\]* { append_valid_utf8(yylval, yytext); } } { [\\] { yy_push_state(quote, yyscanner); } ['] { yy_pop_state(yyscanner); return VALUE; } - [^'\\]* { str_append(yylval->str, yytext); } + [^'\\]* { append_valid_utf8(yylval, yytext); } } { "}" { yy_pop_state(yyscanner); return CCBRACE; } [ \t] { /* ignore */ } \% { return PERC; } - [a-zA-Z\x80-\xff][a-zA-Z0-9_/;:.\x80-\xff-]* { INIT_STR; str_append(yylval->str, yytext); return NAME; } + [a-zA-Z\x80-\xff][a-zA-Z0-9_/;:.\x80-\xff-]* { INIT_STR; append_valid_utf8(yylval, yytext); return NAME; } \| { return PIPE; } \( { return OBRACE; } \) { return CBRACE; } @@ -110,7 +116,7 @@ static int scanner_error(void *yyscanner, const char *msg); ["] { yy_push_state(stringdq, yyscanner); INIT_STR; } [0-9]+ { INIT_STR; str_append(yylval->str, yytext); return NUMBER; } } - +y "%{" { yy_push_state(expr, yyscanner); return OCBRACE; } "%%{" { INIT_STR; str_append(yylval->str, "%{"); return VALUE; } "%" { return PERC; } @@ -151,6 +157,17 @@ void yyfree(void *ptr, void *yyscanner) p_free(state->pool, ptr); } +#undef append_valid_utf8 +static bool append_valid_utf8(void *scanner, YYSTYPE *state, const char *value) +{ + if (!uni_utf8_str_is_valid(value)) { + (void)scanner_error(scanner, "Invalid UTF-8 string"); + return FALSE; + } + str_append(state->str, value); + return TRUE; +} + #define INPUT_POS(state) (state->input + state->input_pos) static size_t input_proc(char *buf, size_t size, yyscan_t scanner)