Harden pcre2test against ridiculously large values in modifiers and command

line arguments.
This commit is contained in:
Philip.Hazel 2015-12-05 18:17:41 +00:00
parent 925146d8cc
commit b34dbecb75
4 changed files with 67 additions and 38 deletions

View File

@ -383,6 +383,9 @@ was found by the LLVM fuzzer.
110. Implemented PCRE2_SUBSTITUTE_UNSET_EMPTY, and updated pcre2test to make it
possible to test it.
111. "Harden" pcre2test against ridiculously large values in modifiers and
command line arguments.
Version 10.20 30-June-2015
--------------------------

View File

@ -2973,33 +2973,6 @@ return 0;
/*************************************************
* Read number from string *
*************************************************/
/* We don't use strtoul() because SunOS4 doesn't have it. Rather than mess
around with conditional compilation, just do the job by hand. It is only used
for unpicking arguments, so just keep it simple.
Arguments:
str string to be converted
endptr where to put the end pointer
Returns: the unsigned long
*/
static int
get_value(const char *str, const char **endptr)
{
int result = 0;
while(*str != 0 && isspace(*str)) str++;
while (isdigit(*str)) result = result * 10 + (int)(*str++ - '0');
*endptr = str;
return(result);
}
/*************************************************
* Scan the main modifier list *
*************************************************/
@ -3149,6 +3122,8 @@ static BOOL
decode_modifiers(uint8_t *p, int ctx, patctl *pctl, datctl *dctl)
{
uint8_t *ep, *pp;
long li;
unsigned long uli;
BOOL first = TRUE;
for (;;)
@ -3314,9 +3289,15 @@ for (;;)
case MOD_IN2: /* One or two unsigned integers */
if (!isdigit(*pp)) goto INVALID_VALUE;
((uint32_t *)field)[0] = (uint32_t)strtoul((const char *)pp, &endptr, 10);
uli = strtoul((const char *)pp, &endptr, 10);
if (uli > UINT32_MAX) goto INVALID_VALUE;
((uint32_t *)field)[0] = (uint32_t)uli;
if (*endptr == ':')
((uint32_t *)field)[1] = (uint32_t)strtoul((const char *)endptr+1, &endptr, 10);
{
uli = strtoul((const char *)endptr+1, &endptr, 10);
if (uli > UINT32_MAX) goto INVALID_VALUE;
((uint32_t *)field)[1] = (uint32_t)uli;
}
else ((uint32_t *)field)[1] = 0;
pp = (uint8_t *)endptr;
break;
@ -3331,19 +3312,25 @@ for (;;)
case MOD_SIZ: /* PCRE2_SIZE value */
if (!isdigit(*pp)) goto INVALID_VALUE;
*((PCRE2_SIZE *)field) = (PCRE2_SIZE)strtoul((const char *)pp, &endptr, 10);
uli = strtoul((const char *)pp, &endptr, 10);
if (uli == ULONG_MAX) goto INVALID_VALUE;
*((PCRE2_SIZE *)field) = (PCRE2_SIZE)uli;
pp = (uint8_t *)endptr;
break;
case MOD_INT: /* Unsigned integer */
if (!isdigit(*pp)) goto INVALID_VALUE;
*((uint32_t *)field) = (uint32_t)strtoul((const char *)pp, &endptr, 10);
uli = strtoul((const char *)pp, &endptr, 10);
if (uli > UINT32_MAX) goto INVALID_VALUE;
*((uint32_t *)field) = (uint32_t)uli;
pp = (uint8_t *)endptr;
break;
case MOD_INS: /* Signed integer */
if (!isdigit(*pp) && *pp != '-') goto INVALID_VALUE;
*((int32_t *)field) = (int32_t)strtol((const char *)pp, &endptr, 10);
li = strtol((const char *)pp, &endptr, 10);
if (li > INT32_MAX || li < INT32_MIN) goto INVALID_VALUE;
*((int32_t *)field) = (int32_t)li;
pp = (uint8_t *)endptr;
break;
@ -3371,7 +3358,10 @@ for (;;)
if (isdigit(*pp) || *pp == '-')
{
int ct = MAXCPYGET - 1;
int32_t value = (int32_t)strtol((const char *)pp, &endptr, 10);
int32_t value;
li = strtol((const char *)pp, &endptr, 10);
if (li > INT32_MAX || li < INT32_MIN) goto INVALID_VALUE;
value = (int32_t)li;
field = (char *)field - m->offset + m->value; /* Adjust field ptr */
if (value >= 0) /* Add new number */
{
@ -6894,8 +6884,9 @@ def_datctl.cfail[0] = def_datctl.cfail[1] = CFAIL_UNSET;
while (argc > 1 && argv[op][0] == '-' && argv[op][1] != 0)
{
const char *endptr;
char *endptr;
char *arg = argv[op];
unsigned long uli;
/* Display and/or set return code for configuration options. */
@ -6945,7 +6936,7 @@ while (argc > 1 && argv[op][0] == '-' && argv[op][1] != 0)
/* Set system stack size */
else if (strcmp(arg, "-S") == 0 && argc > 2 &&
((stack_size = get_value(argv[op+1], &endptr)), *endptr == 0))
((uli = strtoul(argv[op+1], &endptr, 10)), *endptr == 0))
{
#if defined(_WIN32) || defined(WIN32) || defined(__minix) || defined(NATIVE_ZOS) || defined(__VMS)
fprintf(stderr, "pcre2test: -S is not supported on this OS\n");
@ -6953,6 +6944,12 @@ while (argc > 1 && argv[op][0] == '-' && argv[op][1] != 0)
#else
int rc;
struct rlimit rlim;
if (uli > UINT32_MAX)
{
fprintf(stderr, "+++ Argument for -S is too big\n");
exit(1);
}
stack_size = (uint32_t)uli;
getrlimit(RLIMIT_STACK, &rlim);
rlim.rlim_cur = stack_size * 1024 * 1024;
if (rlim.rlim_cur > rlim.rlim_max)
@ -6995,12 +6992,16 @@ while (argc > 1 && argv[op][0] == '-' && argv[op][1] != 0)
else if (strcmp(arg, "-t") == 0 || strcmp(arg, "-tm") == 0 ||
strcmp(arg, "-T") == 0 || strcmp(arg, "-TM") == 0)
{
int temp;
int both = arg[2] == 0;
showtotaltimes = arg[1] == 'T';
if (argc > 2 && (temp = get_value(argv[op+1], &endptr), *endptr == 0))
if (argc > 2 && (uli = strtoul(argv[op+1], &endptr, 10), *endptr == 0))
{
timeitm = temp;
if (uli > INT32_MAX)
{
fprintf(stderr, "+++ Argument for %s is too big\n", arg);
exit(1);
}
timeitm = (int)uli;
op++;
argc--;
}

9
testdata/testinput2 vendored
View File

@ -4756,4 +4756,13 @@ a)"xI
/a|(b)c/replace=>$2<,substitute_unset_empty
cat
/()()()/use_offset_limit
\=ovector=11000000000
\=callout_fail=11000000000
\=callout_fail=1:11000000000
\=callout_data=11000000000
\=callout_data=-11000000000
\=offset_limit=1100000000000000000000
\=copy=11000000000
# End of testinput2

16
testdata/testoutput2 vendored
View File

@ -15085,4 +15085,20 @@ Failed: error -55 at offset 3 in replacement: requested value is not set
cat
Failed: error -49 at offset 3 in replacement: unknown substring
/()()()/use_offset_limit
\=ovector=11000000000
** Invalid value in 'ovector=11000000000'
\=callout_fail=11000000000
** Invalid value in 'callout_fail=11000000000'
\=callout_fail=1:11000000000
** Invalid value in 'callout_fail=1:11000000000'
\=callout_data=11000000000
** Invalid value in 'callout_data=11000000000'
\=callout_data=-11000000000
** Invalid value in 'callout_data=-11000000000'
\=offset_limit=1100000000000000000000
** Invalid value in 'offset_limit=1100000000000000000000'
\=copy=11000000000
** Invalid value in 'copy=11000000000'
# End of testinput2