]>
Commit | Line | Data |
---|---|---|
191976ef MT |
1 | From b3f0b0dd971314df8f865e221aa1a88e75d6d1a6 Mon Sep 17 00:00:00 2001 |
2 | From: ph10 <ph10@2f5784b3-3f2a-0410-8824-cb99058d5e15> | |
3 | Date: Wed, 5 Aug 2015 15:38:32 +0000 | |
4 | Subject: [PATCH] Fix buffer overflow for named references in (?| situations. | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | Ported for 8.37: | |
10 | ||
11 | commit 7af8e8717def179fd7b69e173abd347c1a3547cb | |
12 | Author: ph10 <ph10@2f5784b3-3f2a-0410-8824-cb99058d5e15> | |
13 | Date: Wed Aug 5 15:38:32 2015 +0000 | |
14 | ||
15 | Fix buffer overflow for named references in (?| situations. | |
16 | ||
17 | git-svn-id: svn://vcs.exim.org/pcre/code/trunk@1585 2f5784b3-3f2a-0410-8824-cb99058d5e15 | |
18 | ||
19 | Signed-off-by: Petr Písař <ppisar@redhat.com> | |
20 | --- | |
21 | pcre_compile.c | 74 ++++++++++++++++++++++++++++++---------------------- | |
22 | pcre_internal.h | 1 + | |
23 | testdata/testinput2 | 2 ++ | |
24 | testdata/testoutput2 | 2 ++ | |
25 | 4 files changed, 48 insertions(+), 31 deletions(-) | |
26 | ||
27 | diff --git a/pcre_compile.c b/pcre_compile.c | |
28 | index f5d2384..5fe5c1d 100644 | |
29 | --- a/pcre_compile.c | |
30 | +++ b/pcre_compile.c | |
31 | @@ -6641,6 +6641,7 @@ for (;; ptr++) | |
32 | /* ------------------------------------------------------------ */ | |
33 | case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ | |
34 | reset_bracount = TRUE; | |
35 | + cd->dupgroups = TRUE; /* Record (?| encountered */ | |
36 | /* Fall through */ | |
37 | ||
38 | /* ------------------------------------------------------------ */ | |
39 | @@ -7151,7 +7152,8 @@ for (;; ptr++) | |
40 | if (lengthptr != NULL) | |
41 | { | |
42 | named_group *ng; | |
43 | - | |
44 | + recno = 0; | |
45 | + | |
46 | if (namelen == 0) | |
47 | { | |
48 | *errorcodeptr = ERR62; | |
49 | @@ -7168,32 +7170,6 @@ for (;; ptr++) | |
50 | goto FAILED; | |
51 | } | |
52 | ||
53 | - /* The name table does not exist in the first pass; instead we must | |
54 | - scan the list of names encountered so far in order to get the | |
55 | - number. If the name is not found, set the value to 0 for a forward | |
56 | - reference. */ | |
57 | - | |
58 | - recno = 0; | |
59 | - ng = cd->named_groups; | |
60 | - for (i = 0; i < cd->names_found; i++, ng++) | |
61 | - { | |
62 | - if (namelen == ng->length && | |
63 | - STRNCMP_UC_UC(name, ng->name, namelen) == 0) | |
64 | - { | |
65 | - open_capitem *oc; | |
66 | - recno = ng->number; | |
67 | - if (is_recurse) break; | |
68 | - for (oc = cd->open_caps; oc != NULL; oc = oc->next) | |
69 | - { | |
70 | - if (oc->number == recno) | |
71 | - { | |
72 | - oc->flag = TRUE; | |
73 | - break; | |
74 | - } | |
75 | - } | |
76 | - } | |
77 | - } | |
78 | - | |
79 | /* Count named back references. */ | |
80 | ||
81 | if (!is_recurse) cd->namedrefcount++; | |
82 | @@ -7215,7 +7191,44 @@ for (;; ptr++) | |
83 | issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance | |
84 | only mode, we finesse the bug by allowing more memory always. */ | |
85 | ||
86 | - /* if (recno == 0) */ *lengthptr += 2 + 2*LINK_SIZE; | |
87 | + *lengthptr += 2 + 2*LINK_SIZE; | |
88 | + | |
89 | + /* It is even worse than that. The current reference may be to an | |
90 | + existing named group with a different number (so apparently not | |
91 | + recursive) but which later on is also attached to a group with the | |
92 | + current number. This can only happen if $(| has been previous | |
93 | + encountered. In that case, we allow yet more memory, just in case. | |
94 | + (Again, this is fixed "properly" in PCRE2. */ | |
95 | + | |
96 | + if (cd->dupgroups) *lengthptr += 2 + 2*LINK_SIZE; | |
97 | + | |
98 | + /* Otherwise, check for recursion here. The name table does not exist | |
99 | + in the first pass; instead we must scan the list of names encountered | |
100 | + so far in order to get the number. If the name is not found, leave | |
101 | + the value of recno as 0 for a forward reference. */ | |
102 | + | |
103 | + else | |
104 | + { | |
105 | + ng = cd->named_groups; | |
106 | + for (i = 0; i < cd->names_found; i++, ng++) | |
107 | + { | |
108 | + if (namelen == ng->length && | |
109 | + STRNCMP_UC_UC(name, ng->name, namelen) == 0) | |
110 | + { | |
111 | + open_capitem *oc; | |
112 | + recno = ng->number; | |
113 | + if (is_recurse) break; | |
114 | + for (oc = cd->open_caps; oc != NULL; oc = oc->next) | |
115 | + { | |
116 | + if (oc->number == recno) | |
117 | + { | |
118 | + oc->flag = TRUE; | |
119 | + break; | |
120 | + } | |
121 | + } | |
122 | + } | |
123 | + } | |
124 | + } | |
125 | } | |
126 | ||
127 | /* In the real compile, search the name table. We check the name | |
128 | @@ -7262,8 +7275,6 @@ for (;; ptr++) | |
129 | for (i++; i < cd->names_found; i++) | |
130 | { | |
131 | if (STRCMP_UC_UC(slot + IMM2_SIZE, cslot + IMM2_SIZE) != 0) break; | |
132 | - | |
133 | - | |
134 | count++; | |
135 | cslot += cd->name_entry_size; | |
136 | } | |
137 | @@ -9189,6 +9200,7 @@ cd->names_found = 0; | |
138 | cd->name_entry_size = 0; | |
139 | cd->name_table = NULL; | |
140 | cd->dupnames = FALSE; | |
141 | +cd->dupgroups = FALSE; | |
142 | cd->namedrefcount = 0; | |
143 | cd->start_code = cworkspace; | |
144 | cd->hwm = cworkspace; | |
145 | @@ -9223,7 +9235,7 @@ if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN; | |
146 | ||
147 | DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, | |
148 | (int)(cd->hwm - cworkspace))); | |
149 | - | |
150 | + | |
151 | if (length > MAX_PATTERN_SIZE) | |
152 | { | |
153 | errorcode = ERR20; | |
154 | diff --git a/pcre_internal.h b/pcre_internal.h | |
155 | index dd0ac7f..7ca6020 100644 | |
156 | --- a/pcre_internal.h | |
157 | +++ b/pcre_internal.h | |
158 | @@ -2446,6 +2446,7 @@ typedef struct compile_data { | |
159 | BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ | |
160 | BOOL check_lookbehind; /* Lookbehinds need later checking */ | |
161 | BOOL dupnames; /* Duplicate names exist */ | |
162 | + BOOL dupgroups; /* Duplicate groups exist: (?| found */ | |
163 | BOOL iscondassert; /* Next assert is a condition */ | |
164 | int nltype; /* Newline type */ | |
165 | int nllen; /* Newline string length */ | |
166 | diff --git a/testdata/testinput2 b/testdata/testinput2 | |
167 | index e12de3a..8e044f8 100644 | |
168 | --- a/testdata/testinput2 | |
169 | +++ b/testdata/testinput2 | |
170 | @@ -4158,4 +4158,6 @@ backtracking verbs. --/ | |
171 | ||
172 | "(?J:(?|(?'R')(\k'R')|((?'R'))))" | |
173 | ||
174 | +/(?J:(?|(:(?|(?'R')(\k'R')|((?'R')))H'Rk'Rf)|s(?'R')))/ | |
175 | + | |
176 | /-- End of testinput2 --/ | |
177 | diff --git a/testdata/testoutput2 b/testdata/testoutput2 | |
178 | index 5bad26c..6019425 100644 | |
179 | --- a/testdata/testoutput2 | |
180 | +++ b/testdata/testoutput2 | |
181 | @@ -14430,4 +14430,6 @@ Failed: unmatched parentheses at offset 23 | |
182 | ||
183 | "(?J:(?|(?'R')(\k'R')|((?'R'))))" | |
184 | ||
185 | +/(?J:(?|(:(?|(?'R')(\k'R')|((?'R')))H'Rk'Rf)|s(?'R')))/ | |
186 | + | |
187 | /-- End of testinput2 --/ | |
188 | -- | |
189 | 2.4.3 | |
190 |