Revision: 876
http://www.exim.org/viewvc/pcre2?view=rev&revision=876
Author: ph10
Date: 2017-10-29 16:58:38 +0000 (Sun, 29 Oct 2017)
Log Message:
-----------
Fix oss-fuzz bugs 3852 and 3891 (same bug); mis-closing external captures by
*ACCEPT inside assertions.
Modified Paths:
--------------
code/trunk/ChangeLog
code/trunk/src/pcre2_compile.c
code/trunk/src/pcre2_internal.h
code/trunk/src/pcre2_intmodedep.h
code/trunk/testdata/testinput1
code/trunk/testdata/testoutput1
Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog 2017-10-23 16:57:22 UTC (rev 875)
+++ code/trunk/ChangeLog 2017-10-29 16:58:38 UTC (rev 876)
@@ -39,7 +39,13 @@
path names to 512 characters. There is now a check on the absolute length of
full path file names, which may be up to 2047 characters long.
+12. When an assertion contained (*ACCEPT) it caused all open capturing groups
+to be closed (as for a non-assertion ACCEPT), which was wrong and could lead to
+misbehaviour for subsequent references to groups that started outside the
+recursion. ACCEPT in an assertion now closes only those groups that were
+started within that assertion. Fixes oss-fuzz issues 3852 and 3891.
+
Version 10.30 14-August-2017
----------------------------
Modified: code/trunk/src/pcre2_compile.c
===================================================================
--- code/trunk/src/pcre2_compile.c 2017-10-23 16:57:22 UTC (rev 875)
+++ code/trunk/src/pcre2_compile.c 2017-10-29 16:58:38 UTC (rev 876)
@@ -2194,7 +2194,7 @@
{
uint32_t *previous_callout = *pcalloutptr;
-if (previous_callout != NULL) previous_callout[2] = (uint32_t)(ptr -
+if (previous_callout != NULL) previous_callout[2] = (uint32_t)(ptr -
cb->start_pattern - (PCRE2_SIZE)previous_callout[1]);
if (!auto_callout) previous_callout = NULL; else
@@ -5599,14 +5599,17 @@
/* ===================================================================*/
/* Deal with (*VERB)s. */
- /* Check for open captures before ACCEPT and convert it to ASSERT_ACCEPT if
- in an assertion. In the first pass, just accumulate the length required;
+ /* Check for open captures before ACCEPT and close those that are within
+ the same assertion level, also converting ACCEPT to ASSERT_ACCEPT in an
+ assertion. In the first pass, just accumulate the length required;
otherwise hitting (*ACCEPT) inside many nested parentheses can cause
workspace overflow. Do not set firstcu after *ACCEPT. */
case META_ACCEPT:
cb->had_accept = TRUE;
- for (oc = cb->open_caps; oc != NULL; oc = oc->next)
+ for (oc = cb->open_caps;
+ oc != NULL && oc->assert_depth >= cb->assert_depth;
+ oc = oc->next)
{
if (lengthptr != NULL)
{
@@ -7483,6 +7486,7 @@
capitem.number = capnumber;
capitem.next = cb->open_caps;
capitem.flag = FALSE;
+ capitem.assert_depth = cb->assert_depth;
cb->open_caps = &capitem;
}
Modified: code/trunk/src/pcre2_internal.h
===================================================================
--- code/trunk/src/pcre2_internal.h 2017-10-23 16:57:22 UTC (rev 875)
+++ code/trunk/src/pcre2_internal.h 2017-10-29 16:58:38 UTC (rev 876)
@@ -1770,6 +1770,7 @@
struct open_capitem *next; /* Chain link */
uint16_t number; /* Capture number */
uint16_t flag; /* Set TRUE if recursive back ref */
+ uint16_t assert_depth; /* Assertion depth when opened */
} open_capitem;
/* Layout of the UCP type table that translates property names into types and
Modified: code/trunk/src/pcre2_intmodedep.h
===================================================================
--- code/trunk/src/pcre2_intmodedep.h 2017-10-23 16:57:22 UTC (rev 875)
+++ code/trunk/src/pcre2_intmodedep.h 2017-10-29 16:58:38 UTC (rev 876)
@@ -723,6 +723,8 @@
PCRE2_SIZE erroroffset; /* Offset of error in pattern */
uint16_t names_found; /* Number of entries so far */
uint16_t name_entry_size; /* Size of each entry */
+ uint16_t parens_depth; /* Depth of nested parentheses */
+ uint16_t assert_depth; /* Depth of nested assertions */
open_capitem *open_caps; /* Chain of open capture items */
named_group *named_groups; /* Points to vector in pre-compile */
uint32_t named_group_list_size; /* Number of entries in the list */
@@ -741,8 +743,6 @@
uint32_t class_range_end; /* Overall class range end */
PCRE2_UCHAR nl[4]; /* Newline string when fixed length */
int max_lookbehind; /* Maximum lookbehind (characters) */
- int parens_depth; /* Depth of nested parentheses */
- int assert_depth; /* Depth of nested assertions */
int req_varyopt; /* "After variable item" flag for reqbyte */
BOOL had_accept; /* (*ACCEPT) encountered */
BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */
Modified: code/trunk/testdata/testinput1
===================================================================
--- code/trunk/testdata/testinput1 2017-10-23 16:57:22 UTC (rev 875)
+++ code/trunk/testdata/testinput1 2017-10-29 16:58:38 UTC (rev 876)
@@ -6149,4 +6149,14 @@
/[[:digit:]-]+/
12-24
+/((?<=((*ACCEPT)) )\1?\b) /
+\= Expect no match
+ ((?<=((*ACCEPT)) )\\1?\\b)\x20
+
+/((?<=((*ACCEPT))X)\1?Y)\1/
+ XYYZ
+
+/((?<=((*ACCEPT))X)\1?Y(*ACCEPT))\1/
+ XYYZ
+
# End of testinput1
Modified: code/trunk/testdata/testoutput1
===================================================================
--- code/trunk/testdata/testoutput1 2017-10-23 16:57:22 UTC (rev 875)
+++ code/trunk/testdata/testoutput1 2017-10-29 16:58:38 UTC (rev 876)
@@ -9741,4 +9741,21 @@
12-24
0: 12-24
+/((?<=((*ACCEPT)) )\1?\b) /
+\= Expect no match
+ ((?<=((*ACCEPT)) )\\1?\\b)\x20
+No match
+
+/((?<=((*ACCEPT))X)\1?Y)\1/
+ XYYZ
+ 0: YY
+ 1: Y
+ 2:
+
+/((?<=((*ACCEPT))X)\1?Y(*ACCEPT))\1/
+ XYYZ
+ 0: Y
+ 1: Y
+ 2:
+
# End of testinput1