Add a call to pcre2_dfa_match() to the fuzzer driver.

This commit is contained in:
ph10 2017-05-20 14:28:11 +00:00
parent cfd8c7c56a
commit 58bd4aa3cc

View File

@ -19,6 +19,8 @@ Written by Philip Hazel, October 2016
#define MAX_MATCH_SIZE 1000 #define MAX_MATCH_SIZE 1000
#define DFA_WORKSPACE_COUNT 100
#define ALLOWED_COMPILE_OPTIONS \ #define ALLOWED_COMPILE_OPTIONS \
(PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \
PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \ PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \
@ -33,9 +35,9 @@ Written by Philip Hazel, October 2016
(PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_HARD| \ PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_HARD| \
PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT) PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT)
/* This is the callout function. Its only purpose is to halt matching if there /* This is the callout function. Its only purpose is to halt matching if there
are more than 100 callouts, as one way of stopping too much time being spent on are more than 100 callouts, as one way of stopping too much time being spent on
fruitless matches. The callout data is a pointer to the counter. */ fruitless matches. The callout data is a pointer to the counter. */
static int callout_function(pcre2_callout_block *cb, void *callout_data) static int callout_function(pcre2_callout_block *cb, void *callout_data)
@ -44,9 +46,9 @@ static int callout_function(pcre2_callout_block *cb, void *callout_data)
*((uint32_t *)callout_data) += 1; *((uint32_t *)callout_data) += 1;
return (*((uint32_t *)callout_data) > 100)? PCRE2_ERROR_CALLOUT : 0; return (*((uint32_t *)callout_data) > 100)? PCRE2_ERROR_CALLOUT : 0;
} }
/* Putting in this apparently unnecessary prototype prevents gcc from giving a /* Putting in this apparently unnecessary prototype prevents gcc from giving a
"no previous prototype" warning when compiling at high warning level. */ "no previous prototype" warning when compiling at high warning level. */
int LLVMFuzzerTestOneInput(const unsigned char *, size_t); int LLVMFuzzerTestOneInput(const unsigned char *, size_t);
@ -59,12 +61,13 @@ uint32_t match_options;
pcre2_match_data *match_data = NULL; pcre2_match_data *match_data = NULL;
pcre2_match_context *match_context = NULL; pcre2_match_context *match_context = NULL;
size_t match_size; size_t match_size;
int dfa_workspace[DFA_WORKSPACE_COUNT];
int r1, r2; int r1, r2;
int i; int i;
if (size < 1) return 0; if (size < 1) return 0;
/* Limiting the length of the subject for matching stops fruitless searches /* Limiting the length of the subject for matching stops fruitless searches
in large trees taking too much time. */ in large trees taking too much time. */
match_size = (size > MAX_MATCH_SIZE)? MAX_MATCH_SIZE : size; match_size = (size > MAX_MATCH_SIZE)? MAX_MATCH_SIZE : size;
@ -134,7 +137,7 @@ for (i = 0; i < 2; i++)
code = pcre2_compile((PCRE2_SPTR)data, (PCRE2_SIZE)size, compile_options, code = pcre2_compile((PCRE2_SPTR)data, (PCRE2_SIZE)size, compile_options,
&errorcode, &erroroffset, NULL); &errorcode, &erroroffset, NULL);
/* Compilation succeeded */ /* Compilation succeeded */
if (code != NULL) if (code != NULL)
@ -169,8 +172,8 @@ for (i = 0; i < 2; i++)
return 0; return 0;
} }
(void)pcre2_set_match_limit(match_context, 100); (void)pcre2_set_match_limit(match_context, 100);
(void)pcre2_set_depth_limit(match_context, 100); (void)pcre2_set_depth_limit(match_context, 100);
(void)pcre2_set_callout(match_context, callout_function, &callout_count); (void)pcre2_set_callout(match_context, callout_function, &callout_count);
} }
/* Match twice, with and without options */ /* Match twice, with and without options */
@ -195,6 +198,42 @@ for (i = 0; i < 2; i++)
errorcode = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0, errorcode = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0,
match_options, match_data, match_context); match_options, match_data, match_context);
#ifdef STANDALONE
if (errorcode >= 0) printf("Match returned %d\n", errorcode); else
{
unsigned char buffer[256];
pcre2_get_error_message(errorcode, buffer, 256);
printf("Match failed: error %d: %s\n", errorcode, buffer);
}
#endif
match_options = 0; /* For second time */
}
/* Match with DFA twice, with and without options */
match_options = save_match_options & ~PCRE2_NO_JIT;
for (j = 0; j < 2; j++)
{
#ifdef STANDALONE
printf("DFA match options %.8x", match_options);
printf("%s%s%s%s%s%s%s%s%s\n",
((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "",
((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "",
((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "",
((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "",
((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "",
((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "",
((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "",
((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "",
((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : "");
#endif
callout_count = 0;
errorcode = pcre2_dfa_match(code, (PCRE2_SPTR)data,
(PCRE2_SIZE)match_size, 0, match_options, match_data, match_context,
dfa_workspace, DFA_WORKSPACE_COUNT);
#ifdef STANDALONE #ifdef STANDALONE
if (errorcode >= 0) printf("Match returned %d\n", errorcode); else if (errorcode >= 0) printf("Match returned %d\n", errorcode); else
{ {
@ -210,7 +249,7 @@ for (i = 0; i < 2; i++)
match_options = save_match_options; /* Reset for the second compile */ match_options = save_match_options; /* Reset for the second compile */
pcre2_code_free(code); pcre2_code_free(code);
} }
/* Compilation failed */ /* Compilation failed */
else else
@ -253,30 +292,30 @@ for (i = 1; i < argc; i++)
size_t readsize; size_t readsize;
unsigned char *buffer; unsigned char *buffer;
FILE *f; FILE *f;
/* Handle a literal string. Copy to an exact size buffer so that checks for /* Handle a literal string. Copy to an exact size buffer so that checks for
overrunning work. */ overrunning work. */
if (argv[i][0] == '=') if (argv[i][0] == '=')
{ {
readsize = strlen(argv[i]) - 1; readsize = strlen(argv[i]) - 1;
printf("------ <Literal> ------\n"); printf("------ <Literal> ------\n");
printf("Length = %lu\n", readsize); printf("Length = %lu\n", readsize);
printf("%.*s\n", (int)readsize, argv[i]+1); printf("%.*s\n", (int)readsize, argv[i]+1);
buffer = (unsigned char *)malloc(readsize); buffer = (unsigned char *)malloc(readsize);
if (buffer == NULL) if (buffer == NULL)
printf("** Failed to allocate %lu bytes of memory\n", readsize); printf("** Failed to allocate %lu bytes of memory\n", readsize);
else else
{ {
memcpy(buffer, argv[i]+1, readsize); memcpy(buffer, argv[i]+1, readsize);
LLVMFuzzerTestOneInput(buffer, readsize); LLVMFuzzerTestOneInput(buffer, readsize);
free(buffer); free(buffer);
} }
continue; continue;
} }
/* Handle a string given in a file */ /* Handle a string given in a file */
f = fopen(argv[i], "rb"); f = fopen(argv[i], "rb");
if (f == NULL) if (f == NULL)
{ {