Skip to content

Commit ae4e626

Browse files
authored
match: avoid crash if subject NULL and PCRE2_ZERO_TERMINATED (#53)
* pcre2_match: avoid crash if subject NULL and PCRE2_ZERO_TERMINATED When length of subject is PCRE2_ZERO_TERMINATED strlen is used to calculate its size, which will trigger a crash if subject is also NULL. Move the NULL check before strlen on it would be used, and make sure or dependent variables are set after the NULL validation as well. While at it, fix a typo in a debug flag in the same file, which is otherwise unrelated and make sure the full section of constrain checks can be identified clearly using the leading comment alone. * pcre2_dfa_match: avoid crash if subject NULL and PCRE2_ZERO_TERMINATED When length of subject is PCRE2_ZERO_TERMINATED strlen is used to calculate its size, which will trigger a crash if subject is also NULL. Move the NULL check before the detection for subject sizes to avoid this issue. * pcre2_substitute: avoid crash if subject or replacement are NULL The underlying pcre2_match() function will validate the subject if needed, but will crash when length is PCRE2_ZERO_TERMINATED or if subject == NULL and pcre2_match() is not being called because match_data was provided. The replacement parameter is missing NULL checks, and so currently allows for an equivalent response to "" if rlength == 0. Restrict all other cases to avoid strlen(NULL) crashes in the same way that is done for subject, but also make sure to reject invalid length values as early as possible.
1 parent d24a1c9 commit ae4e626

File tree

4 files changed

+28
-23
lines changed

4 files changed

+28
-23
lines changed

doc/pcre2api.3

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3649,7 +3649,9 @@ needed is returned via \fIoutlengthptr\fP. Note that this does not happen by
36493649
default.
36503650
.P
36513651
PCRE2_ERROR_NULL is returned if PCRE2_SUBSTITUTE_MATCHED is set but the
3652-
\fImatch_data\fP argument is NULL.
3652+
\fImatch_data\fP argument is NULL or if the \fIsubject\fP or \fIreplacement\fP
3653+
arguments are NULL. For backward compatibility reasons an exception is made for
3654+
the \fIreplacement\fP argument if the \fIrlength\fP argument is also 0.
36533655
.P
36543656
PCRE2_ERROR_BADREPLACEMENT is used for miscellaneous syntax errors in the
36553657
replacement string, with more particular errors being PCRE2_ERROR_BADREPESCAPE

src/pcre2_dfa_match.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3285,20 +3285,18 @@ rws->next = NULL;
32853285
rws->size = RWS_BASE_SIZE;
32863286
rws->free = RWS_BASE_SIZE - RWS_ANCHOR_SIZE;
32873287

3288-
/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
3289-
subject string. */
3288+
/* Plausibility checks */
3289+
3290+
if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
3291+
if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL)
3292+
return PCRE2_ERROR_NULL;
32903293

32913294
if (length == PCRE2_ZERO_TERMINATED)
32923295
{
32933296
length = PRIV(strlen)(subject);
32943297
was_zero_terminated = 1;
32953298
}
32963299

3297-
/* Plausibility checks */
3298-
3299-
if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
3300-
if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL)
3301-
return PCRE2_ERROR_NULL;
33023300
if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE;
33033301
if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
33043302

src/pcre2_match.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
4949
/* #define DEBUG_SHOW_OPS */
5050
/* #define DEBUG_SHOW_RMATCH */
5151

52-
#ifdef DEBUG_FRAME_DISPLAY
52+
#ifdef DEBUG_FRAMES_DISPLAY
5353
#include <stdarg.h>
5454
#endif
5555

@@ -6129,8 +6129,8 @@ PCRE2_UCHAR req_cu2 = 0;
61296129
PCRE2_SPTR bumpalong_limit;
61306130
PCRE2_SPTR end_subject;
61316131
PCRE2_SPTR true_end_subject;
6132-
PCRE2_SPTR start_match = subject + start_offset;
6133-
PCRE2_SPTR req_cu_ptr = start_match - 1;
6132+
PCRE2_SPTR start_match;
6133+
PCRE2_SPTR req_cu_ptr;
61346134
PCRE2_SPTR start_partial;
61356135
PCRE2_SPTR match_partial;
61366136

@@ -6170,21 +6170,21 @@ PCRE2_SPTR stack_frames_vector[START_FRAMES_SIZE/sizeof(PCRE2_SPTR)]
61706170
PCRE2_KEEP_UNINITIALIZED;
61716171
mb->stack_frames = (heapframe *)stack_frames_vector;
61726172

6173-
/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
6174-
subject string. */
6173+
/* Plausibility checks */
6174+
6175+
if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
6176+
if (code == NULL || subject == NULL || match_data == NULL)
6177+
return PCRE2_ERROR_NULL;
61756178

6179+
start_match = subject + start_offset;
6180+
req_cu_ptr = start_match - 1;
61766181
if (length == PCRE2_ZERO_TERMINATED)
61776182
{
61786183
length = PRIV(strlen)(subject);
61796184
was_zero_terminated = 1;
61806185
}
61816186
true_end_subject = end_subject = subject + length;
61826187

6183-
/* Plausibility checks */
6184-
6185-
if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
6186-
if (code == NULL || subject == NULL || match_data == NULL)
6187-
return PCRE2_ERROR_NULL;
61886188
if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
61896189

61906190
/* Check that the first field in the block is the magic number. */

src/pcre2_substitute.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ PCRE2_UNSET, so as not to imply an offset in the replacement. */
260260
if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0)
261261
return PCRE2_ERROR_BADOPTION;
262262

263+
/* Validate length and find the end of the replacement. */
264+
if (replacement == NULL && rlength > 0) return PCRE2_ERROR_NULL;
265+
else if (rlength == PCRE2_ZERO_TERMINATED)
266+
rlength = PRIV(strlen)(replacement);
267+
repend = replacement + rlength;
268+
263269
/* Check for using a match that has already happened. Note that the subject
264270
pointer in the match data may be NULL after a no-match. */
265271

@@ -292,6 +298,7 @@ else if (use_existing_match)
292298
(pcre2_general_context *)mcontext;
293299
int pairs = (code->top_bracket + 1 < match_data->oveccount)?
294300
code->top_bracket + 1 : match_data->oveccount;
301+
if (subject == NULL) return PCRE2_ERROR_NULL;
295302
internal_match_data = pcre2_match_data_create(match_data->oveccount,
296303
gcontext);
297304
if (internal_match_data == NULL) return PCRE2_ERROR_NOMEMORY;
@@ -312,11 +319,9 @@ scb.input = subject;
312319
scb.output = (PCRE2_SPTR)buffer;
313320
scb.ovector = ovector;
314321

315-
/* Find lengths of zero-terminated strings and the end of the replacement. */
316-
317-
if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
318-
if (rlength == PCRE2_ZERO_TERMINATED) rlength = PRIV(strlen)(replacement);
319-
repend = replacement + rlength;
322+
/* Find lengths of zero-terminated subject */
323+
if (length == PCRE2_ZERO_TERMINATED)
324+
length = subject? PRIV(strlen)(subject) : 0;
320325

321326
/* Check UTF replacement string if necessary. */
322327

0 commit comments

Comments
 (0)