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 110. Implemented PCRE2_SUBSTITUTE_UNSET_EMPTY, and updated pcre2test to make it
possible to test it. possible to test it.
111. "Harden" pcre2test against ridiculously large values in modifiers and
command line arguments.
Version 10.20 30-June-2015 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 * * Scan the main modifier list *
*************************************************/ *************************************************/
@ -3149,6 +3122,8 @@ static BOOL
decode_modifiers(uint8_t *p, int ctx, patctl *pctl, datctl *dctl) decode_modifiers(uint8_t *p, int ctx, patctl *pctl, datctl *dctl)
{ {
uint8_t *ep, *pp; uint8_t *ep, *pp;
long li;
unsigned long uli;
BOOL first = TRUE; BOOL first = TRUE;
for (;;) for (;;)
@ -3314,9 +3289,15 @@ for (;;)
case MOD_IN2: /* One or two unsigned integers */ case MOD_IN2: /* One or two unsigned integers */
if (!isdigit(*pp)) goto INVALID_VALUE; 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 == ':') 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; else ((uint32_t *)field)[1] = 0;
pp = (uint8_t *)endptr; pp = (uint8_t *)endptr;
break; break;
@ -3331,19 +3312,25 @@ for (;;)
case MOD_SIZ: /* PCRE2_SIZE value */ case MOD_SIZ: /* PCRE2_SIZE value */
if (!isdigit(*pp)) goto INVALID_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; pp = (uint8_t *)endptr;
break; break;
case MOD_INT: /* Unsigned integer */ case MOD_INT: /* Unsigned integer */
if (!isdigit(*pp)) goto INVALID_VALUE; 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; pp = (uint8_t *)endptr;
break; break;
case MOD_INS: /* Signed integer */ case MOD_INS: /* Signed integer */
if (!isdigit(*pp) && *pp != '-') goto INVALID_VALUE; 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; pp = (uint8_t *)endptr;
break; break;
@ -3371,7 +3358,10 @@ for (;;)
if (isdigit(*pp) || *pp == '-') if (isdigit(*pp) || *pp == '-')
{ {
int ct = MAXCPYGET - 1; 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 */ field = (char *)field - m->offset + m->value; /* Adjust field ptr */
if (value >= 0) /* Add new number */ 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) while (argc > 1 && argv[op][0] == '-' && argv[op][1] != 0)
{ {
const char *endptr; char *endptr;
char *arg = argv[op]; char *arg = argv[op];
unsigned long uli;
/* Display and/or set return code for configuration options. */ /* 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 */ /* Set system stack size */
else if (strcmp(arg, "-S") == 0 && argc > 2 && 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) #if defined(_WIN32) || defined(WIN32) || defined(__minix) || defined(NATIVE_ZOS) || defined(__VMS)
fprintf(stderr, "pcre2test: -S is not supported on this OS\n"); 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 #else
int rc; int rc;
struct rlimit rlim; 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); getrlimit(RLIMIT_STACK, &rlim);
rlim.rlim_cur = stack_size * 1024 * 1024; rlim.rlim_cur = stack_size * 1024 * 1024;
if (rlim.rlim_cur > rlim.rlim_max) 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 || else if (strcmp(arg, "-t") == 0 || strcmp(arg, "-tm") == 0 ||
strcmp(arg, "-T") == 0 || strcmp(arg, "-TM") == 0) strcmp(arg, "-T") == 0 || strcmp(arg, "-TM") == 0)
{ {
int temp;
int both = arg[2] == 0; int both = arg[2] == 0;
showtotaltimes = arg[1] == 'T'; 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++; op++;
argc--; argc--;
} }

9
testdata/testinput2 vendored
View File

@ -4756,4 +4756,13 @@ a)"xI
/a|(b)c/replace=>$2<,substitute_unset_empty /a|(b)c/replace=>$2<,substitute_unset_empty
cat 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 # 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 cat
Failed: error -49 at offset 3 in replacement: unknown substring 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 # End of testinput2