Skip to content

Commit 39c3fd6

Browse files
NWilsoncarenas
andcommitted
Add fix and tests for callback enumerate (#801)
Cherry-pick of commit cc6c84d. 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 b2bd425 commit 39c3fd6

File tree

2 files changed

+34
-30
lines changed

2 files changed

+34
-30
lines changed

src/pcre2_pattern_info.c

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

294294
cb.version = 0;
295-
cc = (PCRE2_SPTR)((const uint8_t *)re + sizeof(pcre2_real_code))
296-
+ re->name_count * re->name_entry_size;
295+
cc = (PCRE2_SPTR)((uint8_t *)re + re->code_start);
297296

298297
while (TRUE)
299298
{

src/pcre2test.c

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,6 @@ so many of them that they are split into two fields. */
512512
/* Combinations */
513513

514514
#define CTL_DEBUG (CTL_FULLBINCODE|CTL_INFO) /* For setting */
515-
#define CTL_ANYINFO (CTL_DEBUG|CTL_BINCODE|CTL_CALLOUT_INFO)
516515
#define CTL_ANYGLOB (CTL_ALTGLOBAL|CTL_GLOBAL)
517516

518517
/* Second control word */
@@ -4652,6 +4651,16 @@ fprintf(outfile, "%.*s\n",
46524651
return 0;
46534652
}
46544653

4654+
/* Backport from 10.47 */
4655+
4656+
static int callout_enumerate_function_void(pcre2_callout_enumerate_block_8 *cb,
4657+
void *callout_data)
4658+
{
4659+
(void)cb;
4660+
(void)callout_data;
4661+
return 0;
4662+
}
4663+
46554664

46564665

46574666
/*************************************************
@@ -4671,9 +4680,16 @@ Returns: PR_OK continue processing next line
46714680
static int
46724681
show_pattern_info(void)
46734682
{
4683+
int rc;
46744684
uint32_t compile_options, overall_options, extra_options;
46754685
BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
46764686

4687+
if ((pat_patctl.control & CTL_MEMORY) != 0)
4688+
show_memory_info();
4689+
4690+
if ((pat_patctl.control2 & CTL2_FRAMESIZE) != 0)
4691+
show_framesize();
4692+
46774693
if ((pat_patctl.control & (CTL_BINCODE|CTL_FULLBINCODE)) != 0)
46784694
{
46794695
fprintf(outfile, "------------------------------------------------------------------\n");
@@ -5016,17 +5032,17 @@ if ((pat_patctl.control & CTL_INFO) != 0)
50165032
}
50175033
}
50185034

5019-
if ((pat_patctl.control & CTL_CALLOUT_INFO) != 0)
5035+
PCRE2_CALLOUT_ENUMERATE(rc,
5036+
(((pat_patctl.control & CTL_CALLOUT_INFO) != 0)? callout_callback :
5037+
/* Exercise the callout enumeration code with a dummy callback to make sure
5038+
it works. */
5039+
callout_enumerate_function_void), 0);
5040+
if (rc != 0)
50205041
{
5021-
int errorcode;
5022-
PCRE2_CALLOUT_ENUMERATE(errorcode, callout_callback, 0);
5023-
if (errorcode != 0)
5024-
{
5025-
fprintf(outfile, "Callout enumerate failed: error %d: ", errorcode);
5026-
if (errorcode < 0 && !print_error_message(errorcode, "", "\n"))
5027-
return PR_ABEND;
5028-
return PR_SKIP;
5029-
}
5042+
fprintf(outfile, "Callout enumerate failed: error %d: ", rc);
5043+
if (rc < 0 && !print_error_message(rc, "", "\n"))
5044+
return PR_ABEND;
5045+
return PR_SKIP;
50305046
}
50315047

50325048
return PR_OK;
@@ -5230,13 +5246,9 @@ switch(cmd)
52305246
{
52315247
PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
52325248
}
5233-
if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
5234-
if ((pat_patctl.control2 & CTL2_FRAMESIZE) != 0) show_framesize();
5235-
if ((pat_patctl.control & CTL_ANYINFO) != 0)
5236-
{
5237-
rc = show_pattern_info();
5238-
if (rc != PR_OK) return rc;
5239-
}
5249+
5250+
rc = show_pattern_info();
5251+
if (rc != PR_OK) return rc;
52405252
break;
52415253

52425254
/* Save the stack of compiled patterns to a file, then empty the stack. */
@@ -5395,7 +5407,7 @@ BOOL utf;
53955407
uint32_t k;
53965408
uint8_t *p = buffer;
53975409
unsigned int delimiter = *p++;
5398-
int errorcode;
5410+
int rc, errorcode;
53995411
void *use_pat_context;
54005412
void *use_pbuffer = NULL;
54015413
uint32_t use_forbid_utf = forbid_utf;
@@ -5724,7 +5736,6 @@ local character tables. Neither does it have 16-bit or 32-bit support. */
57245736
if ((pat_patctl.control & CTL_POSIX) != 0)
57255737
{
57265738
#ifdef SUPPORT_PCRE2_8
5727-
int rc;
57285739
int cflags = 0;
57295740
const char *msg = "** Ignored with POSIX interface:";
57305741
#endif
@@ -5931,7 +5942,6 @@ ends up back in the usual place. */
59315942

59325943
if (pat_patctl.convert_type != CONVERT_UNSET)
59335944
{
5934-
int rc;
59355945
int convert_return = PR_OK;
59365946
uint32_t convert_options = pat_patctl.convert_type;
59375947
void *converted_pattern;
@@ -6246,13 +6256,8 @@ if ((pat_patctl.control2 & CTL2_NL_SET) != 0)
62466256

62476257
/* Output code size and other information if requested. */
62486258

6249-
if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
6250-
if ((pat_patctl.control2 & CTL2_FRAMESIZE) != 0) show_framesize();
6251-
if ((pat_patctl.control & CTL_ANYINFO) != 0)
6252-
{
6253-
int rc = show_pattern_info();
6254-
if (rc != PR_OK) return rc;
6255-
}
6259+
rc = show_pattern_info();
6260+
if (rc != PR_OK) return rc;
62566261

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

0 commit comments

Comments
 (0)