The Bug
There is a heap buffer overflow in JS_ReadBigInt.
ASAN Report
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2754686023
INFO: Loaded 1 modules (80429 inline 8-bit counters): 80429 [0x562120666c40, 0x56212067a66d),
INFO: Loaded 1 PC tables (80429 PCs): 80429 [0x56212067a670,0x5621207b4940),
./fuzz: Running 1 inputs 1 time(s) each.
Running: crashes/crash-ef103fd58bb6424db6ffaaaf37565185b03705de
=================================================================
==3106495==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000038 at pc 0x56212032ce1a bp 0x7ffcd0006170 sp 0x7ffcd0006168
WRITE of size 4 at 0x602000000038 thread T0
#0 0x56212032ce19 in JS_ReadBigInt /home/quickjs-ng/quickjs/quickjs.c:36348:19
#1 0x5621201fb43a in JS_ReadObjectRec /home/quickjs-ng/quickjs/quickjs.c:37145:15
#2 0x5621203292c5 in JS_ReadObjectTag /home/quickjs-ng/quickjs/quickjs.c:36775:15
#3 0x5621201fb54b in JS_ReadObjectRec /home/quickjs-ng/quickjs/quickjs.c:37118:15
#4 0x5621201f9ad4 in JS_ReadObject2 /home/quickjs-ng/quickjs/quickjs.c:37285:15
#5 0x56212026e018 in JS_ReadObject /home/quickjs-ng/quickjs/quickjs.c:37300:12
#6 0x56212026e018 in LLVMFuzzerTestOneInput /home/quickjs-ng/quickjs/fuzz.c:18:19
#7 0x56212001e663 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/quickjs-ng/quickjs/fuzz+0x373663) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#8 0x5621200083df in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/quickjs-ng/quickjs/fuzz+0x35d3df) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#9 0x56212000e136 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/quickjs-ng/quickjs/fuzz+0x363136) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#10 0x562120037f52 in main (/home/quickjs-ng/quickjs/fuzz+0x38cf52) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#11 0x7f56e91c3d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#12 0x7f56e91c3e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#13 0x562120002ca4 in _start (/home/quickjs-ng/quickjs/fuzz+0x357ca4) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
0x602000000038 is located 0 bytes to the right of 8-byte region [0x602000000030,0x602000000038)
allocated by thread T0 here:
#0 0x5621200bacde in malloc (/home/quickjs-ng/quickjs/fuzz+0x40fcde) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#1 0x56212027b793 in js_def_malloc /home/quickjs-ng/quickjs/quickjs.c:1851:12
#2 0x5621200f6b38 in js_malloc_rt /home/quickjs-ng/quickjs/quickjs.c:1451:11
#3 0x5621202afad7 in js_malloc /home/quickjs-ng/quickjs/quickjs.c:1534:11
#4 0x5621202afad7 in js_bigint_new /home/quickjs-ng/quickjs/quickjs.c:10786:9
#5 0x56212032c579 in JS_ReadBigInt /home/quickjs-ng/quickjs/quickjs.c:36341:9
#6 0x5621201fb43a in JS_ReadObjectRec /home/quickjs-ng/quickjs/quickjs.c:37145:15
#7 0x5621203292c5 in JS_ReadObjectTag /home/quickjs-ng/quickjs/quickjs.c:36775:15
#8 0x5621201fb54b in JS_ReadObjectRec /home/quickjs-ng/quickjs/quickjs.c:37118:15
#9 0x5621201f9ad4 in JS_ReadObject2 /home/quickjs-ng/quickjs/quickjs.c:37285:15
#10 0x56212026e018 in JS_ReadObject /home/quickjs-ng/quickjs/quickjs.c:37300:12
#11 0x56212026e018 in LLVMFuzzerTestOneInput /home/quickjs-ng/quickjs/fuzz.c:18:19
#12 0x56212001e663 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/quickjs-ng/quickjs/fuzz+0x373663) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#13 0x5621200083df in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/quickjs-ng/quickjs/fuzz+0x35d3df) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#14 0x56212000e136 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/quickjs-ng/quickjs/fuzz+0x363136) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#15 0x562120037f52 in main (/home/quickjs-ng/quickjs/fuzz+0x38cf52) (BuildId: baf1fe61c0160916b98321b4bbc75964be8ce411)
#16 0x7f56e91c3d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/quickjs-ng/quickjs/./quickjs.c:36348:19 in JS_ReadBigInt
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa fd fd fa fa 00[fa]fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: 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
==3106495==ABORTING
Description
This is the same bug as here: bellard/quickjs#399. The issue mentioned contains a fix that can also be applied to quickjs-ng.
Reproducing
using fuzz.c:
// clang -g -O1 -fsanitize=fuzzer -o fuzz fuzz.c
#include "quickjs.h"
#include "quickjs.c"
#include "cutils.c"
#include "libregexp.c"
#include "libunicode.c"
#include "xsum.c"
#include <stdlib.h>
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
{
JSRuntime *rt = JS_NewRuntime();
if (!rt)
exit(1);
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
exit(1);
JSValue val = JS_ReadObject(ctx, buf, len, /*flags*/0);
JS_FreeValue(ctx, val);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return 0;
}
with the following input:
echo -ne '\x14\x00\x08\x7f\x00\x0a\xff\xff\xff\xff\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xdf\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\x00\x00\x00\x00\x00\x06\x00\xab' > crashing_input.bin
The Bug
There is a heap buffer overflow in
JS_ReadBigInt.ASAN Report
Description
This is the same bug as here: bellard/quickjs#399. The issue mentioned contains a fix that can also be applied to quickjs-ng.
Reproducing
using fuzz.c:
with the following input: