diff options
author | ph10 <ph10@2f5784b3-3f2a-0410-8824-cb99058d5e15> | 2015-04-01 15:43:53 +0000 |
---|---|---|
committer | ph10 <ph10@2f5784b3-3f2a-0410-8824-cb99058d5e15> | 2015-04-01 15:43:53 +0000 |
commit | 256d94987eecd7eb87b37e1c981a4e753ed8ab7a (patch) | |
tree | d6ff6ddcb018b6b92bc4b8e4b337a50d5bb21bdc | |
parent | 14ce0b0c24bfb4dff4bcb602057014a487a19eef (diff) | |
download | pcre-256d94987eecd7eb87b37e1c981a4e753ed8ab7a.tar.gz |
Fix stack overflow instead of diagnostic for mutual recursion inside a
lookbehind assertion.
git-svn-id: svn://vcs.exim.org/pcre/code/trunk@1542 2f5784b3-3f2a-0410-8824-cb99058d5e15
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | pcre_compile.c | 38 | ||||
-rw-r--r-- | testdata/testinput2 | 2 | ||||
-rw-r--r-- | testdata/testoutput2 | 3 |
4 files changed, 35 insertions, 12 deletions
@@ -142,6 +142,10 @@ Version 8.37 xx-xxx-2015 incorrectly compiled and could trigger buffer overflow. This bug was discovered by the LLVM fuzzer. +35. A mutual recursion within a lookbehind assertion such as (?<=((?2))((?1))) + caused a stack overflow instead of the diagnosis of a non-fixed length + lookbehind assertion. This bug was discovered by the LLVM fuzzer. + Version 8.36 26-September-2014 ------------------------------ diff --git a/pcre_compile.c b/pcre_compile.c index ce65777..6510835 100644 --- a/pcre_compile.c +++ b/pcre_compile.c @@ -866,6 +866,14 @@ static const pcre_uint8 opcode_possessify[] = { }; +/* Structure for mutual recursion detection. */ + +typedef struct recurse_check { + struct recurse_check *prev; + const pcre_uchar *group; +} recurse_check; + + /************************************************* * Find an error text * @@ -1704,6 +1712,7 @@ Arguments: utf TRUE in UTF-8 / UTF-16 / UTF-32 mode atend TRUE if called when the pattern is complete cd the "compile data" structure + recurses chain of recurse_check to catch mutual recursion Returns: the fixed length, or -1 if there is no fixed length, @@ -1713,10 +1722,11 @@ Returns: the fixed length, */ static int -find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd) +find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd, + recurse_check *recurses) { int length = -1; - +recurse_check this_recurse; register int branchlength = 0; register pcre_uchar *cc = code + 1 + LINK_SIZE; @@ -1741,7 +1751,8 @@ for (;;) case OP_ONCE: case OP_ONCE_NC: case OP_COND: - d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd); + d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd, + recurses); if (d < 0) return d; branchlength += d; do cc += GET(cc, 1); while (*cc == OP_ALT); @@ -1775,7 +1786,15 @@ for (;;) cs = ce = (pcre_uchar *)cd->start_code + GET(cc, 1); /* Start subpattern */ do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */ if (cc > cs && cc < ce) return -1; /* Recursion */ - d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd); + else /* Check for mutual recursion */ + { + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; + if (r != NULL) return -1; /* Mutual recursion */ + } + this_recurse.prev = recurses; + this_recurse.group = cs; + d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd, &this_recurse); if (d < 0) return d; branchlength += d; cc += 1 + LINK_SIZE; @@ -2362,11 +2381,6 @@ Arguments: Returns: TRUE if what is matched could be empty */ -typedef struct recurse_check { - struct recurse_check *prev; - const pcre_uchar *group; -} recurse_check; - static BOOL could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode, BOOL utf, compile_data *cd, recurse_check *recurses) @@ -5924,7 +5938,7 @@ for (;; ptr++) { register int i; int len = (int)(code - previous); - size_t base_hwm_offset = save_hwm_offset; + size_t base_hwm_offset = save_hwm_offset; pcre_uchar *bralink = NULL; pcre_uchar *brazeroptr = NULL; @@ -8291,7 +8305,7 @@ for (;;) int fixed_length; *code = OP_END; fixed_length = find_fixedlength(last_branch, (options & PCRE_UTF8) != 0, - FALSE, cd); + FALSE, cd, NULL); DPRINTF(("fixed length = %d\n", fixed_length)); if (fixed_length == -3) { @@ -9394,7 +9408,7 @@ if (cd->check_lookbehind) int end_op = *be; *be = OP_END; fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE, - cd); + cd, NULL); *be = end_op; DPRINTF(("fixed length = %d\n", fixed_length)); if (fixed_length < 0) diff --git a/testdata/testinput2 b/testdata/testinput2 index 8ba0b7b..c31b6c9 100644 --- a/testdata/testinput2 +++ b/testdata/testinput2 @@ -4142,4 +4142,6 @@ backtracking verbs. --/ "X((?2)()*+){2}"BZ +"(?<=((?2))((?1)))" + /-- End of testinput2 --/ diff --git a/testdata/testoutput2 b/testdata/testoutput2 index 5d93d4c..4b8eec2 100644 --- a/testdata/testoutput2 +++ b/testdata/testoutput2 @@ -14390,4 +14390,7 @@ Failed: assertion expected after (?( at offset 3 End ------------------------------------------------------------------ +"(?<=((?2))((?1)))" +Failed: lookbehind assertion is not fixed length at offset 17 + /-- End of testinput2 --/ |