mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-regexp: cap character class count and free named_captures
Two related bugs uncovered by OSS-Fuzz testcase 6692915710853120:
1. add_class allowed unbounded growth of c->classes. Class IDs are
stored in re_inst.a (uint8_t), so any ID >= 256 silently aliases
another class via the cast at emit sites. Worse, c->class_capa
(uint16_t) overflows on doubling past 32768 -> 0, then
mrb_realloc(..., 0) returns NULL, and the next memset(&c->classes[id])
segfaults at NULL+offset. Cap with RE_MAX_CLASSES = 256 (the encoding
limit) and raise via compile_error past that.
2. Once the crash is fixed, the testcase exposes a leak of
c->named_captures: compile_error frees c->code, c->classes, and
c->stripped (commit 3f321f09bc) but missed named_captures. Add it
to the same cleanup block.
Reported by OSS-Fuzz (clusterfuzz testcase 6692915710853120).
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,8 @@ compile_error(re_compiler *c, const char *msg)
|
||||
c->code = NULL;
|
||||
mrb_free(c->mrb, c->classes);
|
||||
c->classes = NULL;
|
||||
mrb_free(c->mrb, c->named_captures);
|
||||
c->named_captures = NULL;
|
||||
if (c->stripped) mrb_free(c->mrb, c->stripped);
|
||||
c->stripped = NULL;
|
||||
|
||||
@@ -118,9 +120,20 @@ next_char(re_compiler *c)
|
||||
return (uint8_t)*c->p++;
|
||||
}
|
||||
|
||||
/* Class IDs are stored in re_inst.a (uint8_t), so at most 256 distinct
|
||||
character classes can be encoded. Without this cap, class_capa
|
||||
(uint16_t) overflows on doubling past 32768 (8 -> 16 -> ... -> 32768
|
||||
-> 0), mrb_realloc with size 0 returns NULL, and the next memset
|
||||
crashes; even before that, the (uint8_t)id cast at emit sites would
|
||||
silently alias different classes. */
|
||||
#define RE_MAX_CLASSES 256
|
||||
|
||||
static uint16_t
|
||||
add_class(re_compiler *c)
|
||||
{
|
||||
if (c->num_classes >= RE_MAX_CLASSES) {
|
||||
compile_error(c, "too many character classes");
|
||||
}
|
||||
if (c->num_classes >= c->class_capa) {
|
||||
c->class_capa = c->class_capa ? c->class_capa * 2 : 8;
|
||||
c->classes = (re_charclass*)mrb_realloc(c->mrb, c->classes, sizeof(re_charclass) * c->class_capa);
|
||||
|
||||
Reference in New Issue
Block a user