Skip to content

incomplete check in re_parse_char_class() leads to potential heap buffer out-of-bound access #1354

@KpwnZ

Description

@KpwnZ

Description

re_parse_char_class() performs a unicode sets (/v) prefix check with memcmp(s, p, n) for n = 1..3 but does not verify that p + n <= pattern_end.

For short class patterns such as "[]" (or unterminated "["), this causes an out-of-bounds read during regexp compilation from JavaScript only via new RegExp(pattern, "v").

Reproduce

new RegExp("[]", "v");

Please test with ASAN build of quickjs-ng.

ASAN output

=================================================================
==2408536==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7b4d66be82bb at pc 0x7f0d68083bba bp 0x7ffd4709fdc0 sp 0x7ffd4709f568
READ of size 3 at 0x7b4d66be82bb thread T0
    #0 0x7f0d68083bb9 in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:848
    #1 0x7f0d680847c8 in memcmp /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:879
    #2 0x7f0d680847c8 in memcmp /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:874
    #3 0x55c07546ffcb in re_parse_char_class /root/xia0/project/quickjs-ng_src/libregexp.c:844
    #4 0x55c075473ff5 in re_parse_term /root/xia0/project/quickjs-ng_src/libregexp.c:1432
    #5 0x55c0754759ce in re_parse_alternative /root/xia0/project/quickjs-ng_src/libregexp.c:1693
    #6 0x55c075475ba4 in re_parse_disjunction /root/xia0/project/quickjs-ng_src/libregexp.c:1722
    #7 0x55c075476609 in lre_compile /root/xia0/project/quickjs-ng_src/libregexp.c:1839
    #8 0x55c0753ffbb2 in js_compile_regexp /root/xia0/project/quickjs-ng_src/quickjs.c:46958
    #9 0x55c075400c31 in js_regexp_constructor /root/xia0/project/quickjs-ng_src/quickjs.c:47104
    #10 0x55c075317a88 in js_call_c_function /root/xia0/project/quickjs-ng_src/quickjs.c:17113
    #11 0x55c075341e16 in JS_CallConstructorInternal /root/xia0/project/quickjs-ng_src/quickjs.c:20072
    #12 0x55c075321bc9 in JS_CallInternal /root/xia0/project/quickjs-ng_src/quickjs.c:17769
    #13 0x55c07534341c in async_func_resume /root/xia0/project/quickjs-ng_src/quickjs.c:20225
    #14 0x55c075344bef in js_async_function_resume /root/xia0/project/quickjs-ng_src/quickjs.c:20480
    #15 0x55c075345d4a in js_async_function_call /root/xia0/project/quickjs-ng_src/quickjs.c:20599
    #16 0x55c075384c33 in js_execute_sync_module /root/xia0/project/quickjs-ng_src/quickjs.c:30572
    #17 0x55c07538602f in js_inner_module_evaluation /root/xia0/project/quickjs-ng_src/quickjs.c:30684
    #18 0x55c0753867b4 in js_evaluate_module /root/xia0/project/quickjs-ng_src/quickjs.c:30731
    #19 0x55c0753b1701 in JS_EvalFunctionInternal /root/xia0/project/quickjs-ng_src/quickjs.c:36313
    #20 0x55c0753b1881 in JS_EvalFunction /root/xia0/project/quickjs-ng_src/quickjs.c:36327
    #21 0x55c075282531 in eval_buf /root/xia0/project/quickjs-ng_src/qjs.c:128
    #22 0x55c0752827e9 in eval_file /root/xia0/project/quickjs-ng_src/qjs.c:165
    #23 0x55c07528538e in main /root/xia0/project/quickjs-ng_src/qjs.c:686
    #24 0x7f0d67e36634  (/usr/lib/libc.so.6+0x27634) (BuildId: 5e2075850f8de86da4eead11213c59d926ca3796)
    #25 0x7f0d67e366e8 in __libc_start_main (/usr/lib/libc.so.6+0x276e8) (BuildId: 5e2075850f8de86da4eead11213c59d926ca3796)
    #26 0x55c075280c44 in _start (/mnt/zpool0/userdata/git/project/quickjs-ng_src/build-asan/qjs+0x40c44) (BuildId: 207be92ce1afb94eae26e0e5d03b907f31c27f57)

0x7b4d66be82bb is located 0 bytes after 43-byte region [0x7b4d66be8290,0x7b4d66be82bb)
allocated by thread T0 here:
    #0 0x7f0d6811fa45 in realloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:81
    #1 0x55c0752ae066 in js_def_realloc /root/xia0/project/quickjs-ng_src/quickjs.c:2034
    #2 0x55c0752ac706 in js_realloc_rt /root/xia0/project/quickjs-ng_src/quickjs.c:1662
    #3 0x55c0752be17c in string_buffer_end /root/xia0/project/quickjs-ng_src/quickjs.c:4284
    #4 0x55c07534b864 in js_parse_string /root/xia0/project/quickjs-ng_src/quickjs.c:21788
    #5 0x55c07534dff2 in next_token /root/xia0/project/quickjs-ng_src/quickjs.c:22072
    #6 0x55c07536934c in js_parse_postfix_expr /root/xia0/project/quickjs-ng_src/quickjs.c:26317
    #7 0x55c07536c73c in js_parse_unary /root/xia0/project/quickjs-ng_src/quickjs.c:26837
    #8 0x55c07536cb79 in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26880
    #9 0x55c07536ce1a in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26903
    #10 0x55c07536ce1a in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26903
    #11 0x55c07536ce1a in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26903
    #12 0x55c07536ce1a in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26903
    #13 0x55c07536ce1a in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26903
    #14 0x55c07536ce1a in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26903
    #15 0x55c07536ce1a in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26903
    #16 0x55c07536ce1a in js_parse_expr_binary /root/xia0/project/quickjs-ng_src/quickjs.c:26903
    #17 0x55c07536d16e in js_parse_logical_and_or /root/xia0/project/quickjs-ng_src/quickjs.c:27044
    #18 0x55c07536d190 in js_parse_logical_and_or /root/xia0/project/quickjs-ng_src/quickjs.c:27047
    #19 0x55c07536d341 in js_parse_coalesce_expr /root/xia0/project/quickjs-ng_src/quickjs.c:27083
    #20 0x55c07536d49e in js_parse_cond_expr /root/xia0/project/quickjs-ng_src/quickjs.c:27111
    #21 0x55c07536e7e3 in js_parse_assign_expr2 /root/xia0/project/quickjs-ng_src/quickjs.c:27326
    #22 0x55c07536f48b in js_parse_expr2 /root/xia0/project/quickjs-ng_src/quickjs.c:27450
    #23 0x55c07536f5a5 in js_parse_expr /root/xia0/project/quickjs-ng_src/quickjs.c:27472
    #24 0x55c075376aa4 in js_parse_statement_or_decl /root/xia0/project/quickjs-ng_src/quickjs.c:28780
    #25 0x55c075389ea2 in js_parse_source_element /root/xia0/project/quickjs-ng_src/quickjs.c:31279
    #26 0x55c0753b0f46 in js_parse_program /root/xia0/project/quickjs-ng_src/quickjs.c:36244
    #27 0x55c0753b2432 in __JS_EvalInternal /root/xia0/project/quickjs-ng_src/quickjs.c:36413
    #28 0x55c0753b29bb in JS_EvalInternal /root/xia0/project/quickjs-ng_src/quickjs.c:36464
    #29 0x55c0753b3129 in JS_EvalThis2 /root/xia0/project/quickjs-ng_src/quickjs.c:36519

SUMMARY: AddressSanitizer: heap-buffer-overflow /root/xia0/project/quickjs-ng_src/libregexp.c:844 in re_parse_char_class
Shadow bytes around the buggy address:
  0x7b4d66be8000: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x7b4d66be8080: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x7b4d66be8100: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fa
  0x7b4d66be8180: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x7b4d66be8200: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fa
=>0x7b4d66be8280: fa fa 00 00 00 00 00[03]fa fa 00 00 00 00 00 02
  0x7b4d66be8300: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 00 04
  0x7b4d66be8380: fa fa 00 00 00 00 00 05 fa fa fd fd fd fd fd fd
  0x7b4d66be8400: fa fa fd fd fd fd fd fd fa fa fa fa fa fa fa fa
  0x7b4d66be8480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b4d66be8500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==2408536==ABORTING

Credit

Yuan (@Reset816) and xia0o0o0o (@KpwnZ).

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