From b3f0b0dd971314df8f865e221aa1a88e75d6d1a6 Mon Sep 17 00:00:00 2001 From: ph10 Date: Wed, 5 Aug 2015 15:38:32 +0000 Subject: [PATCH] Fix buffer overflow for named references in (?| situations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ported for 8.37: commit 7af8e8717def179fd7b69e173abd347c1a3547cb Author: ph10 Date: Wed Aug 5 15:38:32 2015 +0000 Fix buffer overflow for named references in (?| situations. git-svn-id: svn://vcs.exim.org/pcre/code/trunk@1585 2f5784b3-3f2a-0410-8824-cb99058d5e15 Signed-off-by: Petr Písař --- pcre_compile.c | 74 ++++++++++++++++++++++++++++++---------------------- pcre_internal.h | 1 + testdata/testinput2 | 2 ++ testdata/testoutput2 | 2 ++ 4 files changed, 48 insertions(+), 31 deletions(-) diff --git a/pcre_compile.c b/pcre_compile.c index f5d2384..5fe5c1d 100644 --- a/pcre_compile.c +++ b/pcre_compile.c @@ -6641,6 +6641,7 @@ for (;; ptr++) /* ------------------------------------------------------------ */ case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ reset_bracount = TRUE; + cd->dupgroups = TRUE; /* Record (?| encountered */ /* Fall through */ /* ------------------------------------------------------------ */ @@ -7151,7 +7152,8 @@ for (;; ptr++) if (lengthptr != NULL) { named_group *ng; - + recno = 0; + if (namelen == 0) { *errorcodeptr = ERR62; @@ -7168,32 +7170,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++; @@ -7215,7 +7191,44 @@ for (;; ptr++) issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance only mode, we finesse the bug by allowing more memory always. */ - /* 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 @@ -7262,8 +7275,6 @@ for (;; ptr++) 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; } @@ -9189,6 +9200,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; @@ -9223,7 +9235,7 @@ if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN; DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, (int)(cd->hwm - cworkspace))); - + if (length > MAX_PATTERN_SIZE) { errorcode = ERR20; diff --git a/pcre_internal.h b/pcre_internal.h index dd0ac7f..7ca6020 100644 --- 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 */ BOOL iscondassert; /* Next assert is a condition */ int nltype; /* Newline type */ int nllen; /* Newline string length */ diff --git a/testdata/testinput2 b/testdata/testinput2 index e12de3a..8e044f8 100644 --- a/testdata/testinput2 +++ b/testdata/testinput2 @@ -4158,4 +4158,6 @@ backtracking verbs. --/ "(?J:(?|(?'R')(\k'R')|((?'R'))))" +/(?J:(?|(:(?|(?'R')(\k'R')|((?'R')))H'Rk'Rf)|s(?'R')))/ + /-- End of testinput2 --/ diff --git a/testdata/testoutput2 b/testdata/testoutput2 index 5bad26c..6019425 100644 --- a/testdata/testoutput2 +++ b/testdata/testoutput2 @@ -14430,4 +14430,6 @@ Failed: unmatched parentheses at offset 23 "(?J:(?|(?'R')(\k'R')|((?'R'))))" +/(?J:(?|(:(?|(?'R')(\k'R')|((?'R')))H'Rk'Rf)|s(?'R')))/ + /-- End of testinput2 --/ -- 2.4.3