From a91b8a1eece43f8e32af8988d6d392c335df019f Mon Sep 17 00:00:00 2001 From: "Victor M. Alvarez" Date: Mon, 25 Apr 2022 12:18:54 +0200 Subject: [PATCH] Fix issue #1690 (#1692) Regular expressions with a character class followed by a dash (-) failed with "bad character range". For example, /[0-9]-2/ was not accepted as a valid regexp. --- libyara/re_lexer.c | 135 +++++++++++++++++++++------------------------ libyara/re_lexer.l | 31 ++++------- tests/test-rules.c | 23 ++++---- 3 files changed, 87 insertions(+), 102 deletions(-) diff --git a/libyara/re_lexer.c b/libyara/re_lexer.c index 6e2a1f2b..a7afef9a 100644 --- a/libyara/re_lexer.c +++ b/libyara/re_lexer.c @@ -593,9 +593,9 @@ static const flex_int16_t yy_accept[45] = { 0, 0, 0, 0, 0, 30, 7, 7, 28, 6, 17, 7, 27, 29, 26, 18, 5, 3, 16, 15, 13, - 11, 9, 14, 12, 10, 8, 0, 0, 0, 0, - 25, 23, 21, 24, 22, 20, 0, 4, 0, 1, - 2, 19, 0, 0 + 11, 9, 14, 12, 10, 8, 0, 0, 0, 25, + 23, 21, 24, 22, 20, 0, 4, 0, 1, 2, + 19, 0, 0, 0 } ; static const YY_CHAR yy_ec[256] = @@ -632,61 +632,57 @@ static const YY_CHAR yy_ec[256] = static const YY_CHAR yy_meta[23] = { 0, - 1, 2, 1, 1, 3, 4, 4, 4, 4, 1, - 1, 1, 1, 5, 1, 4, 4, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, + 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1 } ; -static const flex_int16_t yy_base[51] = +static const flex_int16_t yy_base[50] = { 0, - 0, 20, 3, 5, 50, 89, 89, 89, 10, 36, - 0, 44, 43, 47, 38, 89, 26, 33, 89, 89, - 89, 89, 89, 89, 89, 89, 4, 5, 0, 33, - 32, 31, 29, 26, 24, 23, 15, 89, 8, 89, - 89, 89, 0, 89, 67, 72, 77, 82, 84, 4 + 0, 20, 3, 5, 37, 76, 76, 76, 10, 36, + 0, 31, 29, 47, 76, 76, 17, 23, 76, 76, + 76, 76, 76, 76, 76, 76, 4, 5, 0, 76, + 76, 76, 76, 76, 76, 0, 76, 8, 76, 76, + 76, 0, 23, 76, 67, 70, 73, 18, 6 } ; -static const flex_int16_t yy_def[51] = +static const flex_int16_t yy_def[50] = { 0, 45, 45, 46, 46, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 47, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 48, 44, - 44, 44, 44, 44, 44, 44, 49, 44, 44, 44, - 44, 44, 50, 0, 44, 44, 44, 44, 44, 44 + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 47, 44, + 44, 44, 44, 44, 44, 48, 44, 44, 44, 44, + 44, 49, 44, 0, 44, 44, 44, 44, 44 } ; -static const flex_int16_t yy_nxt[112] = +static const flex_int16_t yy_nxt[99] = { 0, - 44, 7, 8, 27, 13, 28, 13, 30, 27, 39, - 28, 9, 10, 39, 8, 14, 15, 14, 15, 29, - 11, 7, 8, 16, 17, 40, 41, 29, 29, 40, - 29, 9, 10, 29, 8, 29, 29, 29, 18, 38, - 11, 18, 29, 19, 20, 21, 22, 29, 29, 44, - 44, 23, 24, 25, 26, 31, 32, 33, 44, 44, - 44, 44, 44, 34, 35, 36, 37, 6, 6, 6, - 6, 6, 12, 12, 12, 12, 12, 30, 44, 30, - 30, 30, 42, 42, 42, 42, 43, 43, 5, 44, + 44, 7, 8, 27, 13, 28, 13, 43, 27, 38, + 28, 9, 10, 38, 8, 14, 15, 14, 15, 42, + 11, 7, 8, 16, 17, 39, 40, 29, 18, 39, + 37, 9, 10, 29, 8, 29, 44, 44, 44, 44, + 11, 18, 44, 19, 20, 21, 22, 44, 44, 44, + 44, 23, 24, 25, 26, 30, 31, 32, 44, 44, + 44, 44, 44, 33, 34, 35, 36, 6, 6, 6, + 12, 12, 12, 41, 41, 5, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44 - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44 } ; -static const flex_int16_t yy_chk[112] = +static const flex_int16_t yy_chk[99] = { 0, - 0, 1, 1, 11, 3, 11, 4, 50, 28, 27, - 28, 1, 1, 39, 1, 3, 3, 4, 4, 37, - 1, 2, 2, 9, 9, 27, 28, 36, 35, 39, - 34, 2, 2, 33, 2, 32, 31, 30, 18, 17, - 2, 10, 15, 10, 10, 10, 10, 13, 12, 5, + 0, 1, 1, 11, 3, 11, 4, 49, 28, 27, + 28, 1, 1, 38, 1, 3, 3, 4, 4, 48, + 1, 2, 2, 9, 9, 27, 28, 43, 18, 38, + 17, 2, 2, 13, 2, 12, 5, 0, 0, 0, + 2, 10, 0, 10, 10, 10, 10, 0, 0, 0, 0, 10, 10, 10, 10, 14, 14, 14, 0, 0, 0, 0, 0, 14, 14, 14, 14, 45, 45, 45, - 45, 45, 46, 46, 46, 46, 46, 47, 0, 47, - 47, 47, 48, 48, 48, 48, 49, 49, 44, 44, + 46, 46, 46, 47, 47, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44 - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44 } ; /* Table of booleans, true if rule could match eol. */ @@ -791,10 +787,10 @@ int read_escaped_char( yyscan_t yyscanner, uint8_t* escaped_char); -#line 794 "re_lexer.c" +#line 790 "re_lexer.c" #define YY_NO_UNISTD_H 1 -#line 797 "re_lexer.c" +#line 793 "re_lexer.c" #define INITIAL 0 #define char_class 1 @@ -1070,7 +1066,7 @@ YY_DECL #line 111 "re_lexer.l" -#line 1073 "re_lexer.c" +#line 1069 "re_lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1378,6 +1374,11 @@ YY_RULE_SETUP { // A range inside a character class. + // + // Matches an hex digit (i.e: \x01), or any character that is + // not ] or \, followed by -, followed by any character that is + // not ] + // // [abc0-9] // ^- matching here @@ -1422,67 +1423,55 @@ YY_RULE_SETUP YY_BREAK case 20: YY_RULE_SETUP -#line 357 "re_lexer.l" +#line 362 "re_lexer.l" { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= word_chars[i]; } YY_BREAK case 21: YY_RULE_SETUP -#line 366 "re_lexer.l" +#line 369 "re_lexer.l" { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= ~word_chars[i]; } YY_BREAK case 22: YY_RULE_SETUP -#line 375 "re_lexer.l" +#line 376 "re_lexer.l" { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= space_chars[i]; } YY_BREAK case 23: YY_RULE_SETUP -#line 384 "re_lexer.l" +#line 383 "re_lexer.l" { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= ~space_chars[i]; } YY_BREAK case 24: YY_RULE_SETUP -#line 393 "re_lexer.l" +#line 390 "re_lexer.l" { - char c; - - for (c = '0'; c <= '9'; c++) + for (char c = '0'; c <= '9'; c++) LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } YY_BREAK case 25: YY_RULE_SETUP -#line 402 "re_lexer.l" +#line 397 "re_lexer.l" { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) { // digits 0-7 are in the sixth byte of the vector, let that byte alone if (i == 6) @@ -1499,7 +1488,7 @@ YY_RULE_SETUP YY_BREAK case 26: YY_RULE_SETUP -#line 422 "re_lexer.l" +#line 415 "re_lexer.l" { uint8_t c; @@ -1517,7 +1506,7 @@ YY_RULE_SETUP YY_BREAK case 27: YY_RULE_SETUP -#line 438 "re_lexer.l" +#line 431 "re_lexer.l" { if (yytext[0] >= 32 && yytext[0] < 127) @@ -1535,7 +1524,7 @@ YY_RULE_SETUP } YY_BREAK case YY_STATE_EOF(char_class): -#line 455 "re_lexer.l" +#line 448 "re_lexer.l" { // End of regexp reached while scanning a character class. @@ -1546,7 +1535,7 @@ case YY_STATE_EOF(char_class): YY_BREAK case 28: YY_RULE_SETUP -#line 464 "re_lexer.l" +#line 457 "re_lexer.l" { if (yytext[0] >= 32 && yytext[0] < 127) @@ -1561,7 +1550,7 @@ YY_RULE_SETUP } YY_BREAK case YY_STATE_EOF(INITIAL): -#line 478 "re_lexer.l" +#line 471 "re_lexer.l" { yyterminate(); @@ -1569,10 +1558,10 @@ case YY_STATE_EOF(INITIAL): YY_BREAK case 29: YY_RULE_SETUP -#line 483 "re_lexer.l" +#line 476 "re_lexer.l" ECHO; YY_BREAK -#line 1575 "re_lexer.c" +#line 1564 "re_lexer.c" case YY_END_OF_BUFFER: { @@ -2721,7 +2710,7 @@ void yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 483 "re_lexer.l" +#line 476 "re_lexer.l" int escaped_char_value( diff --git a/libyara/re_lexer.l b/libyara/re_lexer.l index d333a6d9..42406ec0 100644 --- a/libyara/re_lexer.l +++ b/libyara/re_lexer.l @@ -308,9 +308,14 @@ hex_digit [0-9a-fA-F] -(\\x{hex_digit}{2}|\\.|[^\\])\-[^]] { +(\\x{hex_digit}{2}|[^]\\])-[^]] { // A range inside a character class. + // + // Matches an hex digit (i.e: \x01), or any character that is + // not ] or \, followed by -, followed by any character that is + // not ] + // // [abc0-9] // ^- matching here @@ -356,54 +361,42 @@ hex_digit [0-9a-fA-F] \\w { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= word_chars[i]; } \\W { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= ~word_chars[i]; } \\s { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= space_chars[i]; } \\S { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= ~space_chars[i]; } \\d { - char c; - - for (c = '0'; c <= '9'; c++) + for (char c = '0'; c <= '9'; c++) LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } \\D { - int i; - - for (i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) { // digits 0-7 are in the sixth byte of the vector, let that byte alone if (i == 6) diff --git a/tests/test-rules.c b/tests/test-rules.c index 719750b8..4bb6f14d 100644 --- a/tests/test-rules.c +++ b/tests/test-rules.c @@ -1303,7 +1303,7 @@ static void test_hex_strings() strings: $a = { 31 32 ~32 34 35 } \ condition: $a }", TEXT_1024_BYTES "1234567890"); - + assert_false_rule( "rule test { \ strings: $a = { 31 32 ~33 34 35 } \ @@ -1314,37 +1314,37 @@ static void test_hex_strings() "rule test { \ strings: $a = { ( 31 32 ~32 34 35 | 31 32 ~33 34 35 ) } \ condition: $a }", - TEXT_1024_BYTES "1234567890"); - + TEXT_1024_BYTES "1234567890"); + assert_true_rule( "rule test { \ strings: $a = { 31 32 ~?2 34 35 } \ condition: $a }", TEXT_1024_BYTES "1234567890"); - + assert_false_rule( "rule test { \ strings: $a = { 31 32 ~?3 34 35 } \ condition: $a }", TEXT_1024_BYTES "1234567890"); - + assert_true_rule( "rule test { \ strings: $a = { 31 32 ~4? 34 35 } \ condition: $a }", TEXT_1024_BYTES "1234567890"); - + assert_false_rule( "rule test { \ strings: $a = { 31 32 ~3? 34 35 } \ condition: $a }", TEXT_1024_BYTES "1234567890"); - + assert_true_rule( "rule test { \ strings: $a = { ( 31 32 ~3? 34 35 | 31 32 ~?2 34 35 ) } \ condition: $a }", - TEXT_1024_BYTES "1234567890"); + TEXT_1024_BYTES "1234567890"); assert_false_rule( "rule test { \ @@ -1470,12 +1470,12 @@ static void test_hex_strings() strings: $a = { 01 ~0 11 } \ condition: $a ", ERROR_INVALID_HEX_STRING); - + assert_error( "rule test { \ strings: $a = { 01 ~?? 11 } \ condition: $a ", - ERROR_INVALID_HEX_STRING); + ERROR_INVALID_HEX_STRING); /* TODO: tests.py:551 ff. */ @@ -2277,6 +2277,9 @@ void test_re() assert_true_regexp("a[\\-b]", "ab", "ab"); assert_true_regexp("a]", "a]", "a]"); assert_true_regexp("a[]]b", "a]b", "a]b"); + assert_true_regexp("[a-z]-b", "c-b-c", "c-b"); // Issue #1690 + assert_true_regexp("a[]-]b", "a]b", "a]b"); + assert_true_regexp("a[]-]b", "a-b", "a-b"); assert_true_regexp("a[\\]]b", "a]b", "a]b"); assert_true_regexp("a[^bc]d", "aed", "aed"); assert_false_regexp("a[^bc]d", "abd");