commit 3f437f2

Michael Forney  ·  2026-10-21 22:36:05 +0000 UTC
parent bf43ad0
musl: Add patch fixing CVE-2026-107891
2 files changed,  +168, -1
+167, -0
  1@@ -0,0 +1,167 @@
  2+From 9e4e95f87cdddc9082e33db204c2534b59acde58 Mon Sep 17 00:00:00 2001
  3+From: Szabolcs Nagy <nsz@port70.net>
  4+Date: Thu, 23 Apr 2026 21:22:18 +0000
  5+Subject: [PATCH] regex: avoid int overflow in regcomp
  6+
  7+regcomp has many int arith ops that may overflow. before tre_expand_ast
  8+int values are limited by 2x the input length n, e.g.:
  9+
 10+  input ERE        int field    max value
 11+  aaaaaaaaaaaa...  position     n
 12+  ()()()()()()...  submatch_id  n/2+1
 13+  ()||||||||||...  num_tags     2n-3
 14+
 15+so overflow before expand requires large n (and a lot of memory). later
 16+some values can become big due to repetitions:
 17+
 18+  input ERE                     int field that overflows
 19+  (((a{255}){255}){255}){255}   position
 20+  ((a|b*){255,}){255,}          num_transitions
 21+
 22+num_transitions and memory use can be big without {k,} repetitions too:
 23+
 24+  input ERE        what             max value
 25+  (a|a|a|a...|a)*  num_transitions  n^2/4
 26+  (()|a|a|...|a)*  sum tnfa tags    > n^3/16 - n^2
 27+
 28+so memory can run out quickly as n grows (with 31bit va space 1700 long
 29+input is enough even without {k,}) about half is tnfa and half is ast
 30+firstpos/lastpos data. but overflow can happen before allocations fail.
 31+
 32+fix early overflow by limiting n. the stack usage is in [n,11n] without
 33+repetitions, usually 7n, so the stack limit got adjusted too. the limit
 34+is such that almost all inputs that worked before still work.
 35+
 36+overflows during and after expand are fixed by explicit checks via a
 37+check_add helper and xcalloc instead of xmalloc.
 38+---
 39+ src/regex/regcomp.c | 41 +++++++++++++++++++++++++++++++++++------
 40+ 1 file changed, 35 insertions(+), 6 deletions(-)
 41+
 42+diff --git a/src/regex/regcomp.c b/src/regex/regcomp.c
 43+index b4b81968..a7115b12 100644
 44+--- a/src/regex/regcomp.c
 45++++ b/src/regex/regcomp.c
 46+@@ -1680,6 +1680,12 @@ tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree,
 47+   AST to TNFA compilation routines.
 48+ */
 49+ 
 50++/* check if a+b overflows for a,b in [0,INT_MAX] */
 51++static int check_add(unsigned a, unsigned b)
 52++{
 53++	return a + b > INT_MAX;
 54++}
 55++
 56+ typedef enum {
 57+   COPY_RECURSE,
 58+   COPY_SET_RESULT_PTR
 59+@@ -1731,6 +1737,8 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
 60+ 		    /* XXX - e.g. [ab] has only one position but two
 61+ 		       nodes, so we are creating holes in the state space
 62+ 		       here.  Not fatal, just wastes memory. */
 63++		    if (check_add(pos, *pos_add))
 64++		      return REG_ESPACE;
 65+ 		    pos += *pos_add;
 66+ 		    num_copied++;
 67+ 		  }
 68+@@ -1826,6 +1834,8 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
 69+ 	  break;
 70+ 	}
 71+     }
 72++  if (check_add(*pos_add, num_copied))
 73++    return REG_ESPACE;
 74+   *pos_add += num_copied;
 75+   return status;
 76+ }
 77+@@ -1870,6 +1880,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
 78+ 		tre_literal_t *lit= node->obj;
 79+ 		if (!IS_SPECIAL(lit) || IS_BACKREF(lit))
 80+ 		  {
 81++		    if (check_add(lit->position, pos_add))
 82++		      return REG_ESPACE;
 83+ 		    lit->position += pos_add;
 84+ 		    if (lit->position > max_pos)
 85+ 		      max_pos = lit->position;
 86+@@ -1998,6 +2010,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
 87+ 	      }
 88+ 
 89+ 	    iter_depth--;
 90++	    if (check_add(pos_add_total, pos_add - pos_add_last))
 91++	      return REG_ESPACE;
 92+ 	    pos_add_total += pos_add - pos_add_last;
 93+ 	    if (iter_depth == 0)
 94+ 	      pos_add = pos_add_total;
 95+@@ -2010,6 +2024,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
 96+ 	}
 97+     }
 98+ 
 99++  if (check_add(*position, pos_add_total))
100++    return REG_ESPACE;
101+   *position += pos_add_total;
102+ 
103+   /* `max_pos' should never be larger than `*position' if the above
104+@@ -2711,9 +2727,19 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
105+   /* Parse context. */
106+   tre_parse_ctx_t parse_ctx;
107+ 
108++  /* Limits: before tre_expand_ast, int values like position, subid or
109++   * num_tags are bounded by 2x input length, used stack entries are
110++   * bounded by 16x input length. input length is checked upfront to
111++   * avoid overflows before expand. later, values that can grow big are
112++   * bounds checked via check_add and xcalloc. */
113++  const int input_limit = 1024000;
114++  const int stack_limit = 8*input_limit;
115++  if (strnlen(regex, input_limit) >= input_limit)
116++    return REG_ESPACE;
117++
118+   /* Allocate a stack used throughout the compilation process for various
119+      purposes. */
120+-  stack = tre_stack_new(512, 1024000, 128);
121++  stack = tre_stack_new(512, stack_limit, 128);
122+   if (!stack)
123+     return REG_ESPACE;
124+   /* Allocate a fast memory allocator. */
125+@@ -2801,9 +2827,12 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
126+ 	   for example "a*" or "ab*".	Figure out a simple way to detect
127+ 	   this possibility. */
128+   tmp_ast_l = tree;
129+-  tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position++);
130++  tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position);
131+   if (tmp_ast_r == NULL)
132+     ERROR_EXIT(REG_ESPACE);
133++  if (check_add(parse_ctx.position, 1))
134++    ERROR_EXIT(REG_ESPACE);
135++  parse_ctx.position++;
136+ 
137+   tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r);
138+   if (tree == NULL)
139+@@ -2813,22 +2842,22 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
140+   if (errcode != REG_OK)
141+     ERROR_EXIT(errcode);
142+ 
143+-  counts = xmalloc(sizeof(int) * parse_ctx.position);
144++  counts = xcalloc(sizeof(int), parse_ctx.position);
145+   if (counts == NULL)
146+     ERROR_EXIT(REG_ESPACE);
147+ 
148+-  offs = xmalloc(sizeof(int) * parse_ctx.position);
149++  offs = xcalloc(sizeof(int), parse_ctx.position);
150+   if (offs == NULL)
151+     ERROR_EXIT(REG_ESPACE);
152+ 
153+-  for (i = 0; i < parse_ctx.position; i++)
154+-    counts[i] = 0;
155+   tre_ast_to_tnfa(tree, NULL, counts, NULL);
156+ 
157+   add = 0;
158+   for (i = 0; i < parse_ctx.position; i++)
159+     {
160+       offs[i] = add;
161++      if (check_add(add, counts[i] + 1))
162++        ERROR_EXIT(REG_ESPACE);
163+       add += counts[i] + 1;
164+       counts[i] = 0;
165+     }
166+-- 
167+2.54.0
168+
+1, -1
1@@ -1 +1 @@
2-1.2.6 r1
3+1.2.6 r2