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.
This commit is contained in:
parent
d24a1c9d31
commit
ae4e6261e5
|
@ -3649,7 +3649,9 @@ needed is returned via \fIoutlengthptr\fP. Note that this does not happen by
|
||||||
default.
|
default.
|
||||||
.P
|
.P
|
||||||
PCRE2_ERROR_NULL is returned if PCRE2_SUBSTITUTE_MATCHED is set but the
|
PCRE2_ERROR_NULL is returned if PCRE2_SUBSTITUTE_MATCHED is set but the
|
||||||
\fImatch_data\fP argument is NULL.
|
\fImatch_data\fP argument is NULL or if the \fIsubject\fP or \fIreplacement\fP
|
||||||
|
arguments are NULL. For backward compatibility reasons an exception is made for
|
||||||
|
the \fIreplacement\fP argument if the \fIrlength\fP argument is also 0.
|
||||||
.P
|
.P
|
||||||
PCRE2_ERROR_BADREPLACEMENT is used for miscellaneous syntax errors in the
|
PCRE2_ERROR_BADREPLACEMENT is used for miscellaneous syntax errors in the
|
||||||
replacement string, with more particular errors being PCRE2_ERROR_BADREPESCAPE
|
replacement string, with more particular errors being PCRE2_ERROR_BADREPESCAPE
|
||||||
|
|
|
@ -3285,8 +3285,11 @@ rws->next = NULL;
|
||||||
rws->size = RWS_BASE_SIZE;
|
rws->size = RWS_BASE_SIZE;
|
||||||
rws->free = RWS_BASE_SIZE - RWS_ANCHOR_SIZE;
|
rws->free = RWS_BASE_SIZE - RWS_ANCHOR_SIZE;
|
||||||
|
|
||||||
/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
|
/* Plausibility checks */
|
||||||
subject string. */
|
|
||||||
|
if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
|
||||||
|
if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL)
|
||||||
|
return PCRE2_ERROR_NULL;
|
||||||
|
|
||||||
if (length == PCRE2_ZERO_TERMINATED)
|
if (length == PCRE2_ZERO_TERMINATED)
|
||||||
{
|
{
|
||||||
|
@ -3294,11 +3297,6 @@ if (length == PCRE2_ZERO_TERMINATED)
|
||||||
was_zero_terminated = 1;
|
was_zero_terminated = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Plausibility checks */
|
|
||||||
|
|
||||||
if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
|
|
||||||
if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL)
|
|
||||||
return PCRE2_ERROR_NULL;
|
|
||||||
if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE;
|
if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE;
|
||||||
if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
|
if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
/* #define DEBUG_SHOW_OPS */
|
/* #define DEBUG_SHOW_OPS */
|
||||||
/* #define DEBUG_SHOW_RMATCH */
|
/* #define DEBUG_SHOW_RMATCH */
|
||||||
|
|
||||||
#ifdef DEBUG_FRAME_DISPLAY
|
#ifdef DEBUG_FRAMES_DISPLAY
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -6129,8 +6129,8 @@ PCRE2_UCHAR req_cu2 = 0;
|
||||||
PCRE2_SPTR bumpalong_limit;
|
PCRE2_SPTR bumpalong_limit;
|
||||||
PCRE2_SPTR end_subject;
|
PCRE2_SPTR end_subject;
|
||||||
PCRE2_SPTR true_end_subject;
|
PCRE2_SPTR true_end_subject;
|
||||||
PCRE2_SPTR start_match = subject + start_offset;
|
PCRE2_SPTR start_match;
|
||||||
PCRE2_SPTR req_cu_ptr = start_match - 1;
|
PCRE2_SPTR req_cu_ptr;
|
||||||
PCRE2_SPTR start_partial;
|
PCRE2_SPTR start_partial;
|
||||||
PCRE2_SPTR match_partial;
|
PCRE2_SPTR match_partial;
|
||||||
|
|
||||||
|
@ -6170,9 +6170,14 @@ PCRE2_SPTR stack_frames_vector[START_FRAMES_SIZE/sizeof(PCRE2_SPTR)]
|
||||||
PCRE2_KEEP_UNINITIALIZED;
|
PCRE2_KEEP_UNINITIALIZED;
|
||||||
mb->stack_frames = (heapframe *)stack_frames_vector;
|
mb->stack_frames = (heapframe *)stack_frames_vector;
|
||||||
|
|
||||||
/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
|
/* Plausibility checks */
|
||||||
subject string. */
|
|
||||||
|
|
||||||
|
if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
|
||||||
|
if (code == NULL || subject == NULL || match_data == NULL)
|
||||||
|
return PCRE2_ERROR_NULL;
|
||||||
|
|
||||||
|
start_match = subject + start_offset;
|
||||||
|
req_cu_ptr = start_match - 1;
|
||||||
if (length == PCRE2_ZERO_TERMINATED)
|
if (length == PCRE2_ZERO_TERMINATED)
|
||||||
{
|
{
|
||||||
length = PRIV(strlen)(subject);
|
length = PRIV(strlen)(subject);
|
||||||
|
@ -6180,11 +6185,6 @@ if (length == PCRE2_ZERO_TERMINATED)
|
||||||
}
|
}
|
||||||
true_end_subject = end_subject = subject + length;
|
true_end_subject = end_subject = subject + length;
|
||||||
|
|
||||||
/* Plausibility checks */
|
|
||||||
|
|
||||||
if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
|
|
||||||
if (code == NULL || subject == NULL || match_data == NULL)
|
|
||||||
return PCRE2_ERROR_NULL;
|
|
||||||
if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
|
if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
|
||||||
|
|
||||||
/* Check that the first field in the block is the magic number. */
|
/* Check that the first field in the block is the magic number. */
|
||||||
|
|
|
@ -260,6 +260,12 @@ PCRE2_UNSET, so as not to imply an offset in the replacement. */
|
||||||
if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0)
|
if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0)
|
||||||
return PCRE2_ERROR_BADOPTION;
|
return PCRE2_ERROR_BADOPTION;
|
||||||
|
|
||||||
|
/* Validate length and find the end of the replacement. */
|
||||||
|
if (replacement == NULL && rlength > 0) return PCRE2_ERROR_NULL;
|
||||||
|
else if (rlength == PCRE2_ZERO_TERMINATED)
|
||||||
|
rlength = PRIV(strlen)(replacement);
|
||||||
|
repend = replacement + rlength;
|
||||||
|
|
||||||
/* Check for using a match that has already happened. Note that the subject
|
/* Check for using a match that has already happened. Note that the subject
|
||||||
pointer in the match data may be NULL after a no-match. */
|
pointer in the match data may be NULL after a no-match. */
|
||||||
|
|
||||||
|
@ -292,6 +298,7 @@ else if (use_existing_match)
|
||||||
(pcre2_general_context *)mcontext;
|
(pcre2_general_context *)mcontext;
|
||||||
int pairs = (code->top_bracket + 1 < match_data->oveccount)?
|
int pairs = (code->top_bracket + 1 < match_data->oveccount)?
|
||||||
code->top_bracket + 1 : match_data->oveccount;
|
code->top_bracket + 1 : match_data->oveccount;
|
||||||
|
if (subject == NULL) return PCRE2_ERROR_NULL;
|
||||||
internal_match_data = pcre2_match_data_create(match_data->oveccount,
|
internal_match_data = pcre2_match_data_create(match_data->oveccount,
|
||||||
gcontext);
|
gcontext);
|
||||||
if (internal_match_data == NULL) return PCRE2_ERROR_NOMEMORY;
|
if (internal_match_data == NULL) return PCRE2_ERROR_NOMEMORY;
|
||||||
|
@ -312,11 +319,9 @@ scb.input = subject;
|
||||||
scb.output = (PCRE2_SPTR)buffer;
|
scb.output = (PCRE2_SPTR)buffer;
|
||||||
scb.ovector = ovector;
|
scb.ovector = ovector;
|
||||||
|
|
||||||
/* Find lengths of zero-terminated strings and the end of the replacement. */
|
/* Find lengths of zero-terminated subject */
|
||||||
|
if (length == PCRE2_ZERO_TERMINATED)
|
||||||
if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
|
length = subject? PRIV(strlen)(subject) : 0;
|
||||||
if (rlength == PCRE2_ZERO_TERMINATED) rlength = PRIV(strlen)(replacement);
|
|
||||||
repend = replacement + rlength;
|
|
||||||
|
|
||||||
/* Check UTF replacement string if necessary. */
|
/* Check UTF replacement string if necessary. */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue