Description: Fix buffer overflow for named references in (?| situations.
 .
 Addresses CVE-2015-8392.
Origin: upstream, http://vcs.pcre.org/pcre?view=revision&revision=1585
Forwarded: not-needed
Author: Salvatore Bonaccorso <carnil@debian.org>
Last-Update: 2015-12-29
Applied-Upstream: 8.38

---
 pcre_compile.c       | 74 ++++++++++++++++++++++++++++++----------------------
 pcre_internal.h      |  1 +
 testdata/testinput2  |  2 ++
 testdata/testoutput2 |  2 ++
 5 files changed, 54 insertions(+), 31 deletions(-)

--- a/pcre_compile.c
+++ b/pcre_compile.c
@@ -6555,6 +6555,7 @@ for (;; ptr++)
         /* ------------------------------------------------------------ */
         case CHAR_VERTICAL_LINE:  /* Reset capture count for each branch */
         reset_bracount = TRUE;
+        cd->dupgroups = TRUE;     /* Record (?| encountered */ 
         /* Fall through */
 
         /* ------------------------------------------------------------ */
@@ -7056,7 +7057,8 @@ for (;; ptr++)
         if (lengthptr != NULL)
           {
           named_group *ng;
-
+          recno = 0;
+           
           if (namelen == 0)
             {
             *errorcodeptr = ERR62;
@@ -7073,32 +7075,6 @@ for (;; ptr++)
             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. */
-
-          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)
-              {
-              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;
-                  }
-                }
-              }
-            }
-
           /* Count named back references. */
 
           if (!is_recurse) cd->namedrefcount++;
@@ -7109,7 +7085,44 @@ for (;; ptr++)
           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. */
 
-          if (recno == 0) *lengthptr += 2 + 2*LINK_SIZE;
+          *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 += 2 + 2*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
@@ -9078,6 +9091,7 @@ cd->names_found = 0;
 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;
@@ -9111,7 +9125,7 @@ if (errorcode != 0) goto PCRE_EARLY_ERRO
 
 DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,
   (int)(cd->hwm - cworkspace)));
-
+  
 if (length > MAX_PATTERN_SIZE)
   {
   errorcode = ERR20;
--- a/pcre_internal.h
+++ b/pcre_internal.h
@@ -2446,6 +2446,7 @@ typedef struct compile_data {
   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 */
   int  nltype;                      /* Newline type */
   int  nllen;                       /* Newline string length */
   pcre_uchar nl[4];                 /* Newline string when fixed length */
--- a/testdata/testinput2
+++ b/testdata/testinput2
@@ -4090,4 +4090,6 @@ backtracking verbs. --/
 
 "[[[.\xe8Nq\xffq\xff\xe0\x2|||::Nq\xffq\xff\xe0\x6\x2|||::[[[:[::::::[[[[[::::::::[:[[[:[:::[[[[[[[[[[[[:::::::::::::::::[[.\xe8Nq\xffq\xff\xe0\x2|||::Nq\xffq\xff\xe0\x6\x2|||::[[[:[::::::[[[[[::::::::[:[[[:[:::[[[[[[[[[[[[[[:::E[[[:[:[[:[:::[[:::E[[[:[:[[:'[:::::E[[[:[::::::[[[:[[[[[[[::E[[[:[::::::[[[:[[[[[[[[:[[::[::::[[:::::::[[:[[[[[[[:[[::[:[[:[~"
 
+/(?J:(?|(:(?|(?'R')(\k'R')|((?'R')))H'Rk'Rf)|s(?'R')))/
+
 /-- End of testinput2 --/
--- a/testdata/testoutput2
+++ b/testdata/testoutput2
@@ -14216,4 +14216,6 @@ Matched, but too many substrings
 "[[[.\xe8Nq\xffq\xff\xe0\x2|||::Nq\xffq\xff\xe0\x6\x2|||::[[[:[::::::[[[[[::::::::[:[[[:[:::[[[[[[[[[[[[:::::::::::::::::[[.\xe8Nq\xffq\xff\xe0\x2|||::Nq\xffq\xff\xe0\x6\x2|||::[[[:[::::::[[[[[::::::::[:[[[:[:::[[[[[[[[[[[[[[:::E[[[:[:[[:[:::[[:::E[[[:[:[[:'[:::::E[[[:[::::::[[[:[[[[[[[::E[[[:[::::::[[[:[[[[[[[[:[[::[::::[[:::::::[[:[[[[[[[:[[::[:[[:[~"
 Failed: missing terminating ] for character class at offset 353
 
+/(?J:(?|(:(?|(?'R')(\k'R')|((?'R')))H'Rk'Rf)|s(?'R')))/
+
 /-- End of testinput2 --/
--- a/testdata/testoutput11-8
+++ b/testdata/testoutput11-8
@@ -231,7 +231,7 @@ Memory allocation (code space): 45
 ------------------------------------------------------------------
 
 /(?P<a>a)...(?P=a)bbb(?P>a)d/BM
-Memory allocation (code space): 34
+Memory allocation (code space): 46
 ------------------------------------------------------------------
   0  30 Bra
   3   7 CBra 1
