Skip to content

Commit

Permalink
avoid LIMIT_HEAP truncation because of multiplication integer overflow
Browse files Browse the repository at this point in the history
If a LIMIT_HEAP value once converted to bytes is larger than UINT_MAX
would result in a bogus setting that could trigger a matching failure
as shown by the following:

  PCRE2 version 10.42 2022-12-11
    re> /(*LIMIT_HEAP=4194304)a/
  data> a
  Failed: error -63: heap limit exceeded

Remove the multiplication and instead keep track of the maximum heap
allowed in KB as was done originally.

Aditionally, add a check to avoid overflowing a PCRE2_SIZE while
doubling the heap used and that could result in a crash (mostly on
systems with a 32-bit PCRE2_SIZE with non standard settings).

Fixes: d90fb23 (Refactor match_data() to always use the heap instead
       of having an initial frames vector on the stack..., 2022-07-27)
Closes: PCRE2Project#183
  • Loading branch information
carenas committed Jan 1, 2023
1 parent 0746b3d commit 636f05e
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/pcre2_intmodedep.h
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ doing traditional NFA matching (pcre2_match() and friends). */

typedef struct match_block {
pcre2_memctl memctl; /* For general use */
PCRE2_SIZE heap_limit; /* As it says */
uint32_t heap_limit; /* As it says */
uint32_t match_limit; /* As it says */
uint32_t match_limit_depth; /* As it says */
uint32_t match_call_count; /* Number of times a new frame is created */
Expand Down Expand Up @@ -911,7 +911,7 @@ typedef struct dfa_match_block {
PCRE2_SPTR last_used_ptr; /* Latest consulted character */
const uint8_t *tables; /* Character tables */
PCRE2_SIZE start_offset; /* The start offset value */
PCRE2_SIZE heap_limit; /* As it says */
uint32_t heap_limit; /* As it says */
PCRE2_SIZE heap_used; /* As it says */
uint32_t match_limit; /* As it says */
uint32_t match_limit_depth; /* As it says */
Expand Down
34 changes: 25 additions & 9 deletions src/pcre2_match.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,13 +665,28 @@ N = (heapframe *)((char *)F + frame_size);
if (N >= frames_top)
{
heapframe *new;
PCRE2_SIZE newsize = match_data->heapframes_size * 2;
PCRE2_SIZE newsize;

if (newsize > mb->heap_limit)
if (match_data->heapframes_size >= PCRE2_SIZE_MAX / 2)
{
PCRE2_SIZE maxsize = (mb->heap_limit/frame_size) * frame_size;
if (match_data->heapframes_size >= maxsize) return PCRE2_ERROR_HEAPLIMIT;
newsize = maxsize;
if (match_data->heapframes_size == PCRE2_SIZE_MAX - 1)
return PCRE2_ERROR_HEAPLIMIT;
newsize = PCRE2_SIZE_MAX - 1;
}
else
newsize = match_data->heapframes_size * 2;

if (newsize / 1024 >= mb->heap_limit)
{
PCRE2_SIZE old_size = match_data->heapframes_size / 1024;
if (mb->heap_limit <= old_size) return PCRE2_ERROR_HEAPLIMIT;
else
{
PCRE2_SIZE max_size = frame_size * ((1024 *
(mb->heap_limit - old_size)) / frame_size);
if (max_size <= frame_size) return PCRE2_ERROR_HEAPLIMIT;
newsize = match_data->heapframes_size + max_size;
}
}

new = match_data->memctl.malloc(newsize, match_data->memctl.memory_data);
Expand Down Expand Up @@ -6816,7 +6831,7 @@ frame_size = (offsetof(heapframe, ovector) +
smaller. */

mb->heap_limit = ((mcontext->heap_limit < re->limit_heap)?
mcontext->heap_limit : re->limit_heap) * 1024;
mcontext->heap_limit : re->limit_heap);

mb->match_limit = (mcontext->match_limit < re->limit_match)?
mcontext->match_limit : re->limit_match;
Expand All @@ -6832,10 +6847,11 @@ the size to a multiple of the frame size. */

heapframes_size = frame_size * 10;
if (heapframes_size < START_FRAMES_SIZE) heapframes_size = START_FRAMES_SIZE;
if (heapframes_size > mb->heap_limit)
if (heapframes_size / 1024 >= mb->heap_limit)
{
if (frame_size > mb->heap_limit ) return PCRE2_ERROR_HEAPLIMIT;
heapframes_size = mb->heap_limit;
PCRE2_SIZE max_size = frame_size * ((1024 * mb->heap_limit)/frame_size);
if (max_size <= frame_size) return PCRE2_ERROR_HEAPLIMIT;
heapframes_size = max_size;
}

/* If an existing frame vector in the match_data block is large enough, we can
Expand Down

0 comments on commit 636f05e

Please sign in to comment.