Submitted By: Ken Moffat Date: 2015-09-03 Initial Package Version: 8.37 Upstream Status: Applied Origin: Upstream, via fedora Description: Various buffer overflows, including CVE-2015-3210 and CVE-2015-5073. Some of fixes these were backported to 8.37 by fedora. Some, or all, of the issues also apply to several earlier versions of PCRE. This contains the following patches, applied in this order: pcre-8.37-Fix-buffer-overflow-for-named-recursive-back-referen.patch (fixes CVE-2015-3210) pcre-8.37-Fix-buffer-overflow-for-forward-reference-within-bac.patch (fixes CVE-2015-5073) pcre-8.37-Fix-named-forward-reference-to-duplicate-group-numbe.patch pcre-8.37-Fix-another-buffer-overflow.patch (these two are both required for this next one -) pcre-8.37-Fix-buffer-overflow-for-named-references-in-situatio.patch (prevents crashes, e.g. in pcretest or php, with a crafted regex) pcre-8.37-Hack-in-yet-other-patch-for-a-bug-in-size-computatio.patch diff -Naur pcre-8.37.orig/pcre_compile.c pcre-8.37.patched/pcre_compile.c --- pcre-8.37.orig/pcre_compile.c 2015-04-13 16:54:01.000000000 +0100 +++ pcre-8.37.patched/pcre_compile.c 2015-09-03 18:35:01.007810651 +0100 @@ -6641,6 +6641,7 @@ /* ------------------------------------------------------------ */ case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ reset_bracount = TRUE; + cd->dupgroups = TRUE; /* Record (?| encountered */ /* Fall through */ /* ------------------------------------------------------------ */ @@ -7151,7 +7152,8 @@ if (lengthptr != NULL) { named_group *ng; - + recno = 0; + if (namelen == 0) { *errorcodeptr = ERR62; @@ -7168,20 +7170,6 @@ goto FAILED; } - /* The name table does not exist in the first pass; instead we must - scan the list of names encountered so far in order to get the - number. If the name is not found, set the value to 0 for a forward - reference. */ - - ng = cd->named_groups; - for (i = 0; i < cd->names_found; i++, ng++) - { - if (namelen == ng->length && - STRNCMP_UC_UC(name, ng->name, namelen) == 0) - break; - } - recno = (i < cd->names_found)? ng->number : 0; - /* Count named back references. */ if (!is_recurse) cd->namedrefcount++; @@ -7191,6 +7179,56 @@ 16-bit data item. */ *lengthptr += IMM2_SIZE; + + /* If this is a forward reference and we are within a (?|...) group, + the reference may end up as the number of a group which we are + currently inside, that is, it could be a recursive reference. In the + real compile this will be picked up and the reference wrapped with + OP_ONCE to make it atomic, so we must space in case this occurs. */ + + /* In fact, this can happen for a non-forward reference because + another group with the same number might be created later. This + issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance + only mode, we finesse the bug by allowing more memory always. */ + + *lengthptr += 2 + 2*LINK_SIZE; + + /* It is even worse than that. The current reference may be to an + existing named group with a different number (so apparently not + recursive) but which later on is also attached to a group with the + current number. This can only happen if $(| has been previous + encountered. In that case, we allow yet more memory, just in case. + (Again, this is fixed "properly" in PCRE2. */ + + if (cd->dupgroups) *lengthptr += 4 + 4*LINK_SIZE; + + /* Otherwise, check for recursion here. The name table does not exist + in the first pass; instead we must scan the list of names encountered + so far in order to get the number. If the name is not found, leave + the value of recno as 0 for a forward reference. */ + + else + { + ng = cd->named_groups; + for (i = 0; i < cd->names_found; i++, ng++) + { + if (namelen == ng->length && + STRNCMP_UC_UC(name, ng->name, namelen) == 0) + { + open_capitem *oc; + recno = ng->number; + if (is_recurse) break; + for (oc = cd->open_caps; oc != NULL; oc = oc->next) + { + if (oc->number == recno) + { + oc->flag = TRUE; + break; + } + } + } + } + } } /* In the real compile, search the name table. We check the name @@ -7237,8 +7275,6 @@ for (i++; i < cd->names_found; i++) { if (STRCMP_UC_UC(slot + IMM2_SIZE, cslot + IMM2_SIZE) != 0) break; - - count++; cslot += cd->name_entry_size; } @@ -9164,6 +9200,7 @@ cd->name_entry_size = 0; cd->name_table = NULL; cd->dupnames = FALSE; +cd->dupgroups = FALSE; cd->namedrefcount = 0; cd->start_code = cworkspace; cd->hwm = cworkspace; @@ -9198,7 +9235,7 @@ DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, (int)(cd->hwm - cworkspace))); - + if (length > MAX_PATTERN_SIZE) { errorcode = ERR20; @@ -9366,7 +9403,7 @@ "const" attribute if the cast (pcre_uchar *)codestart is used directly in the function call. */ -if ((options & PCRE_NO_AUTO_POSSESS) == 0) +if (errorcode == 0 && (options & PCRE_NO_AUTO_POSSESS) == 0) { pcre_uchar *temp = (pcre_uchar *)codestart; auto_possessify(temp, utf, cd); @@ -9380,7 +9417,7 @@ exceptional ones forgo this. We scan the pattern to check that they are fixed length, and set their lengths. */ -if (cd->check_lookbehind) +if (errorcode == 0 && cd->check_lookbehind) { pcre_uchar *cc = (pcre_uchar *)codestart; @@ -9593,4 +9630,3 @@ } /* End of pcre_compile.c */ - diff -Naur pcre-8.37.orig/pcre_internal.h pcre-8.37.patched/pcre_internal.h --- pcre-8.37.orig/pcre_internal.h 2015-04-14 18:06:44.000000000 +0100 +++ pcre-8.37.patched/pcre_internal.h 2015-09-03 18:34:38.903811043 +0100 @@ -2446,6 +2446,7 @@ BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ BOOL check_lookbehind; /* Lookbehinds need later checking */ BOOL dupnames; /* Duplicate names exist */ + BOOL dupgroups; /* Duplicate groups exist: (?| found */ BOOL iscondassert; /* Next assert is a condition */ int nltype; /* Newline type */ int nllen; /* Newline string length */ diff -Naur pcre-8.37.orig/testdata/testinput1 pcre-8.37.patched/testdata/testinput1 --- pcre-8.37.orig/testdata/testinput1 2015-03-29 12:25:15.000000000 +0100 +++ pcre-8.37.patched/testdata/testinput1 2015-09-03 18:33:59.227811748 +0100 @@ -5730,4 +5730,7 @@ "(?1)(?#?'){8}(a)" baaaaaaaaac +"(?|(\k'Pm')|(?'Pm'))" + abcd + /-- End of testinput1 --/ diff -Naur pcre-8.37.orig/testdata/testinput2 pcre-8.37.patched/testdata/testinput2 --- pcre-8.37.orig/testdata/testinput2 2015-04-13 10:36:15.000000000 +0100 +++ pcre-8.37.patched/testdata/testinput2 2015-09-03 18:35:01.007810651 +0100 @@ -4152,4 +4152,14 @@ /((?2){73}(?2))((?1))/ +"(?J)(?'d'(?'d'\g{d}))" + +/(?=di(?<=(?1))|(?=(.))))/ + +"(?J:(?|(?'R')(\k'R')|((?'R'))))" + +/(?J:(?|(:(?|(?'R')(\k'R')|((?'R')))H'Rk'Rf)|s(?'R')))/ + +/(?J:(?|(:(?|(?'R')(\z(?|(?'R')(\k'R')|((?'R')))k'R')|((?'R')))H'Ak'Rf)|s(?'R')))/ + /-- End of testinput2 --/ diff -Naur pcre-8.37.orig/testdata/testoutput1 pcre-8.37.patched/testdata/testoutput1 --- pcre-8.37.orig/testdata/testoutput1 2015-03-29 12:25:26.000000000 +0100 +++ pcre-8.37.patched/testdata/testoutput1 2015-09-03 18:33:59.227811748 +0100 @@ -9429,4 +9429,9 @@ 0: aaaaaaaaa 1: a +"(?|(\k'Pm')|(?'Pm'))" + abcd + 0: + 1: + /-- End of testinput1 --/ diff -Naur pcre-8.37.orig/testdata/testoutput11-16 pcre-8.37.patched/testdata/testoutput11-16 --- pcre-8.37.orig/testdata/testoutput11-16 2015-03-02 17:09:21.000000000 +0000 +++ pcre-8.37.patched/testdata/testoutput11-16 2015-09-03 18:34:19.207811393 +0100 @@ -231,7 +231,7 @@ ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/BM -Memory allocation (code space): 61 +Memory allocation (code space): 77 ------------------------------------------------------------------ 0 24 Bra 2 5 CBra 1 diff -Naur pcre-8.37.orig/testdata/testoutput11-32 pcre-8.37.patched/testdata/testoutput11-32 --- pcre-8.37.orig/testdata/testoutput11-32 2015-03-02 17:09:30.000000000 +0000 +++ pcre-8.37.patched/testdata/testoutput11-32 2015-09-03 18:34:19.207811393 +0100 @@ -231,7 +231,7 @@ ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/BM -Memory allocation (code space): 125 +Memory allocation (code space): 157 ------------------------------------------------------------------ 0 24 Bra 2 5 CBra 1 diff -Naur pcre-8.37.orig/testdata/testoutput11-8 pcre-8.37.patched/testdata/testoutput11-8 --- pcre-8.37.orig/testdata/testoutput11-8 2015-03-02 17:09:13.000000000 +0000 +++ pcre-8.37.patched/testdata/testoutput11-8 2015-09-03 18:34:19.207811393 +0100 @@ -231,7 +231,7 @@ ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/BM -Memory allocation (code space): 38 +Memory allocation (code space): 50 ------------------------------------------------------------------ 0 30 Bra 3 7 CBra 1 diff -Naur pcre-8.37.orig/testdata/testoutput2 pcre-8.37.patched/testdata/testoutput2 --- pcre-8.37.orig/testdata/testoutput2 2015-04-13 10:36:27.000000000 +0100 +++ pcre-8.37.patched/testdata/testoutput2 2015-09-03 18:35:01.007810651 +0100 @@ -14423,4 +14423,15 @@ /((?2){73}(?2))((?1))/ +"(?J)(?'d'(?'d'\g{d}))" + +/(?=di(?<=(?1))|(?=(.))))/ +Failed: unmatched parentheses at offset 23 + +"(?J:(?|(?'R')(\k'R')|((?'R'))))" + +/(?J:(?|(:(?|(?'R')(\k'R')|((?'R')))H'Rk'Rf)|s(?'R')))/ + +/(?J:(?|(:(?|(?'R')(\z(?|(?'R')(\k'R')|((?'R')))k'R')|((?'R')))H'Ak'Rf)|s(?'R')))/ + /-- End of testinput2 --/