Skip to content

Commit dbf5653

Browse files
srt32Copilot
andcommitted
Backport regexp repeat and null-check ID overflow guards
Backport ruby/ruby@493d26d for CVE-2026-110264. Reject excessive range-repeat and null-check counts before their IDs wrap, retaining the existing downstream fixes. Cover the accepted 32767-count boundary and rejection at 32768 and 100000 with diagnostic assertions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 286bedb commit dbf5653

4 files changed

Lines changed: 28 additions & 0 deletions

File tree

‎include/ruby/onigmo.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,8 @@ ONIG_EXTERN const OnigSyntaxType* OnigDefaultSyntax;
687687
#define ONIGERR_NEVER_ENDING_RECURSION -221
688688
#define ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY -222
689689
#define ONIGERR_INVALID_CHAR_PROPERTY_NAME -223
690+
#define ONIGERR_TOO_MANY_RANGE_REPEAT -224
691+
#define ONIGERR_TOO_MANY_NULL_CHECK -225
690692
#define ONIGERR_TOO_BIG_COMPILED_PROGRAM -226
691693
#define ONIGERR_INVALID_CODE_POINT_VALUE -400
692694
#define ONIGERR_INVALID_WIDE_CHAR_VALUE -400

‎regcomp.c‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ compile_tree_empty_check(Node* node, regex_t* reg, int empty_info)
398398
r = add_mem_num(reg, reg->num_null_check); /* NULL CHECK ID */
399399
if (r) return r;
400400
reg->num_null_check++;
401+
if ((MemNumType)reg->num_null_check <= 0) return ONIGERR_TOO_MANY_NULL_CHECK;
401402
}
402403

403404
r = compile_tree(node, reg);
@@ -707,6 +708,7 @@ compile_range_repeat_node(QtfrNode* qn, int target_len, int empty_info,
707708
if (r) return r;
708709
r = add_mem_num(reg, num_repeat); /* OP_REPEAT ID */
709710
reg->num_repeat++;
711+
if ((MemNumType)reg->num_repeat <= 0) return ONIGERR_TOO_MANY_RANGE_REPEAT;
710712
if (r) return r;
711713
r = add_rel_addr(reg, target_len + SIZE_OP_REPEAT_INC);
712714
if (r) return r;

‎regerror.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ onig_error_code_to_format(OnigPosition code)
165165
p = "group number is too big for capture history"; break;
166166
case ONIGERR_INVALID_CHAR_PROPERTY_NAME:
167167
p = "invalid character property name {%n}"; break;
168+
case ONIGERR_TOO_MANY_RANGE_REPEAT:
169+
p = "too many range repeat"; break;
170+
case ONIGERR_TOO_MANY_NULL_CHECK:
171+
p = "too many null check"; break;
168172
case ONIGERR_TOO_BIG_COMPILED_PROGRAM:
169173
p = "too big compiled program"; break;
170174
case ONIGERR_TOO_MANY_CAPTURE_GROUPS:

‎test/ruby/test_regexp.rb‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,4 +2303,24 @@ def test_nested_repeat_expansion_overflow
23032303
end
23042304
end;
23052305
end
2306+
2307+
def test_too_many_range_repeat
2308+
source = '(?:foobar){0,100}'
2309+
assert_nothing_raised { Regexp.new(source * 32767) }
2310+
[32768, 100000].each do |count|
2311+
assert_raise_with_message(RegexpError, /\Atoo many range repeat:/) do
2312+
Regexp.new(source * count)
2313+
end
2314+
end
2315+
end
2316+
2317+
def test_too_many_null_check
2318+
source = '(?:(?:foo)?|(?:bar)?)*'
2319+
assert_nothing_raised { Regexp.new(source * 32767) }
2320+
[32768, 100000].each do |count|
2321+
assert_raise_with_message(RegexpError, /\Atoo many null check:/) do
2322+
Regexp.new(source * count)
2323+
end
2324+
end
2325+
end
23062326
end

0 commit comments

Comments
 (0)