← All issues

[JSC] IPInt slow path for `memory.atomic.notify` truncates the Memory64 pointer and offset to 32 bits

afc44e3

Source/JavaScriptCore/wasm/WasmIPIntSlowPaths.cpp

WASM_IPINT_EXTERN_CPP_DECL(memory_atomic_notify, IPIntStackEntry* args)
{
#if CPU(ARM64) || CPU(X86_64)
- unsigned offset = args[0].i32;
+ uint64_t offset = args[0].i64;
uint8_t memoryIndex = args[1].i32;
int32_t count = args[2].i32;
- unsigned base = args[3].i32;
+ uint64_t base = args[3].i64;
int32_t result = Wasm::memoryAtomicNotify(instance, base, offset, count, memoryIndex);

JSTests/wasm/stress/memory64-atomic-notify-out-of-bounds.js

+assert.throws(() => exports.notify(0x1_0000_0000n), WebAssembly.RuntimeError, "Out of bounds memory access");
+assert.throws(() => exports.notify(0xffff_ffff_ffff_ffffn), WebAssembly.RuntimeError, "Out of bounds memory access");
+assert.eq(exports.notify(0n), 0);

IPInt의 assembly fast path에서 inline으로 처리할 수 없는 instruction은 C++ "slow path" 함수로 폴백됩니다. 인자는 .i32.i64 멤버가 같은 storage를 공유하는 IPIntStackEntry union을 통해 전달되며, 잘못된 멤버를 읽으면 상위 비트가 아무런 오류 없이 누락됩니다. Memory64는 linear memory 주소 지정을 64비트로 확장합니다.

이 commit은 memory.atomic.notify의 IPInt C++ slow path를 수정했습니다. 기존 코드는 64비트 주소 피연산자와 immediate offset을 IPIntStackEntry.i32 union 멤버를 통해 읽었기 때문에, 두 값 모두 오류 없이 32비트로 truncate되었습니다. 수정 후에는 두 읽기 모두 .i64로 변경되었습니다. assembly fast path는 64비트 값을 정상적으로 전달했기 때문에, 이 버그는 Memory32 모듈에서는 드러나지 않았습니다. Memory64 주소의 상위 32비트가 설정된 경우에만 발현되었습니다.

IPIntStackEntry.i32 union 멤버를 통해 64비트 주소를 읽으면 상위 32비트가 아무런 오류 없이 삭제되었습니다. pointer 0x1_0000_0000n은 주소 0에 대응되어, memory.atomic.notify가 trap하는 대신 linear memory의 첫 번째 슬롯에서 동작했습니다.

🔒

The `.i32`/`.i64` union mismatch pattern may recur in other atomic and memory instruction slow paths — audit directions included.

더 확인하려면 구독해 주세요