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
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).
Description
re_parse_char_class()performs a unicode sets (/v) prefix check withmemcmp(s, p, n)forn = 1..3but does not verify thatp + n <= pattern_end.For short class patterns such as
"[]"(or unterminated"["), this causes an out-of-bounds read during regexp compilation from JavaScript only vianew RegExp(pattern, "v").Reproduce
Please test with ASAN build of quickjs-ng.
ASAN output
Credit
Yuan (@Reset816) and xia0o0o0o (@KpwnZ).