diff lib/regexec.c @ 6206:ca2f5d46eeb6

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.
author Paul Eggert <eggert@cs.ucla.edu>
date Fri, 02 Sep 2005 22:54:59 +0000 (2005-09-02)
parents 25eaa608fc4e
children afb93b90dcb8
line wrap: on
line diff
--- 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;