From 28624ecfd814856c075d55d73a8f852985b76820 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 7 May 2026 16:25:12 +0900 Subject: [PATCH] mruby-regexp: cap {n}/{n,m} quantifiers to prevent overflow parse_quantifier read digits via min = min * 10 + d with no upper bound, allowing patterns like /a{1111558833}/ to overflow int and trigger signed-integer-overflow UB. Even without UB, the value flows into compile_quantified's emit loop where it would attempt to emit a billion copies of the atom. Add RE_MAX_REPEAT = 32768 (the largest value that still fits in re_inst.offset, the uint16_t jump field) and reject quantifiers beyond that during parsing via compile_error. Apply the same cap to the max field. Reported by OSS-Fuzz (clusterfuzz testcase 6152367367323648). Co-authored-by: Claude --- mrbgems/mruby-regexp/src/re_compile.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mrbgems/mruby-regexp/src/re_compile.c b/mrbgems/mruby-regexp/src/re_compile.c index cb5c3b07d..b3571a589 100644 --- a/mrbgems/mruby-regexp/src/re_compile.c +++ b/mrbgems/mruby-regexp/src/re_compile.c @@ -264,6 +264,11 @@ compile_charclass(re_compiler *c) emit(c, negated ? RE_NCLASS : RE_CLASS, (uint8_t)id, 0); } +/* Maximum value for {n}/{n,m} quantifiers. Each unit becomes (min-1) + + (max-min) emitted copies of the inner atom; the cap keeps both the + parse free of integer overflow and the bytecode size sane. */ +#define RE_MAX_REPEAT 32768 + /* Parse {n}, {n,}, {n,m} quantifier. Returns min,max via pointers. */ static mrb_bool parse_quantifier(re_compiler *c, int *min_out, int *max_out) @@ -273,6 +278,7 @@ parse_quantifier(re_compiler *c, int *min_out, int *max_out) while (peek(c) >= '0' && peek(c) <= '9') { min = min * 10 + (next_char(c) - '0'); + if (min > RE_MAX_REPEAT) compile_error(c, "quantifier too large"); } if (peek(c) == ',') { next_char(c); @@ -280,6 +286,7 @@ parse_quantifier(re_compiler *c, int *min_out, int *max_out) max = 0; while (peek(c) >= '0' && peek(c) <= '9') { max = max * 10 + (next_char(c) - '0'); + if (max > RE_MAX_REPEAT) compile_error(c, "quantifier too large"); } } /* else max = -1 (unlimited) */