components/pcre/patches/04-CVE-2015-3210.patch
author Bill Rushmore <bill.rushmore@oracle.com>
Fri, 07 Aug 2015 13:43:38 -0700
changeset 4746 8e237ffd0a48
parent 4549 cef88d7826a6
permissions -rw-r--r--
20995635 Perl TK needs to be upgraded to work with Perl 5.20 20994112 Perl XML::Parser needs to work with Perl 5.20 20989929 Perl net-ssleay needs to be fixed so it builds with Perl 5.20 20989909 Perl libxml needs to be fixed so it builds with Perl 5.20 20989894 Perl DBI - needs to be fixed so it builds with Perl 5.20 20989877 AUTHEN-PAM needs to be fixed so it builds with Perl 5.20 21195142 OpenSCAP's Makefile needs to be updated to work with Perl 5.20 21216887 Dependencies and references to Perl 5.16 need to be replaced with Perl 5.20

Patch from upstream:
http://vcs.pcre.org/pcre?view=revision&revision=1558
to fix CVE-2015-3210 in this upstream bug:
https://bugs.exim.org/show_bug.cgi?id=1636

Must also include the other commits to pcre_compile.c since 8.37;
otherwise, a test case fails.
http://vcs.pcre.org/pcre?view=revision&revision=1555
http://vcs.pcre.org/pcre?view=revision&revision=1556
http://vcs.pcre.org/pcre?view=revision&revision=1557

This patch may be removed when pcre is upgraded from version 8.37

--- pcre-8.37-orig/ChangeLog	2015-04-28 04:37:57.000000000 -0700
+++ pcre-8.37/ChangeLog	2015-06-18 14:04:00.765607692 -0700
@@ -1,6 +1,29 @@
 ChangeLog for PCRE
 ------------------
 
+Changes since Version 8.37
+------------------------
+
+1.  If a group that contained a recursive back reference also contained a
+    forward reference subroutine call followed by a non-forward-reference
+    subroutine call, for example /.((?2)(?R)\1)()/, pcre2_compile() failed to
+    compile correct code, leading to undefined behaviour or an internally
+    detected error. This bug was discovered by the LLVM fuzzer.
+    
+2.  Quantification of certain items (e.g. atomic back references) could cause
+    incorrect code to be compiled when recursive forward references were
+    involved. For example, in this pattern: /(?1)()((((((\1++))\x85)+)|))/.
+    This bug was discovered by the LLVM fuzzer.
+    
+3.  A repeated conditional group whose condition was a reference by name caused
+    a buffer overflow if there was more than one group with the given name.
+    This bug was discovered by the LLVM fuzzer.
+    
+4.  A recursive back reference by name within a group that had the same name as
+    another group caused a buffer overflow. For example:
+    /(?J)(?'d'(?'d'\g{d}))/. This bug was discovered by the LLVM fuzzer.
+ 
+
 Version 8.37 28-April-2015
 --------------------------
 
--- pcre-8.37-orig/pcre_compile.c	2015-04-13 08:54:01.000000000 -0700
+++ pcre-8.37/pcre_compile.c	2015-06-18 13:50:47.045221926 -0700
@@ -3985,11 +3985,12 @@ have their offsets adjusted. That one of
 is called, the partially compiled regex must be temporarily terminated with
 OP_END.
 
-This function has been extended with the possibility of forward references for
-recursions and subroutine calls. It must also check the list of such references
-for the group we are dealing with. If it finds that one of the recursions in
-the current group is on this list, it adjusts the offset in the list, not the
-value in the reference (which is a group number).
+This function has been extended to cope with forward references for recursions
+and subroutine calls. It must check the list of such references for the
+group we are dealing with. If it finds that one of the recursions in the
+current group is on this list, it does not adjust the value in the reference
+(which is a group number). After the group has been scanned, all the offsets in
+the forward reference list for the group are adjusted.
 
 Arguments:
   group      points to the start of the group
@@ -4005,29 +4006,21 @@ static void
 adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd,
   size_t save_hwm_offset)
 {
+int offset;
+pcre_uchar *hc;
 pcre_uchar *ptr = group;
 
 while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL)
   {
-  int offset;
-  pcre_uchar *hc;
-
-  /* See if this recursion is on the forward reference list. If so, adjust the
-  reference. */
-
   for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
        hc += LINK_SIZE)
     {
     offset = (int)GET(hc, 0);
-    if (cd->start_code + offset == ptr + 1)
-      {
-      PUT(hc, 0, offset + adjust);
-      break;
-      }
+    if (cd->start_code + offset == ptr + 1) break;
     }
 
-  /* Otherwise, adjust the recursion offset if it's after the start of this
-  group. */
+  /* If we have not found this recursion on the forward reference list, adjust
+  the recursion's offset if it's after the start of this group. */
 
   if (hc >= cd->hwm)
     {
@@ -4037,6 +4030,15 @@ while ((ptr = (pcre_uchar *)find_recurse
 
   ptr += 1 + LINK_SIZE;
   }
+
+/* Now adjust all forward reference offsets for the group. */
+
+for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
+     hc += LINK_SIZE)
+  {
+  offset = (int)GET(hc, 0);
+  PUT(hc, 0, offset + adjust);
+  }
 }
 
 
@@ -4465,7 +4467,7 @@ const pcre_uchar *tempptr;
 const pcre_uchar *nestptr = NULL;
 pcre_uchar *previous = NULL;
 pcre_uchar *previous_callout = NULL;
-size_t save_hwm_offset = 0;
+size_t item_hwm_offset = 0;
 pcre_uint8 classbits[32];
 
 /* We can fish out the UTF-8 setting once and for all into a BOOL, but we
@@ -4767,6 +4769,7 @@ for (;; ptr++)
     zeroreqchar = reqchar;
     zeroreqcharflags = reqcharflags;
     previous = code;
+    item_hwm_offset = cd->hwm - cd->start_workspace;
     *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY;
     break;
 
@@ -4818,6 +4821,7 @@ for (;; ptr++)
     /* Handle a real character class. */
 
     previous = code;
+    item_hwm_offset = cd->hwm - cd->start_workspace;
 
     /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
     they are encountered at the top level, so we'll do that too. */
@@ -5930,7 +5934,7 @@ for (;; ptr++)
       {
       register int i;
       int len = (int)(code - previous);
-      size_t base_hwm_offset = save_hwm_offset;
+      size_t base_hwm_offset = item_hwm_offset;
       pcre_uchar *bralink = NULL;
       pcre_uchar *brazeroptr = NULL;
 
@@ -5985,7 +5989,7 @@ for (;; ptr++)
         if (repeat_max <= 1)    /* Covers 0, 1, and unlimited */
           {
           *code = OP_END;
-          adjust_recurse(previous, 1, utf, cd, save_hwm_offset);
+          adjust_recurse(previous, 1, utf, cd, item_hwm_offset);
           memmove(previous + 1, previous, IN_UCHARS(len));
           code++;
           if (repeat_max == 0)
@@ -6009,7 +6013,7 @@ for (;; ptr++)
           {
           int offset;
           *code = OP_END;
-          adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm_offset);
+          adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, item_hwm_offset);
           memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len));
           code += 2 + LINK_SIZE;
           *previous++ = OP_BRAZERO + repeat_type;
@@ -6267,7 +6271,7 @@ for (;; ptr++)
               {
               int nlen = (int)(code - bracode);
               *code = OP_END;
-              adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+              adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
               memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen));
               code += 1 + LINK_SIZE;
               nlen += 1 + LINK_SIZE;
@@ -6401,7 +6405,7 @@ for (;; ptr++)
         else
           {
           *code = OP_END;
-          adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+          adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
           memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
           code += 1 + LINK_SIZE;
           len += 1 + LINK_SIZE;
@@ -6450,7 +6454,7 @@ for (;; ptr++)
 
         default:
         *code = OP_END;
-        adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+        adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
         memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
         code += 1 + LINK_SIZE;
         len += 1 + LINK_SIZE;
@@ -6623,7 +6627,7 @@ for (;; ptr++)
     newoptions = options;
     skipbytes = 0;
     bravalue = OP_CBRA;
-    save_hwm_offset = cd->hwm - cd->start_workspace;
+    item_hwm_offset = cd->hwm - cd->start_workspace;
     reset_bracount = FALSE;
 
     /* Deal with the extended parentheses; all are introduced by '?', and the
@@ -6769,7 +6773,7 @@ for (;; ptr++)
             ptr++;
             }
           namelen = (int)(ptr - name);
-          if (lengthptr != NULL) *lengthptr += IMM2_SIZE;
+          if (lengthptr != NULL) skipbytes += IMM2_SIZE;
           }
 
         /* Check the terminator */
@@ -7173,14 +7177,26 @@ for (;; ptr++)
           number. If the name is not found, set the value to 0 for a forward
           reference. */
 
+          recno = 0;
           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;
+              {
+              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;
+                  }                                                         
+                }                          
+              }    
             }
-          recno = (i < cd->names_found)? ng->number : 0;
 
           /* Count named back references. */
 
@@ -7247,6 +7263,7 @@ for (;; ptr++)
             {
             if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
             previous = code;
+            item_hwm_offset = cd->hwm - cd->start_workspace;
             *code++ = ((options & PCRE_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
             PUT2INC(code, 0, index);
             PUT2INC(code, 0, count);
@@ -7360,6 +7377,7 @@ for (;; ptr++)
           HANDLE_RECURSION:
 
           previous = code;
+          item_hwm_offset = cd->hwm - cd->start_workspace;
           called = cd->start_code;
 
           /* When we are actually compiling, find the bracket that is being
@@ -7561,7 +7579,11 @@ for (;; ptr++)
       previous = NULL;
       cd->iscondassert = FALSE;
       }
-    else previous = code;
+    else 
+      {
+      previous = code;
+      item_hwm_offset = cd->hwm - cd->start_workspace;
+      }
 
     *code = bravalue;
     tempcode = code;
@@ -7809,7 +7831,7 @@ for (;; ptr++)
         const pcre_uchar *p;
         pcre_uint32 cf;
 
-        save_hwm_offset = cd->hwm - cd->start_workspace;   /* Normally this is set when '(' is read */
+        item_hwm_offset = cd->hwm - cd->start_workspace;   /* Normally this is set when '(' is read */
         terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
           CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
 
@@ -7877,6 +7899,7 @@ for (;; ptr++)
         HANDLE_REFERENCE:
         if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
         previous = code;
+        item_hwm_offset = cd->hwm - cd->start_workspace;
         *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF;
         PUT2INC(code, 0, recno);
         cd->backref_map |= (recno < 32)? (1 << recno) : 1;
@@ -7906,6 +7929,7 @@ for (;; ptr++)
         if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr))
           goto FAILED;
         previous = code;
+        item_hwm_offset = cd->hwm - cd->start_workspace;
         *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP;
         *code++ = ptype;
         *code++ = pdata;
@@ -7946,6 +7970,7 @@ for (;; ptr++)
 
           {
           previous = (escape > ESC_b && escape < ESC_Z)? code : NULL;
+          item_hwm_offset = cd->hwm - cd->start_workspace;
           *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape;
           }
         }
@@ -7989,6 +8014,7 @@ for (;; ptr++)
 
     ONE_CHAR:
     previous = code;
+    item_hwm_offset = cd->hwm - cd->start_workspace;
 
     /* For caseless UTF-8 mode when UCP support is available, check whether
     this character has more than one other case. If so, generate a special
--- pcre-8.37-orig/testdata/testinput11	2015-03-02 09:08:42.000000000 -0800
+++ pcre-8.37/testdata/testinput11	2015-06-18 14:07:11.883240591 -0700
@@ -136,4 +136,6 @@ is required for these tests. --/
 
 /((?+1)(\1))/B
 
+/.((?2)(?R)\1)()/B
+
 /-- End of testinput11 --/
--- pcre-8.37-orig/testdata/testinput2	2015-04-13 02:36:15.000000000 -0700
+++ pcre-8.37/testdata/testinput2	2015-06-18 14:13:30.706283638 -0700
@@ -4152,4 +4152,20 @@ backtracking verbs. --/
 
 /((?2){73}(?2))((?1))/
 
+/.((?2)(?R)\1)()/BZ
+
+/(?1)()((((((\1++))\x85)+)|))/
+
+/(\9*+(?2);\3++()2|)++{/
+
+/\V\x85\9*+((?2)\3++()2)*:2/
+
+/(((?(R)){0,2}) (?''((?'R')((?'R')))))/J
+
+/(((?(X)){0,2}) (?''((?'X')((?'X')))))/J
+
+/(((?(R)){0,2}) (?''((?'X')((?'R')))))/
+
+"(?J)(?'d'(?'d'\g{d}))"
+
 /-- End of testinput2 --/
--- pcre-8.37-orig/testdata/testoutput11-16	2015-03-02 09:09:21.000000000 -0800
+++ pcre-8.37/testdata/testoutput11-16	2015-06-18 14:09:10.358550764 -0700
@@ -748,4 +748,21 @@ Memory allocation (code space): 14
  22     End
 ------------------------------------------------------------------
 
+/.((?2)(?R)\1)()/B
+------------------------------------------------------------------
+  0  23 Bra
+  2     Any
+  3  13 Once
+  5   9 CBra 1
+  8  18 Recurse
+ 10   0 Recurse
+ 12     \1
+ 14   9 Ket
+ 16  13 Ket
+ 18   3 CBra 2
+ 21   3 Ket
+ 23  23 Ket
+ 25     End
+------------------------------------------------------------------
+
 /-- End of testinput11 --/
--- pcre-8.37-orig/testdata/testoutput11-32	2015-03-02 09:09:30.000000000 -0800
+++ pcre-8.37/testdata/testoutput11-32	2015-06-18 14:10:09.893600910 -0700
@@ -748,4 +748,21 @@ Memory allocation (code space): 28
  22     End
 ------------------------------------------------------------------
 
+/.((?2)(?R)\1)()/B
+------------------------------------------------------------------
+  0  23 Bra
+  2     Any
+  3  13 Once
+  5   9 CBra 1
+  8  18 Recurse
+ 10   0 Recurse
+ 12     \1
+ 14   9 Ket
+ 16  13 Ket
+ 18   3 CBra 2
+ 21   3 Ket
+ 23  23 Ket
+ 25     End
+------------------------------------------------------------------
+
 /-- End of testinput11 --/
--- pcre-8.37-orig/testdata/testoutput11-8	2015-03-02 09:09:13.000000000 -0800
+++ pcre-8.37/testdata/testoutput11-8	2015-06-18 14:11:19.765400848 -0700
@@ -748,4 +748,21 @@ Memory allocation (code space): 10
  34     End
 ------------------------------------------------------------------
 
+/.((?2)(?R)\1)()/B
+------------------------------------------------------------------
+  0  35 Bra
+  3     Any
+  4  20 Once
+  7  14 CBra 1
+ 12  27 Recurse
+ 15   0 Recurse
+ 18     \1
+ 21  14 Ket
+ 24  20 Ket
+ 27   5 CBra 2
+ 32   5 Ket
+ 35  35 Ket
+ 38     End
+------------------------------------------------------------------
+
 /-- End of testinput11 --/
--- pcre-8.37-orig/testdata/testoutput2	2015-04-13 02:36:27.000000000 -0700
+++ pcre-8.37/testdata/testoutput2	2015-06-18 14:15:05.747984099 -0700
@@ -14423,4 +14423,37 @@ Failed: lookbehind assertion is not fixe
 
 /((?2){73}(?2))((?1))/
 
+/.((?2)(?R)\1)()/BZ
+------------------------------------------------------------------
+        Bra
+        Any
+        Once
+        CBra 1
+        Recurse
+        Recurse
+        \1
+        Ket
+        Ket
+        CBra 2
+        Ket
+        Ket
+        End
+------------------------------------------------------------------
+
+/(?1)()((((((\1++))\x85)+)|))/
+
+/(\9*+(?2);\3++()2|)++{/
+Failed: reference to non-existent subpattern at offset 22
+
+/\V\x85\9*+((?2)\3++()2)*:2/
+Failed: reference to non-existent subpattern at offset 26
+
+/(((?(R)){0,2}) (?''((?'R')((?'R')))))/J
+
+/(((?(X)){0,2}) (?''((?'X')((?'X')))))/J
+
+/(((?(R)){0,2}) (?''((?'X')((?'R')))))/
+
+"(?J)(?'d'(?'d'\g{d}))"
+
 /-- End of testinput2 --/