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
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