Skip to content

Commit c39d352

Browse files
committed
avoid LIMIT_HEAP integer multiplication wrap around
If a LIMIT_HEAP value once converted to bytes is larger than UINT_MAX would result in a bogus valueg 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 (only on systems with a 32-bit PCRE2_SIZE and using non standard settings). Unlike the original, this code avoids rounding the heapframes_size to the frame_size at the allocation time, which simplifies the logic and wasn't really needed. Fixes: d90fb23 (Refactor match_data() to always use the heap instead of having an initial frames vector on the stack..., 2022-07-27) Closes: #183
1 parent 0746b3d commit c39d352

File tree

2 files changed

+29
-13
lines changed

2 files changed

+29
-13
lines changed

src/pcre2_intmodedep.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ doing traditional NFA matching (pcre2_match() and friends). */
858858

859859
typedef struct match_block {
860860
pcre2_memctl memctl; /* For general use */
861-
PCRE2_SIZE heap_limit; /* As it says */
861+
uint32_t heap_limit; /* As it says */
862862
uint32_t match_limit; /* As it says */
863863
uint32_t match_limit_depth; /* As it says */
864864
uint32_t match_call_count; /* Number of times a new frame is created */
@@ -911,7 +911,7 @@ typedef struct dfa_match_block {
911911
PCRE2_SPTR last_used_ptr; /* Latest consulted character */
912912
const uint8_t *tables; /* Character tables */
913913
PCRE2_SIZE start_offset; /* The start offset value */
914-
PCRE2_SIZE heap_limit; /* As it says */
914+
uint32_t heap_limit; /* As it says */
915915
PCRE2_SIZE heap_used; /* As it says */
916916
uint32_t match_limit; /* As it says */
917917
uint32_t match_limit_depth; /* As it says */

src/pcre2_match.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -665,13 +665,28 @@ N = (heapframe *)((char *)F + frame_size);
665665
if (N >= frames_top)
666666
{
667667
heapframe *new;
668-
PCRE2_SIZE newsize = match_data->heapframes_size * 2;
668+
PCRE2_SIZE newsize;
669669

670-
if (newsize > mb->heap_limit)
670+
if (match_data->heapframes_size >= PCRE2_SIZE_MAX / 2)
671671
{
672-
PCRE2_SIZE maxsize = (mb->heap_limit/frame_size) * frame_size;
673-
if (match_data->heapframes_size >= maxsize) return PCRE2_ERROR_HEAPLIMIT;
674-
newsize = maxsize;
672+
if (match_data->heapframes_size == PCRE2_SIZE_MAX - 1)
673+
return PCRE2_ERROR_NOMEMORY;
674+
newsize = PCRE2_SIZE_MAX - 1;
675+
}
676+
else
677+
newsize = match_data->heapframes_size * 2;
678+
679+
if (newsize / 1024 >= mb->heap_limit)
680+
{
681+
PCRE2_SIZE old_size = match_data->heapframes_size / 1024;
682+
if (mb->heap_limit <= old_size) return PCRE2_ERROR_HEAPLIMIT;
683+
else
684+
{
685+
PCRE2_SIZE max_delta = 1024 * (mb->heap_limit - old_size);
686+
int over_bytes = match_data->heapframes_size % 1024;
687+
if (over_bytes) max_delta -= (1024 - over_bytes);
688+
newsize = match_data->heapframes_size + max_delta;
689+
}
675690
}
676691

677692
new = match_data->memctl.malloc(newsize, match_data->memctl.memory_data);
@@ -6801,7 +6816,7 @@ the pattern. It is not used at all if there are no capturing parentheses.
68016816
68026817
frame_size is the total size of each frame
68036818
match_data->heapframes is the pointer to the frames vector
6804-
match_data->heapframes_size is the total size of the vector
6819+
match_data->heapframes_size is the allocated size of the vector
68056820
68066821
We must pad the frame_size for alignment to ensure subsequent frames are as
68076822
aligned as heapframe. Whilst ovector is word-aligned due to being a PCRE2_SIZE
@@ -6816,7 +6831,7 @@ frame_size = (offsetof(heapframe, ovector) +
68166831
smaller. */
68176832

68186833
mb->heap_limit = ((mcontext->heap_limit < re->limit_heap)?
6819-
mcontext->heap_limit : re->limit_heap) * 1024;
6834+
mcontext->heap_limit : re->limit_heap);
68206835

68216836
mb->match_limit = (mcontext->match_limit < re->limit_match)?
68226837
mcontext->match_limit : re->limit_match;
@@ -6832,14 +6847,15 @@ the size to a multiple of the frame size. */
68326847

68336848
heapframes_size = frame_size * 10;
68346849
if (heapframes_size < START_FRAMES_SIZE) heapframes_size = START_FRAMES_SIZE;
6835-
if (heapframes_size > mb->heap_limit)
6850+
if (heapframes_size / 1024 > mb->heap_limit)
68366851
{
6837-
if (frame_size > mb->heap_limit ) return PCRE2_ERROR_HEAPLIMIT;
6838-
heapframes_size = mb->heap_limit;
6852+
PCRE2_SIZE max_size = 1024 * mb->heap_limit;
6853+
if (max_size < frame_size) return PCRE2_ERROR_HEAPLIMIT;
6854+
heapframes_size = max_size;
68396855
}
68406856

68416857
/* If an existing frame vector in the match_data block is large enough, we can
6842-
use it.Otherwise, free any pre-existing vector and get a new one. */
6858+
use it. Otherwise, free any pre-existing vector and get a new one. */
68436859

68446860
if (match_data->heapframes_size < heapframes_size)
68456861
{

0 commit comments

Comments
 (0)