Fix heap buffer overflow via side-effects in js_typed_array_constructor

Fixes: https://github.com/quickjs-ng/quickjs/issues/1296
Fixes: https://github.com/bellard/quickjs/issues/478
This commit is contained in:
Saúl Ibarra Corretgé 2026-01-05 11:22:53 +01:00 committed by Michal Suchanek
parent 28940c6d18
commit bc629c8b65
3 changed files with 35 additions and 0 deletions

@ -457,6 +457,7 @@ test: qjs$(EXE)
$(WINE) ./qjs$(EXE) tests/bug1301.js
$(WINE) ./qjs$(EXE) tests/bug1302.js
$(WINE) ./qjs$(EXE) tests/bug1305.js
$(WINE) ./qjs$(EXE) tests/bug1296.js
ifndef CONFIG_WIN32
$(WINE) ./qjs$(EXE) tests/test_std.js
endif

@ -58228,6 +58228,27 @@ static JSValue js_typed_array_constructor(JSContext *ctx,
JS_FreeValue(ctx, buffer);
return JS_EXCEPTION;
}
// Re-validate buffer after js_create_from_ctor which may have run JS code
// that resized or detached the ArrayBuffer
abuf = JS_VALUE_GET_OBJ(buffer)->u.array_buffer;
if (abuf->detached) {
JS_FreeValue(ctx, buffer);
JS_FreeValue(ctx, obj);
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
}
if (offset > abuf->byte_length) {
JS_FreeValue(ctx, buffer);
JS_FreeValue(ctx, obj);
return JS_ThrowRangeError(ctx, "invalid offset");
}
if (track_rab) {
// Recalculate length for RAB-backed view
len = (abuf->byte_length - offset) >> size_log2;
} else if ((offset + (len << size_log2)) > abuf->byte_length) {
JS_FreeValue(ctx, buffer);
JS_FreeValue(ctx, obj);
return JS_ThrowRangeError(ctx, "invalid length");
}
if (typed_array_init(ctx, obj, buffer, offset, len, track_rab)) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;

13
tests/bug1296.js Normal file

@ -0,0 +1,13 @@
import {assert} from "./assert.js"
const ab = new ArrayBuffer(10, { maxByteLength: 10 });
function f() {
return 1337;
}
const evil = f.bind();
Object.defineProperty(evil, "prototype", { get: () => {
return ab.resize();
} });
let u8 = Reflect.construct(Uint8Array, [ab], evil);
assert(u8.length == 0);