Skip to content

Commit cc6c84d

Browse files
NWilsoncarenas
andauthored
Add fix and tests for callback enumerate (#801)
This is a bug in PCRE2 10.45 and 10.46, not present in 10.44 and earlier. The bug is that applications using pcre2_callout_enumerate() will crash badly on patterns with Unicode (ie non-ASCII) character classes. There is an out-of-bounds read of arbitrary length, including misinterpreting the bytes as offsets, allowing the read to jump forwards in memory to pretty much anywhere. Applications which call pcre2_callout_enumerate should potentially downgrade to PCRE2 10.44 until we release an update of PCRE2 with the fix. Since this function is (clearly!!) not used often by applications, I am not currently treating this as very high severity. There is no way for an attacker to make any application call this function, if it is not currently using it. The root cause seems to be commit 24f9d8d (#540). --------- Co-authored-by: Carlo Marcelo Arenas Belón <[email protected]>
1 parent 4d3b779 commit cc6c84d

File tree

3 files changed

+24
-30
lines changed

3 files changed

+24
-30
lines changed

src/pcre2_pattern_info.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,7 @@ if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
289289
if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
290290

291291
cb.version = 0;
292-
cc = (PCRE2_SPTR)((const uint8_t *)re + sizeof(pcre2_real_code))
293-
+ re->name_count * re->name_entry_size;
292+
cc = (PCRE2_SPTR)((uint8_t *)re + re->code_start);
294293

295294
while (TRUE)
296295
{

src/pcre2test.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,6 @@ so many of them that they are split into two fields. */
558558
/* Combinations */
559559

560560
#define CTL_DEBUG (CTL_FULLBINCODE|CTL_INFO) /* For setting */
561-
#define CTL_ANYINFO (CTL_DEBUG|CTL_BINCODE|CTL_CALLOUT_INFO)
562561
#define CTL_ANYGLOB (CTL_ALTGLOBAL|CTL_GLOBAL)
563562

564563
/* Second control word */

src/pcre2test_inc.h

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,9 +1258,16 @@ Returns: PR_OK continue processing next line
12581258
static int
12591259
show_pattern_info(void)
12601260
{
1261+
int rc;
12611262
uint32_t compile_options, overall_options, extra_options;
12621263
BOOL utf = (compiled_code->overall_options & PCRE2_UTF) != 0;
12631264

1265+
if ((pat_patctl.control & CTL_MEMORY) != 0)
1266+
show_memory_info();
1267+
1268+
if ((pat_patctl.control2 & CTL2_FRAMESIZE) != 0)
1269+
show_framesize();
1270+
12641271
if ((pat_patctl.control & (CTL_BINCODE|CTL_FULLBINCODE)) != 0)
12651272
{
12661273
fprintf(outfile, "------------------------------------------------------------------\n");
@@ -1586,17 +1593,17 @@ if ((pat_patctl.control & CTL_INFO) != 0)
15861593
}
15871594
}
15881595

1589-
if ((pat_patctl.control & CTL_CALLOUT_INFO) != 0)
1596+
rc = pcre2_callout_enumerate(compiled_code,
1597+
((pat_patctl.control & CTL_CALLOUT_INFO) != 0)? callout_enumerate_function :
1598+
/* Exercise the callout enumeration code with a dummy callback to make sure
1599+
it works. */
1600+
callout_enumerate_function_void, NULL);
1601+
if (rc != 0)
15901602
{
1591-
int errorcode = pcre2_callout_enumerate(compiled_code,
1592-
callout_enumerate_function, NULL);
1593-
if (errorcode != 0)
1594-
{
1595-
fprintf(outfile, "Callout enumerate failed: error %d: ", errorcode);
1596-
if (errorcode < 0 && !print_error_message(errorcode, "", "\n"))
1597-
return PR_ABEND;
1598-
return PR_SKIP;
1599-
}
1603+
fprintf(outfile, "Callout enumerate failed: error %d: ", rc);
1604+
if (rc < 0 && !print_error_message(rc, "", "\n"))
1605+
return PR_ABEND;
1606+
return PR_SKIP;
16001607
}
16011608

16021609
return PR_OK;
@@ -1763,13 +1770,9 @@ switch(cmd)
17631770
{
17641771
jitrc = pcre2_jit_compile(compiled_code, pat_patctl.jit);
17651772
}
1766-
if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
1767-
if ((pat_patctl.control2 & CTL2_FRAMESIZE) != 0) show_framesize();
1768-
if ((pat_patctl.control & CTL_ANYINFO) != 0)
1769-
{
1770-
rc = show_pattern_info();
1771-
if (rc != PR_OK) return rc;
1772-
}
1773+
1774+
rc = show_pattern_info();
1775+
if (rc != PR_OK) return rc;
17731776
break;
17741777

17751778
/* Save the stack of compiled patterns to a file, then empty the stack. */
@@ -1979,7 +1982,7 @@ BOOL utf;
19791982
uint32_t k;
19801983
uint8_t *p = buffer;
19811984
unsigned int delimiter = *p++;
1982-
int errorcode;
1985+
int rc, errorcode;
19831986
pcre2_compile_context *use_pat_context;
19841987
PCRE2_SPTR use_pbuffer = NULL;
19851988
uint32_t use_forbid_utf = forbid_utf;
@@ -2313,7 +2316,6 @@ if ((pat_patctl.control & CTL_POSIX) != 0)
23132316
return PR_SKIP;
23142317

23152318
#else
2316-
int rc;
23172319
int cflags = 0;
23182320
const char *msg = "** Ignored with POSIX interface:";
23192321

@@ -2523,7 +2525,6 @@ ends up back in the usual place. */
25232525

25242526
if (pat_patctl.convert_type != CONVERT_UNSET)
25252527
{
2526-
int rc;
25272528
int convert_return = PR_OK;
25282529
uint32_t convert_options = pat_patctl.convert_type;
25292530
PCRE2_UCHAR *converted_pattern;
@@ -2918,13 +2919,8 @@ if ((pat_patctl.control2 & CTL2_NL_SET) != 0)
29182919

29192920
/* Output code size and other information if requested. */
29202921

2921-
if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
2922-
if ((pat_patctl.control2 & CTL2_FRAMESIZE) != 0) show_framesize();
2923-
if ((pat_patctl.control & CTL_ANYINFO) != 0)
2924-
{
2925-
int rc = show_pattern_info();
2926-
if (rc != PR_OK) return rc;
2927-
}
2922+
rc = show_pattern_info();
2923+
if (rc != PR_OK) return rc;
29282924

29292925
/* The "push" control requests that the compiled pattern be remembered on a
29302926
stack. This is mainly for testing the serialization functionality. */

0 commit comments

Comments
 (0)