From cfde639a4195395381b2ea1b7f45f09e43a1e7c9 Mon Sep 17 00:00:00 2001 From: munzzyy Date: Sun, 2 Aug 2026 10:02:04 -0500 Subject: [PATCH] reject hex jump and repeat lengths that overflow an int The hex string and regexp lexers parse jump lengths and repeat intervals with atoi, which is undefined for numbers that don't fit in an int. glibc hands back the low 32 bits, so a value that wraps to a small positive number passes every bounds check and silently changes the pattern: rule r1 { strings: $a = /a{4294967296}/ condition: $a } rule r2 { strings: $b = { 61 [0-4294967297] 62 } condition: $b } Before this change r1 compiled as a{0} and matched at every offset, and r2 compiled as { 61 [0-1] 62 }. MSVC saturates atoi at INT_MAX instead, so the same rule behaves differently there, which is what #1791 reports. Parse with strtoll instead. Numbers too large for a long long are clamped to LLONG_MAX, which still fails the range check, so "repeat interval too large" now fires for everything above RE_MAX_RANGE on any platform. Hex jumps get an explicit INT_MAX check because RE_NODE stores start and end as ints, and the grammar already casts to int. The hi_bound < 0 and lo_bound < 0 checks are gone. They were there to catch atoi wrapping negative and are unreachable now that the only thing the pattern matches is digits. Fixes #1791. --- libyara/hex_lexer.c | 76 ++++++++++++++++++++-------------- libyara/hex_lexer.l | 18 ++++++++- libyara/re_lexer.c | 99 +++++++++++++++++++++++---------------------- libyara/re_lexer.l | 25 +++++++----- tests/test-rules.c | 20 +++++++++ 5 files changed, 148 insertions(+), 90 deletions(-) diff --git a/libyara/hex_lexer.c b/libyara/hex_lexer.c index 97c80f05dd..209bab0df8 100644 --- a/libyara/hex_lexer.c +++ b/libyara/hex_lexer.c @@ -735,6 +735,7 @@ with noyywrap then we can remove this pragma. #pragma GCC diagnostic ignored "-Wunused-function" #endif +#include #include #include @@ -750,6 +751,7 @@ with noyywrap then we can remove this pragma. #ifdef _WIN32 #define snprintf _snprintf +#define strtoll _strtoi64 #endif #define ERROR_IF(x, error) \ @@ -760,11 +762,11 @@ with noyywrap then we can remove this pragma. YYABORT; \ } \ -#line 763 "libyara/hex_lexer.c" +#line 765 "libyara/hex_lexer.c" #define YY_NO_UNISTD_H 1 #define YY_NO_INPUT 1 -#line 767 "libyara/hex_lexer.c" +#line 769 "libyara/hex_lexer.c" #define INITIAL 0 #define comment 1 @@ -1038,11 +1040,11 @@ YY_DECL } { -#line 95 "libyara/hex_lexer.l" +#line 97 "libyara/hex_lexer.l" -#line 1045 "libyara/hex_lexer.c" +#line 1047 "libyara/hex_lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1109,7 +1111,7 @@ YY_DECL case 1: YY_RULE_SETUP -#line 98 "libyara/hex_lexer.l" +#line 100 "libyara/hex_lexer.l" { yylval->integer = xtoi(yytext); @@ -1118,7 +1120,7 @@ YY_RULE_SETUP YY_BREAK case 2: YY_RULE_SETUP -#line 104 "libyara/hex_lexer.l" +#line 106 "libyara/hex_lexer.l" { yytext[1] = '0'; // replace ? by 0 @@ -1128,7 +1130,7 @@ YY_RULE_SETUP YY_BREAK case 3: YY_RULE_SETUP -#line 111 "libyara/hex_lexer.l" +#line 113 "libyara/hex_lexer.l" { yylval->integer = xtoi(&(yytext[1])); @@ -1137,7 +1139,7 @@ YY_RULE_SETUP YY_BREAK case 4: YY_RULE_SETUP -#line 117 "libyara/hex_lexer.l" +#line 119 "libyara/hex_lexer.l" { yytext[0] = '0'; // replace ? by 0 @@ -1147,7 +1149,7 @@ YY_RULE_SETUP YY_BREAK case 5: YY_RULE_SETUP -#line 124 "libyara/hex_lexer.l" +#line 126 "libyara/hex_lexer.l" { yylval->integer = 0x0000; @@ -1156,7 +1158,7 @@ YY_RULE_SETUP YY_BREAK case 6: YY_RULE_SETUP -#line 130 "libyara/hex_lexer.l" +#line 132 "libyara/hex_lexer.l" { yytext[2] = '0'; // replace ? by 0 @@ -1166,7 +1168,7 @@ YY_RULE_SETUP YY_BREAK case 7: YY_RULE_SETUP -#line 137 "libyara/hex_lexer.l" +#line 139 "libyara/hex_lexer.l" { yytext[1] = '0'; // replace ? by 0 @@ -1176,7 +1178,7 @@ YY_RULE_SETUP YY_BREAK case 8: YY_RULE_SETUP -#line 144 "libyara/hex_lexer.l" +#line 146 "libyara/hex_lexer.l" { yyerror(yyscanner, lex_env, "uneven number of digits in hex string"); @@ -1185,7 +1187,7 @@ YY_RULE_SETUP YY_BREAK case 9: YY_RULE_SETUP -#line 150 "libyara/hex_lexer.l" +#line 152 "libyara/hex_lexer.l" { yyerror(yyscanner, lex_env, "invalid not operator (~) in hex string"); @@ -1194,7 +1196,7 @@ YY_RULE_SETUP YY_BREAK case 10: YY_RULE_SETUP -#line 157 "libyara/hex_lexer.l" +#line 159 "libyara/hex_lexer.l" { BEGIN(range); @@ -1203,7 +1205,7 @@ YY_RULE_SETUP YY_BREAK case 11: YY_RULE_SETUP -#line 163 "libyara/hex_lexer.l" +#line 165 "libyara/hex_lexer.l" { BEGIN(comment); @@ -1211,7 +1213,7 @@ YY_RULE_SETUP YY_BREAK case 12: YY_RULE_SETUP -#line 168 "libyara/hex_lexer.l" +#line 170 "libyara/hex_lexer.l" { BEGIN(INITIAL); @@ -1220,17 +1222,17 @@ YY_RULE_SETUP case 13: /* rule 13 can match eol */ YY_RULE_SETUP -#line 173 "libyara/hex_lexer.l" +#line 175 "libyara/hex_lexer.l" // skip comments YY_BREAK case 14: YY_RULE_SETUP -#line 175 "libyara/hex_lexer.l" +#line 177 "libyara/hex_lexer.l" // skip single-line comments YY_BREAK case 15: YY_RULE_SETUP -#line 177 "libyara/hex_lexer.l" +#line 179 "libyara/hex_lexer.l" { return yytext[0]; @@ -1238,16 +1240,30 @@ YY_RULE_SETUP YY_BREAK case 16: YY_RULE_SETUP -#line 182 "libyara/hex_lexer.l" +#line 184 "libyara/hex_lexer.l" { - yylval->integer = atoi(yytext); + // strtoll is used instead of atoi because atoi has undefined behaviour for + // numbers that don't fit in an int. Numbers too large for a long long are + // clamped to LLONG_MAX by strtoll, which is still caught by the check below. + + yylval->integer = strtoll(yytext, NULL, 10); + + // Jump lengths end up stored in the int fields of a RE_NODE, anything above + // INT_MAX can't be represented. + + if (yylval->integer > INT_MAX) + { + yyerror(yyscanner, lex_env, "jump length too large"); + yyterminate(); + } + return _NUMBER_; } YY_BREAK case 17: YY_RULE_SETUP -#line 188 "libyara/hex_lexer.l" +#line 204 "libyara/hex_lexer.l" { BEGIN(INITIAL); @@ -1257,12 +1273,12 @@ YY_RULE_SETUP case 18: /* rule 18 can match eol */ YY_RULE_SETUP -#line 194 "libyara/hex_lexer.l" +#line 210 "libyara/hex_lexer.l" // skip whitespaces YY_BREAK case 19: YY_RULE_SETUP -#line 196 "libyara/hex_lexer.l" +#line 212 "libyara/hex_lexer.l" { yyerror(yyscanner, lex_env, "invalid character in hex string jump"); @@ -1272,12 +1288,12 @@ YY_RULE_SETUP case 20: /* rule 20 can match eol */ YY_RULE_SETUP -#line 202 "libyara/hex_lexer.l" +#line 218 "libyara/hex_lexer.l" // skip whitespaces YY_BREAK case 21: YY_RULE_SETUP -#line 204 "libyara/hex_lexer.l" +#line 220 "libyara/hex_lexer.l" { // pass valid characters to the parser return yytext[0]; @@ -1285,7 +1301,7 @@ YY_RULE_SETUP YY_BREAK case 22: YY_RULE_SETUP -#line 209 "libyara/hex_lexer.l" +#line 225 "libyara/hex_lexer.l" { // reject all other characters yyerror(yyscanner, lex_env, "invalid character in hex string"); @@ -1294,10 +1310,10 @@ YY_RULE_SETUP YY_BREAK case 23: YY_RULE_SETUP -#line 215 "libyara/hex_lexer.l" +#line 231 "libyara/hex_lexer.l" ECHO; YY_BREAK -#line 1300 "libyara/hex_lexer.c" +#line 1316 "libyara/hex_lexer.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(comment): case YY_STATE_EOF(range): @@ -2450,7 +2466,7 @@ void yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 215 "libyara/hex_lexer.l" +#line 231 "libyara/hex_lexer.l" // diff --git a/libyara/hex_lexer.l b/libyara/hex_lexer.l index ad99244905..887dd98c42 100644 --- a/libyara/hex_lexer.l +++ b/libyara/hex_lexer.l @@ -44,6 +44,7 @@ with noyywrap then we can remove this pragma. #pragma GCC diagnostic ignored "-Wunused-function" #endif +#include #include #include @@ -59,6 +60,7 @@ with noyywrap then we can remove this pragma. #ifdef _WIN32 #define snprintf _snprintf +#define strtoll _strtoi64 #endif #define ERROR_IF(x, error) \ @@ -181,7 +183,21 @@ hexdigit [a-fA-F0-9] {digit}+ { - yylval->integer = atoi(yytext); + // strtoll is used instead of atoi because atoi has undefined behaviour for + // numbers that don't fit in an int. Numbers too large for a long long are + // clamped to LLONG_MAX by strtoll, which is still caught by the check below. + + yylval->integer = strtoll(yytext, NULL, 10); + + // Jump lengths end up stored in the int fields of a RE_NODE, anything above + // INT_MAX can't be represented. + + if (yylval->integer > INT_MAX) + { + yyerror(yyscanner, lex_env, "jump length too large"); + yyterminate(); + } + return _NUMBER_; } diff --git a/libyara/re_lexer.c b/libyara/re_lexer.c index 34b948cdf9..78c15485c2 100644 --- a/libyara/re_lexer.c +++ b/libyara/re_lexer.c @@ -770,6 +770,7 @@ with noyywrap then we can remove this pragma. #ifdef _WIN32 #define snprintf _snprintf +#define strtoll _strtoi64 #endif // Bitmap with 1 bit for each of the 256 characters in the ASCII table. The bit @@ -800,10 +801,10 @@ int read_escaped_char( uint8_t* escaped_char, bool strict_escape); -#line 803 "libyara/re_lexer.c" +#line 804 "libyara/re_lexer.c" #define YY_NO_UNISTD_H 1 -#line 806 "libyara/re_lexer.c" +#line 807 "libyara/re_lexer.c" #define INITIAL 0 #define char_class 1 @@ -1076,10 +1077,10 @@ YY_DECL } { -#line 114 "libyara/re_lexer.l" +#line 115 "libyara/re_lexer.l" -#line 1082 "libyara/re_lexer.c" +#line 1083 "libyara/re_lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1146,13 +1147,18 @@ YY_DECL case 1: YY_RULE_SETUP -#line 116 "libyara/re_lexer.l" +#line 117 "libyara/re_lexer.l" { // Examples: {3,8} {3, 8}, {3 ,8} {3 , 8} {0,5} {,5} {7,} - int hi_bound; - int lo_bound = atoi(yytext + 1); + // strtoll is used instead of atoi because atoi has undefined behaviour for + // numbers that don't fit in an int. Numbers too large for a long long are + // clamped to LLONG_MAX by strtoll, which is still caught by the RE_MAX_RANGE + // check below. + + long long hi_bound; + long long lo_bound = strtoll(yytext + 1, NULL, 10); char* comma = strchr(yytext, ','); char* hi_bound_ptr = comma + 1; @@ -1163,7 +1169,7 @@ YY_RULE_SETUP if (*hi_bound_ptr == '}') hi_bound = RE_MAX_RANGE; else - hi_bound = atoi(hi_bound_ptr); + hi_bound = strtoll(hi_bound_ptr, NULL, 10); if (hi_bound > RE_MAX_RANGE) { @@ -1171,43 +1177,40 @@ YY_RULE_SETUP yyterminate(); } - if (hi_bound < lo_bound || hi_bound < 0 || lo_bound < 0) + if (hi_bound < lo_bound) { yyerror(yyscanner, lex_env, "bad repeat interval"); yyterminate(); } - yylval->range = (hi_bound << 16) | lo_bound; + yylval->range = (uint32_t) ((hi_bound << 16) | lo_bound); return _RANGE_; } YY_BREAK case 2: YY_RULE_SETUP -#line 152 "libyara/re_lexer.l" +#line 158 "libyara/re_lexer.l" { // Example: {10} - int value = atoi(yytext + 1); - - // atoi can return a negative value if the input string represents a number - // too large to fit in an integer. + long long value = strtoll(yytext + 1, NULL, 10); - if (value > RE_MAX_RANGE || value < 0) + if (value > RE_MAX_RANGE) { yyerror(yyscanner, lex_env, "repeat interval too large"); yyterminate(); } - yylval->range = (value << 16) | value; + yylval->range = (uint32_t) ((value << 16) | value); return _RANGE_; } YY_BREAK case 3: YY_RULE_SETUP -#line 173 "libyara/re_lexer.l" +#line 176 "libyara/re_lexer.l" { // Start of a negated character class. Example: [^abcd] @@ -1219,7 +1222,7 @@ YY_RULE_SETUP YY_BREAK case 4: YY_RULE_SETUP -#line 182 "libyara/re_lexer.l" +#line 185 "libyara/re_lexer.l" { // Start of character negated class containing a ]. @@ -1234,7 +1237,7 @@ YY_RULE_SETUP YY_BREAK case 5: YY_RULE_SETUP -#line 195 "libyara/re_lexer.l" +#line 198 "libyara/re_lexer.l" { // Start of character class containing a ]. @@ -1249,7 +1252,7 @@ YY_RULE_SETUP YY_BREAK case 6: YY_RULE_SETUP -#line 208 "libyara/re_lexer.l" +#line 211 "libyara/re_lexer.l" { // Start of character class. Example: [abcd] @@ -1262,7 +1265,7 @@ YY_RULE_SETUP case 7: /* rule 7 can match eol */ YY_RULE_SETUP -#line 218 "libyara/re_lexer.l" +#line 221 "libyara/re_lexer.l" { // Any non-special character is passed as a CHAR token to the scanner. @@ -1273,63 +1276,63 @@ YY_RULE_SETUP YY_BREAK case 8: YY_RULE_SETUP -#line 227 "libyara/re_lexer.l" +#line 230 "libyara/re_lexer.l" { return _WORD_CHAR_; } YY_BREAK case 9: YY_RULE_SETUP -#line 232 "libyara/re_lexer.l" +#line 235 "libyara/re_lexer.l" { return _NON_WORD_CHAR_; } YY_BREAK case 10: YY_RULE_SETUP -#line 237 "libyara/re_lexer.l" +#line 240 "libyara/re_lexer.l" { return _SPACE_; } YY_BREAK case 11: YY_RULE_SETUP -#line 242 "libyara/re_lexer.l" +#line 245 "libyara/re_lexer.l" { return _NON_SPACE_; } YY_BREAK case 12: YY_RULE_SETUP -#line 247 "libyara/re_lexer.l" +#line 250 "libyara/re_lexer.l" { return _DIGIT_; } YY_BREAK case 13: YY_RULE_SETUP -#line 252 "libyara/re_lexer.l" +#line 255 "libyara/re_lexer.l" { return _NON_DIGIT_; } YY_BREAK case 14: YY_RULE_SETUP -#line 257 "libyara/re_lexer.l" +#line 260 "libyara/re_lexer.l" { return _WORD_BOUNDARY_; } YY_BREAK case 15: YY_RULE_SETUP -#line 261 "libyara/re_lexer.l" +#line 264 "libyara/re_lexer.l" { return _NON_WORD_BOUNDARY_; } YY_BREAK case 16: YY_RULE_SETUP -#line 266 "libyara/re_lexer.l" +#line 269 "libyara/re_lexer.l" { yyerror(yyscanner, lex_env, "backreferences are not allowed"); @@ -1338,7 +1341,7 @@ YY_RULE_SETUP YY_BREAK case 17: YY_RULE_SETUP -#line 273 "libyara/re_lexer.l" +#line 276 "libyara/re_lexer.l" { uint8_t c; @@ -1365,7 +1368,7 @@ YY_RULE_SETUP YY_BREAK case 18: YY_RULE_SETUP -#line 298 "libyara/re_lexer.l" +#line 301 "libyara/re_lexer.l" { // End of character class. @@ -1381,7 +1384,7 @@ YY_RULE_SETUP case 19: /* rule 19 can match eol */ YY_RULE_SETUP -#line 312 "libyara/re_lexer.l" +#line 315 "libyara/re_lexer.l" { // A range inside a character class. The regexp is... @@ -1446,7 +1449,7 @@ YY_RULE_SETUP YY_BREAK case 20: YY_RULE_SETUP -#line 375 "libyara/re_lexer.l" +#line 378 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) @@ -1455,7 +1458,7 @@ YY_RULE_SETUP YY_BREAK case 21: YY_RULE_SETUP -#line 382 "libyara/re_lexer.l" +#line 385 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) @@ -1464,7 +1467,7 @@ YY_RULE_SETUP YY_BREAK case 22: YY_RULE_SETUP -#line 389 "libyara/re_lexer.l" +#line 392 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) @@ -1473,7 +1476,7 @@ YY_RULE_SETUP YY_BREAK case 23: YY_RULE_SETUP -#line 396 "libyara/re_lexer.l" +#line 399 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) @@ -1482,7 +1485,7 @@ YY_RULE_SETUP YY_BREAK case 24: YY_RULE_SETUP -#line 403 "libyara/re_lexer.l" +#line 406 "libyara/re_lexer.l" { for (char c = '0'; c <= '9'; c++) @@ -1491,7 +1494,7 @@ YY_RULE_SETUP YY_BREAK case 25: YY_RULE_SETUP -#line 410 "libyara/re_lexer.l" +#line 413 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) @@ -1511,7 +1514,7 @@ YY_RULE_SETUP YY_BREAK case 26: YY_RULE_SETUP -#line 428 "libyara/re_lexer.l" +#line 431 "libyara/re_lexer.l" { uint8_t c; @@ -1536,7 +1539,7 @@ YY_RULE_SETUP YY_BREAK case 27: YY_RULE_SETUP -#line 451 "libyara/re_lexer.l" +#line 454 "libyara/re_lexer.l" { if (yytext[0] >= 32 && yytext[0] < 127) @@ -1554,7 +1557,7 @@ YY_RULE_SETUP } YY_BREAK case YY_STATE_EOF(char_class): -#line 468 "libyara/re_lexer.l" +#line 471 "libyara/re_lexer.l" { // End of regexp reached while scanning a character class. @@ -1565,7 +1568,7 @@ case YY_STATE_EOF(char_class): YY_BREAK case 28: YY_RULE_SETUP -#line 477 "libyara/re_lexer.l" +#line 480 "libyara/re_lexer.l" { if (yytext[0] >= 32 && yytext[0] < 127) @@ -1580,7 +1583,7 @@ YY_RULE_SETUP } YY_BREAK case YY_STATE_EOF(INITIAL): -#line 491 "libyara/re_lexer.l" +#line 494 "libyara/re_lexer.l" { yyterminate(); @@ -1588,10 +1591,10 @@ case YY_STATE_EOF(INITIAL): YY_BREAK case 29: YY_RULE_SETUP -#line 496 "libyara/re_lexer.l" +#line 499 "libyara/re_lexer.l" ECHO; YY_BREAK -#line 1594 "libyara/re_lexer.c" +#line 1597 "libyara/re_lexer.c" case YY_END_OF_BUFFER: { @@ -2740,7 +2743,7 @@ void yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 496 "libyara/re_lexer.l" +#line 499 "libyara/re_lexer.l" int escaped_char_value( diff --git a/libyara/re_lexer.l b/libyara/re_lexer.l index affe9581d4..657c45dded 100644 --- a/libyara/re_lexer.l +++ b/libyara/re_lexer.l @@ -61,6 +61,7 @@ with noyywrap then we can remove this pragma. #ifdef _WIN32 #define snprintf _snprintf +#define strtoll _strtoi64 #endif // Bitmap with 1 bit for each of the 256 characters in the ASCII table. The bit @@ -117,8 +118,13 @@ hex_digit [0-9a-fA-F] // Examples: {3,8} {3, 8}, {3 ,8} {3 , 8} {0,5} {,5} {7,} - int hi_bound; - int lo_bound = atoi(yytext + 1); + // strtoll is used instead of atoi because atoi has undefined behaviour for + // numbers that don't fit in an int. Numbers too large for a long long are + // clamped to LLONG_MAX by strtoll, which is still caught by the RE_MAX_RANGE + // check below. + + long long hi_bound; + long long lo_bound = strtoll(yytext + 1, NULL, 10); char* comma = strchr(yytext, ','); char* hi_bound_ptr = comma + 1; @@ -129,7 +135,7 @@ hex_digit [0-9a-fA-F] if (*hi_bound_ptr == '}') hi_bound = RE_MAX_RANGE; else - hi_bound = atoi(hi_bound_ptr); + hi_bound = strtoll(hi_bound_ptr, NULL, 10); if (hi_bound > RE_MAX_RANGE) { @@ -137,13 +143,13 @@ hex_digit [0-9a-fA-F] yyterminate(); } - if (hi_bound < lo_bound || hi_bound < 0 || lo_bound < 0) + if (hi_bound < lo_bound) { yyerror(yyscanner, lex_env, "bad repeat interval"); yyterminate(); } - yylval->range = (hi_bound << 16) | lo_bound; + yylval->range = (uint32_t) ((hi_bound << 16) | lo_bound); return _RANGE_; } @@ -153,18 +159,15 @@ hex_digit [0-9a-fA-F] // Example: {10} - int value = atoi(yytext + 1); - - // atoi can return a negative value if the input string represents a number - // too large to fit in an integer. + long long value = strtoll(yytext + 1, NULL, 10); - if (value > RE_MAX_RANGE || value < 0) + if (value > RE_MAX_RANGE) { yyerror(yyscanner, lex_env, "repeat interval too large"); yyterminate(); } - yylval->range = (value << 16) | value; + yylval->range = (uint32_t) ((value << 16) | value); return _RANGE_; } diff --git a/tests/test-rules.c b/tests/test-rules.c index 8b80f2f794..3d7158c423 100644 --- a/tests/test-rules.c +++ b/tests/test-rules.c @@ -1703,6 +1703,20 @@ static void test_hex_strings() condition: $a ", ERROR_INVALID_HEX_STRING); + // Jump lengths that don't fit in an int must be rejected. 4294967297 used to + // wrap around to 1, so this compiled as { 61 [0-1] 62 }. + assert_error( + "rule test { \ + strings: $a = { 61 [0-4294967297] 62 } \ + condition: $a }", + ERROR_INVALID_HEX_STRING); + + assert_error( + "rule test { \ + strings: $a = { 61 [0-2147483648] 62 } \ + condition: $a }", + ERROR_INVALID_HEX_STRING); + /* TODO: tests.py:551 ff. */ YR_DEBUG_FPRINTF(1, stderr, "} // %s()\n", __FUNCTION__); @@ -2767,6 +2781,12 @@ void test_re() // Test for integer overflow in repeat interval assert_regexp_syntax_error("a{2977952116}"); + // Values that wrap around to a small positive number when truncated to an + // int must be rejected too, not silently turned into a{0} and b{1,1}. + assert_regexp_syntax_error("a{4294967296}"); + assert_regexp_syntax_error("b{1,4294967297}"); + assert_regexp_syntax_error("c{99999999999999999999}"); + assert_error( "rule test { strings: $a = /a\\/ condition: $a }", ERROR_SYNTAX_ERROR);