# HG changeset patch # User Paul Eggert # Date 1125701699 0 # Node ID ca2f5d46eeb695cf5764a2affd39d389ddf86b47 # Parent e7f4068da97674150194b8b5a6f300b6f21223f7 Check for arithmetic overflow when calculating sizes, to prevent some buffer-overflow issues. These patches are conservative, in the sense that when I couldn't determine whether an overflow was possible, I inserted a run-time check. * regex_internal.h (re_xmalloc, re_xrealloc, re_x2realloc): New macros. (SIZE_MAX) [!defined SIZE_MAX]: New macro. (re_alloc_oversized, re_x2alloc_oversized, re_xnmalloc): (re_xnrealloc, re_x2nrealloc): New inline functions. * lib/regcomp.c (init_dfa, analyze, build_range_exp, parse_bracket_exp): (build_equiv_class, build_charclass): Check for arithmetic overflow in size expression calculations. * lib/regex_internal.c (re_string_realloc_buffers): (build_wcs_upper_buffer, re_node_set_add_intersect): (re_node_set_init_union, re_node_set_insert, re_node_set_insert_last): (re_dfa_add_node, register_state): Likewise. * lib/regexec.c (re_search_stub, re_copy_regs, re_search_internal): (prune_impossible_nodes, push_fail_stack, set_regs, check_arrival): (build_trtable, extend_buffers, match_ctx_init, match_ctx_add_entry): (match_ctx_add_subtop, match_ctx_add_sublast): Likewise. diff --git a/config/srclist.txt b/config/srclist.txt --- a/config/srclist.txt +++ b/config/srclist.txt @@ -1,4 +1,4 @@ -# $Id: srclist.txt,v 1.100 2005-09-02 12:27:28 karl Exp $ +# $Id: srclist.txt,v 1.101 2005-09-02 22:54:59 eggert Exp $ # Files for which we are not the source. See ./srclistvars.sh for the # variable definitions. @@ -109,6 +109,7 @@ # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1281 # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1282 # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1285 +# http://sources.redhat.com/bugzilla/show_bug.cgi?id=1291 #$LIBCSRC/posix/regcomp.c lib gpl # # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1238 @@ -138,6 +139,7 @@ # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1285 # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1286 # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1287 +# http://sources.redhat.com/bugzilla/show_bug.cgi?id=1291 #$LIBCSRC/posix/regex_internal.c lib gpl # # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1054 @@ -150,6 +152,7 @@ # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1278 # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1281 # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1285 +# http://sources.redhat.com/bugzilla/show_bug.cgi?id=1291 #$LIBCSRC/posix/regex_internal.h lib gpl # # http://sources.redhat.com/bugzilla/show_bug.cgi?id=1216 diff --git a/lib/ChangeLog b/lib/ChangeLog --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,25 @@ +2005-09-02 Paul Eggert + + Check for arithmetic overflow when calculating sizes, to prevent + some buffer-overflow issues. These patches are conservative, in the + sense that when I couldn't determine whether an overflow was possible, + I inserted a run-time check. + * regex_internal.h (re_xmalloc, re_xrealloc, re_x2realloc): New macros. + (SIZE_MAX) [!defined SIZE_MAX]: New macro. + (re_alloc_oversized, re_x2alloc_oversized, re_xnmalloc): + (re_xnrealloc, re_x2nrealloc): New inline functions. + * lib/regcomp.c (init_dfa, analyze, build_range_exp, parse_bracket_exp): + (build_equiv_class, build_charclass): Check for arithmetic overflow + in size expression calculations. + * lib/regex_internal.c (re_string_realloc_buffers): + (build_wcs_upper_buffer, re_node_set_add_intersect): + (re_node_set_init_union, re_node_set_insert, re_node_set_insert_last): + (re_dfa_add_node, register_state): Likewise. + * lib/regexec.c (re_search_stub, re_copy_regs, re_search_internal): + (prune_impossible_nodes, push_fail_stack, set_regs, check_arrival): + (build_trtable, extend_buffers, match_ctx_init, match_ctx_add_entry): + (match_ctx_add_subtop, match_ctx_add_sublast): Likewise. + 2005-09-01 Paul Eggert * glob.c (GET_LOGIN_NAME_MAX): Renamed from LOGIN_NAME_MAX, diff --git a/lib/regcomp.c b/lib/regcomp.c --- a/lib/regcomp.c +++ b/lib/regcomp.c @@ -808,7 +808,7 @@ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; dfa->nodes_alloc = pat_len + 1; - dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); + dfa->nodes = re_xmalloc (re_token_t, dfa->nodes_alloc); /* table_size = 2 ^ ceil(log pat_len) */ for (table_size = 1; table_size <= pat_len; table_size <<= 1) @@ -1083,13 +1083,13 @@ /* Allocate arrays. */ dfa->nexts = re_malloc (Idx, dfa->nodes_alloc); dfa->org_indices = re_malloc (Idx, dfa->nodes_alloc); - dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); + dfa->edests = re_xmalloc (re_node_set, dfa->nodes_alloc); dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL || dfa->eclosures == NULL, 0)) return REG_ESPACE; - dfa->subexp_map = re_malloc (Idx, preg->re_nsub); + dfa->subexp_map = re_xmalloc (Idx, preg->re_nsub); if (dfa->subexp_map != NULL) { Idx i; @@ -1125,7 +1125,7 @@ if ((!preg->re_no_sub && preg->re_nsub > 0 && dfa->has_plural_match) || dfa->nbackref) { - dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len); + dfa->inveclosures = re_xmalloc (re_node_set, dfa->nodes_len); if (BE (dfa->inveclosures == NULL, 0)) return REG_ESPACE; ret = calc_inveclosure (dfa); @@ -2608,12 +2608,11 @@ wchar_t *new_array_start, *new_array_end; Idx new_nranges; - /* +1 in case of mbcset->nranges is 0. */ - new_nranges = 2 * mbcset->nranges + 1; + new_nranges = mbcset->nranges; /* Use realloc since mbcset->range_starts and mbcset->range_ends are NULL if *range_alloc == 0. */ - new_array_start = re_realloc (mbcset->range_starts, wchar_t, - new_nranges); + new_array_start = re_x2realloc (mbcset->range_starts, wchar_t, + &new_nranges); new_array_end = re_realloc (mbcset->range_ends, wchar_t, new_nranges); @@ -2840,10 +2839,9 @@ uint32_t *new_array_end; Idx new_nranges; - /* +1 in case of mbcset->nranges is 0. */ - new_nranges = 2 * mbcset->nranges + 1; - new_array_start = re_realloc (mbcset->range_starts, uint32_t, - new_nranges); + new_nranges = mbcset->nranges; + new_array_start = re_x2realloc (mbcset->range_starts, uint32_t, + &new_nranges); new_array_end = re_realloc (mbcset->range_ends, uint32_t, new_nranges); @@ -2914,12 +2912,11 @@ if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0)) { /* Not enough, realloc it. */ - /* +1 in case of mbcset->ncoll_syms is 0. */ - Idx new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1; + Idx new_coll_sym_alloc = mbcset->ncoll_syms; /* Use realloc since mbcset->coll_syms is NULL if *alloc == 0. */ - int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t, - new_coll_sym_alloc); + int32_t *new_coll_syms = re_x2realloc (mbcset->coll_syms, int32_t, + &new_coll_sym_alloc); if (BE (new_coll_syms == NULL, 0)) return REG_ESPACE; mbcset->coll_syms = new_coll_syms; @@ -3103,11 +3100,10 @@ { wchar_t *new_mbchars; /* Not enough, realloc it. */ - /* +1 in case of mbcset->nmbchars is 0. */ - mbchar_alloc = 2 * mbcset->nmbchars + 1; + mbchar_alloc = mbcset->nmbchars; /* Use realloc since array is NULL if *alloc == 0. */ - new_mbchars = re_realloc (mbcset->mbchars, wchar_t, - mbchar_alloc); + new_mbchars = re_x2realloc (mbcset->mbchars, wchar_t, + &mbchar_alloc); if (BE (new_mbchars == NULL, 0)) goto parse_bracket_exp_espace; mbcset->mbchars = new_mbchars; @@ -3381,12 +3377,11 @@ if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0)) { /* Not enough, realloc it. */ - /* +1 in case of mbcset->nequiv_classes is 0. */ - Idx new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1; + Idx new_equiv_class_alloc = mbcset->nequiv_classes; /* Use realloc since the array is NULL if *alloc == 0. */ - int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes, - int32_t, - new_equiv_class_alloc); + int32_t *new_equiv_classes = re_x2realloc (mbcset->equiv_classes, + int32_t, + &new_equiv_class_alloc); if (BE (new_equiv_classes == NULL, 0)) return REG_ESPACE; mbcset->equiv_classes = new_equiv_classes; @@ -3431,11 +3426,10 @@ if (BE (*char_class_alloc == mbcset->nchar_classes, 0)) { /* Not enough, realloc it. */ - /* +1 in case of mbcset->nchar_classes is 0. */ - Idx new_char_class_alloc = 2 * mbcset->nchar_classes + 1; + Idx new_char_class_alloc = mbcset->nchar_classes; /* Use realloc since array is NULL if *alloc == 0. */ - wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t, - new_char_class_alloc); + wctype_t *new_char_classes = re_x2realloc (mbcset->char_classes, wctype_t, + &new_char_class_alloc); if (BE (new_char_classes == NULL, 0)) return REG_ESPACE; mbcset->char_classes = new_char_classes; diff --git a/lib/regex_internal.c b/lib/regex_internal.c --- a/lib/regex_internal.c +++ b/lib/regex_internal.c @@ -132,13 +132,13 @@ #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) { - wint_t *new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); + wint_t *new_wcs = re_xrealloc (pstr->wcs, wint_t, new_buf_len); if (BE (new_wcs == NULL, 0)) return REG_ESPACE; pstr->wcs = new_wcs; if (pstr->offsets != NULL) { - Idx *new_offsets = re_realloc (pstr->offsets, Idx, new_buf_len); + Idx *new_offsets = re_xrealloc (pstr->offsets, Idx, new_buf_len); if (BE (new_offsets == NULL, 0)) return REG_ESPACE; pstr->offsets = new_offsets; @@ -392,7 +392,7 @@ if (pstr->offsets == NULL) { - pstr->offsets = re_malloc (Idx, pstr->bufs_len); + pstr->offsets = re_xmalloc (Idx, pstr->bufs_len); if (pstr->offsets == NULL) return REG_ESPACE; @@ -873,7 +873,7 @@ { set->alloc = size; set->nelem = 0; - set->elems = re_malloc (Idx, size); + set->elems = re_xmalloc (Idx, size); if (BE (set->elems == NULL, 0)) return REG_ESPACE; return REG_NOERROR; @@ -964,7 +964,12 @@ if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) { Idx new_alloc = src1->nelem + src2->nelem + dest->alloc; - Idx *new_elems = re_realloc (dest->elems, Idx, new_alloc); + Idx *new_elems; + if (sizeof (Idx) < 3 + && (new_alloc < dest->alloc + || ((Idx) (src1->nelem + src2->nelem) < src1->nelem))) + return REG_ESPACE; + new_elems = re_xrealloc (dest->elems, Idx, new_alloc); if (BE (new_elems == NULL, 0)) return REG_ESPACE; dest->elems = new_elems; @@ -1050,7 +1055,9 @@ if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) { dest->alloc = src1->nelem + src2->nelem; - dest->elems = re_malloc (Idx, dest->alloc); + if (sizeof (Idx) < 2 && dest->alloc < src1->nelem) + return REG_ESPACE; + dest->elems = re_xmalloc (Idx, dest->alloc); if (BE (dest->elems == NULL, 0)) return REG_ESPACE; } @@ -1101,10 +1108,17 @@ Idx is, id, sbase, delta; if (src == NULL || src->nelem == 0) return REG_NOERROR; + if (sizeof (Idx) < 3 + && ((Idx) (2 * src->nelem) < src->nelem + || (Idx) (2 * src->nelem + dest->nelem) < dest->nelem)) + return REG_ESPACE; if (dest->alloc < 2 * src->nelem + dest->nelem) { - Idx new_alloc = 2 * (src->nelem + dest->alloc); - Idx *new_buffer = re_realloc (dest->elems, Idx, new_alloc); + Idx new_alloc = src->nelem + dest->alloc; + Idx *new_buffer; + if (sizeof (Idx) < 4 && new_alloc < dest->alloc) + return REG_ESPACE; + new_buffer = re_x2realloc (dest->elems, Idx, &new_alloc); if (BE (new_buffer == NULL, 0)) return REG_ESPACE; dest->elems = new_buffer; @@ -1199,9 +1213,7 @@ /* Realloc if we need. */ if (set->alloc == set->nelem) { - Idx *new_elems; - set->alloc = set->alloc * 2; - new_elems = re_realloc (set->elems, Idx, set->alloc); + Idx *new_elems = re_x2realloc (set->elems, Idx, &set->alloc); if (BE (new_elems == NULL, 0)) return false; set->elems = new_elems; @@ -1239,8 +1251,7 @@ if (set->alloc == set->nelem) { Idx *new_elems; - set->alloc = (set->alloc + 1) * 2; - new_elems = re_realloc (set->elems, Idx, set->alloc); + new_elems = re_x2realloc (set->elems, Idx, &set->alloc); if (BE (new_elems == NULL, 0)) return false; set->elems = new_elems; @@ -1313,18 +1324,18 @@ int type = token.type; if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0)) { - Idx new_nodes_alloc = dfa->nodes_alloc * 2; + Idx new_nodes_alloc = dfa->nodes_alloc; Idx *new_nexts, *new_indices; re_node_set *new_edests, *new_eclosures; - re_token_t *new_nodes = re_realloc (dfa->nodes, re_token_t, - new_nodes_alloc); + re_token_t *new_nodes = re_x2realloc (dfa->nodes, re_token_t, + &new_nodes_alloc); if (BE (new_nodes == NULL, 0)) return REG_MISSING; dfa->nodes = new_nodes; new_nexts = re_realloc (dfa->nexts, Idx, new_nodes_alloc); new_indices = re_realloc (dfa->org_indices, Idx, new_nodes_alloc); - new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc); + new_edests = re_xrealloc (dfa->edests, re_node_set, new_nodes_alloc); new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc); if (BE (new_nexts == NULL || new_indices == NULL || new_edests == NULL || new_eclosures == NULL, 0)) @@ -1487,9 +1498,9 @@ spot = dfa->state_table + (hash & dfa->state_hash_mask); if (BE (spot->alloc <= spot->num, 0)) { - Idx new_alloc = 2 * spot->num + 2; - re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *, - new_alloc); + Idx new_alloc = spot->num; + re_dfastate_t **new_array = re_x2realloc (spot->array, re_dfastate_t *, + &new_alloc); if (BE (new_array == NULL, 0)) return REG_ESPACE; spot->array = new_array; diff --git a/lib/regex_internal.h b/lib/regex_internal.h --- a/lib/regex_internal.h +++ b/lib/regex_internal.h @@ -442,10 +442,70 @@ #endif #define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) +#define re_xmalloc(t,n) ((t *) re_xnmalloc (n, sizeof (t))) #define re_calloc(t,n) ((t *) calloc (n, sizeof (t))) #define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) +#define re_xrealloc(p,t,n) ((t *) re_xnrealloc (p, n, sizeof (t))) +#define re_x2realloc(p,t,pn) ((t *) re_x2nrealloc (p, pn, sizeof (t))) #define re_free(p) free (p) +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +/* Return true if an array of N objects, each of size S, cannot exist + due to size arithmetic overflow. S must be nonzero. */ +static inline bool +re_alloc_oversized (size_t n, size_t s) +{ + return BE (SIZE_MAX / s < n, 0); +} + +/* Return true if an array of (2 * N + 1) objects, each of size S, + cannot exist due to size arithmetic overflow. S must be nonzero. */ +static inline bool +re_x2alloc_oversized (size_t n, size_t s) +{ + return BE ((SIZE_MAX / s - 1) / 2 < n, 0); +} + +/* Allocate an array of N objects, each with S bytes of memory, + dynamically, with error checking. S must be nonzero. */ +static inline void * +re_xnmalloc (size_t n, size_t s) +{ + return re_alloc_oversized (n, s) ? NULL : malloc (n * s); +} + +/* Change the size of an allocated block of memory P to an array of N + objects each of S bytes, with error checking. S must be nonzero. */ +static inline void * +re_xnrealloc (void *p, size_t n, size_t s) +{ + return re_alloc_oversized (n, s) ? NULL : realloc (p, n * s); +} + +/* Reallocate a block of memory P to an array of (2 * (*PN) + 1) + objects each of S bytes, with error checking. S must be nonzero. + If the allocation is successful, set *PN to the new allocation + count and return the resulting pointer. Otherwise, return + NULL. */ +static inline void * +re_x2nrealloc (void *p, size_t *pn, size_t s) +{ + if (re_x2alloc_oversized (*pn, s)) + return NULL; + else + { + /* Add 1 in case *PN is zero. */ + size_t n1 = 2 * *pn + 1; + p = realloc (p, n1 * s); + if (BE (p != NULL, 1)) + *pn = n1; + return p; + } +} + struct bin_tree_t { struct bin_tree_t *parent; diff --git a/lib/regexec.c b/lib/regexec.c --- a/lib/regexec.c +++ b/lib/regexec.c @@ -434,7 +434,7 @@ if (regs == NULL) nregs = 1; else if (BE (bufp->re_regs_allocated == REG_FIXED - && regs->rm_num_regs < bufp->re_nsub + 1, 0)) + && regs->rm_num_regs <= bufp->re_nsub, 0)) { nregs = regs->rm_num_regs; if (BE (nregs < 1, 0)) @@ -446,7 +446,7 @@ } else nregs = bufp->re_nsub + 1; - pmatch = re_malloc (regmatch_t, nregs); + pmatch = re_xmalloc (regmatch_t, nregs); if (BE (pmatch == NULL, 0)) { rval = -2; @@ -500,7 +500,7 @@ /* Have the register data arrays been allocated? */ if (regs_allocated == REG_UNALLOCATED) { /* No. So allocate them with malloc. */ - regs->rm_start = re_malloc (regoff_t, need_regs); + regs->rm_start = re_xmalloc (regoff_t, need_regs); regs->rm_end = re_malloc (regoff_t, need_regs); if (BE (regs->rm_start == NULL, 0) || BE (regs->rm_end == NULL, 0)) return REG_UNALLOCATED; @@ -513,7 +513,7 @@ if (BE (need_regs > regs->rm_num_regs, 0)) { regoff_t *new_start = - re_realloc (regs->rm_start, regoff_t, need_regs); + re_xrealloc (regs->rm_start, regoff_t, need_regs); regoff_t *new_end = re_realloc (regs->rm_end, regoff_t, need_regs); if (BE (new_start == NULL, 0) || BE (new_end == NULL, 0)) return REG_UNALLOCATED; @@ -685,7 +685,7 @@ multi character collating element. */ if (nmatch > 1 || dfa->has_mb_node) { - mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1); + mctx.state_log = re_xmalloc (re_dfastate_t *, mctx.input.bufs_len + 1); if (BE (mctx.state_log == NULL, 0)) { err = REG_ESPACE; @@ -945,7 +945,7 @@ #endif match_last = mctx->match_last; halt_node = mctx->last_node; - sifted_states = re_malloc (re_dfastate_t *, match_last + 1); + sifted_states = re_xmalloc (re_dfastate_t *, match_last + 1); if (BE (sifted_states == NULL, 0)) { ret = REG_ESPACE; @@ -953,7 +953,7 @@ } if (dfa->nbackref) { - lim_states = re_malloc (re_dfastate_t *, match_last + 1); + lim_states = re_xmalloc (re_dfastate_t *, match_last + 1); if (BE (lim_states == NULL, 0)) { ret = REG_ESPACE; @@ -1343,15 +1343,14 @@ if (fs->num == fs->alloc) { struct re_fail_stack_ent_t *new_array = - re_realloc (fs->stack, struct re_fail_stack_ent_t, fs->alloc * 2); + re_x2realloc (fs->stack, struct re_fail_stack_ent_t, &fs->alloc); if (new_array == NULL) return REG_ESPACE; - fs->alloc *= 2; fs->stack = new_array; } fs->stack[num].idx = str_idx; fs->stack[num].node = dest_node; - fs->stack[num].regs = re_malloc (regmatch_t, nregs); + fs->stack[num].regs = re_xmalloc (regmatch_t, nregs); if (fs->stack[num].regs == NULL) return REG_ESPACE; memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); @@ -1399,7 +1398,7 @@ if (fl_backtrack) { fs = &fs_body; - fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); + fs->stack = re_xmalloc (struct re_fail_stack_ent_t, fs->alloc); if (fs->stack == NULL) return REG_ESPACE; } @@ -1409,6 +1408,11 @@ cur_node = dfa->init_node; re_node_set_init_empty (&eps_via_nodes); + if (re_alloc_oversized (nmatch, sizeof (regmatch_t))) + { + free_fail_stack_return (fs); + return REG_ESPACE; + } if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); else @@ -2872,16 +2876,16 @@ { re_dfastate_t **new_array; Idx old_alloc = path->alloc; - path->alloc += last_str + mctx->max_mb_elem_len + 1; - new_array = re_realloc (path->array, re_dfastate_t *, path->alloc); - if (new_array == NULL) - { - path->alloc = old_alloc; - return REG_ESPACE; - } + Idx new_alloc = old_alloc + last_str + mctx->max_mb_elem_len + 1; + if (BE (new_alloc < old_alloc, 0)) + return REG_ESPACE; + new_array = re_xrealloc (path->array, re_dfastate_t *, new_alloc); + if (BE (new_array == NULL, 0)) + return REG_ESPACE; path->array = new_array; + path->alloc = new_alloc; memset (new_array + old_alloc, '\0', - sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); + sizeof (re_dfastate_t *) * (new_alloc - old_alloc)); } str_idx = path->next_idx == 0 ? top_str : path->next_idx; @@ -3336,6 +3340,12 @@ if (BE (err != REG_NOERROR, 0)) goto out_free; + /* Avoid arithmetic overflow in size calculation. */ + if (BE (((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX) + / (3 * sizeof (re_dfastate_t *))) + < ndests, 0)) + goto out_free; + if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX + ndests * 3 * sizeof (re_dfastate_t *))) dest_states = (re_dfastate_t **) @@ -4057,8 +4067,8 @@ /* XXX We have no indication of the size of this buffer. If this allocation fail we have no indication that the state_log array does not have the right size. */ - re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *, - pstr->bufs_len + 1); + re_dfastate_t **new_array = re_xrealloc (mctx->state_log, re_dfastate_t *, + pstr->bufs_len + 1); if (BE (new_array == NULL, 0)) return REG_ESPACE; mctx->state_log = new_array; @@ -4106,8 +4116,8 @@ mctx->match_last = REG_MISSING; if (n > 0) { - mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n); - mctx->sub_tops = re_malloc (re_sub_match_top_t *, n); + mctx->bkref_ents = re_xmalloc (struct re_backref_cache_entry, n); + mctx->sub_tops = re_xmalloc (re_sub_match_top_t *, n); if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0)) return REG_ESPACE; } @@ -4179,8 +4189,8 @@ if (mctx->nbkref_ents >= mctx->abkref_ents) { struct re_backref_cache_entry* new_entry; - new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry, - mctx->abkref_ents * 2); + new_entry = re_x2realloc (mctx->bkref_ents, struct re_backref_cache_entry, + &mctx->abkref_ents); if (BE (new_entry == NULL, 0)) { re_free (mctx->bkref_ents); @@ -4188,8 +4198,8 @@ } mctx->bkref_ents = new_entry; memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', - sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); - mctx->abkref_ents *= 2; + (sizeof (struct re_backref_cache_entry) + * (mctx->abkref_ents - mctx->nbkref_ents))); } if (mctx->nbkref_ents > 0 && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) @@ -4253,10 +4263,10 @@ #endif if (BE (mctx->nsub_tops == mctx->asub_tops, 0)) { - Idx new_asub_tops = mctx->asub_tops * 2; - re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops, - re_sub_match_top_t *, - new_asub_tops); + Idx new_asub_tops = mctx->asub_tops; + re_sub_match_top_t **new_array = re_x2realloc (mctx->sub_tops, + re_sub_match_top_t *, + &new_asub_tops); if (BE (new_array == NULL, 0)) return REG_ESPACE; mctx->sub_tops = new_array; @@ -4280,10 +4290,10 @@ re_sub_match_last_t *new_entry; if (BE (subtop->nlasts == subtop->alasts, 0)) { - Idx new_alasts = 2 * subtop->alasts + 1; - re_sub_match_last_t **new_array = re_realloc (subtop->lasts, - re_sub_match_last_t *, - new_alasts); + Idx new_alasts = subtop->alasts; + re_sub_match_last_t **new_array = re_x2realloc (subtop->lasts, + re_sub_match_last_t *, + &new_alasts); if (BE (new_array == NULL, 0)) return NULL; subtop->lasts = new_array;