Skip to content

Commit 7f82c12

Browse files
authored
Reject pathological regular expressions (#1222)
Fixes CVE-2025-62495. Fixes: #1221
1 parent 307a59f commit 7f82c12

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

libregexp.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,13 @@ static int re_parse_out_of_memory(REParseState *s)
391391
return re_parse_error(s, "out of memory");
392392
}
393393

394+
static int lre_check_size(REParseState *s)
395+
{
396+
if (s->byte_code.size < 64*1024*1024)
397+
return 0;
398+
return re_parse_out_of_memory(s);
399+
}
400+
394401
/* If allow_overflow is false, return -1 in case of
395402
overflow. Otherwise return INT32_MAX. */
396403
static int parse_digits(const uint8_t **pp, bool allow_overflow)
@@ -1176,6 +1183,8 @@ static int re_parse_term(REParseState *s, bool is_backward_dir)
11761183
bool greedy, add_zero_advance_check, is_neg, is_backward_lookahead;
11771184
CharRange cr_s, *cr = &cr_s;
11781185

1186+
if (lre_check_size(s))
1187+
return -1;
11791188
last_atom_start = -1;
11801189
last_capture_count = 0;
11811190
p = s->buf_ptr;
@@ -1667,6 +1676,8 @@ static int re_parse_alternative(REParseState *s, bool is_backward_dir)
16671676
int ret;
16681677
size_t start, term_start, end, term_size;
16691678

1679+
if (lre_check_size(s))
1680+
return -1;
16701681
start = s->byte_code.size;
16711682
for(;;) {
16721683
p = s->buf_ptr;
@@ -1701,7 +1712,8 @@ static int re_parse_disjunction(REParseState *s, bool is_backward_dir)
17011712

17021713
if (lre_check_stack_overflow(s->opaque, 0))
17031714
return re_parse_error(s, "stack overflow");
1704-
1715+
if (lre_check_size(s))
1716+
return -1;
17051717
start = s->byte_code.size;
17061718
if (re_parse_alternative(s, is_backward_dir))
17071719
return -1;

tests/bug1221.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {assert} from "./assert.js"
2+
3+
let caught = 0
4+
for (let i = 1; i <= 32; i++) {
5+
const prefix = "(:?".repeat(i)
6+
const suffix = "|)+".repeat(i)
7+
const between = "(?:a|)+"
8+
try {
9+
new RegExp(prefix + between + suffix)
10+
} catch (e) {
11+
assert(e instanceof SyntaxError)
12+
assert(e.message, "out of memory")
13+
caught++
14+
}
15+
}
16+
assert(caught, 12) // subject to change

0 commit comments

Comments
 (0)