[5] Wasm GC struct.new_default Information Leak via Missing v128 Initialization
Severity: Medium | Component: JSC Wasm OMG JIT | 4be0a7f
Medium 등급으로 평가됩니다. struct allocation당 8바이트의 초기화되지 않은 프로세스 메모리가 안정적으로 노출되며, ASLR 우회에 활용될 수 있습니다. 초기화 분기 누락은 diff를 통해 신뢰도 0.95로 확인됩니다. 다만 backing store가 사전에 zero로 채워지는지, 아니면 field별 초기화에만 의존하는지는 확인되지 않습니다.
struct.new_default의 v128 field를 v128_t { }로 초기화하도록 수정되었습니다. 아울러 array.new_default도 constant() 헬퍼를 사용하도록 변경되었습니다.
Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp
for (StructFieldCount i = 0; i < structType.fieldCount(); ++i) {
Value* initValue;
- if (Wasm::isRefType(structType.field(i).type))
+ auto fieldType = structType.field(i).type;
+ if (Wasm::isRefType(fieldType))
initValue = m_currentBlock->appendNew<WasmConstRefValue>(m_proc, origin(), JSValue::encode(jsNull()));
- else if (typeSizeInBytes(structType.field(i).type) <= 4)
+ else if (typeSizeInBytes(fieldType) == 16)
+ initValue = constant(V128, v128_t { });
+ else if (typeSizeInBytes(fieldType) <= 4)
initValue = constant(Int32, 0);
else
initValue = constant(Int64, 0);
JSTests/wasm/gc/struct-new-default-v128.js
+ (type $S1 (struct (field $vec (mut v128))))
+ (func (export "leak") (result i64)
+ (struct.new_default $S1)
+ (struct.get $S1 0)
+ (i64x2.extract_lane 1)
+ )
+...
+ for (let i = 0; i < 1000000; i++) {
+ const value = instance.exports.leak();
+ assert.eq(value, 0n);
+ }
Wasm struct 기본값 초기화에서 128-bit SIMD field를 처리하는 size-class 분기가 누락되어, 부분 초기화와 정보 누출이 발생합니다.
Patch Details
OMGIRGenerator::addStructNewDefault의 field 초기화 루프에는 16바이트 v128 field를 처리하는 분기가 없었습니다. 패치 이전에는 v128 field(크기 16)가 ref type이 아니고 크기도 4를 초과하므로 else 분기로 진입했고, constant(Int64, 0)으로 초기화되었습니다. 즉 16바이트 슬롯에 8바이트 zero 값만 기록된 셈입니다. 패치에서는 typeSizeInBytes(fieldType) == 16 조건을 명시적으로 추가하여 v128 field를 constant(V128, v128_t { })로 초기화합니다. 128-bit zero가 정상적으로 기록됩니다. 아울러 addArrayNewDefault에서도 장황한 Const128Value 생성 코드를 동일한 헬퍼로 대체하여 일관성을 확보했습니다.
Background
Wasm GC의 struct.new_default는 WebAssembly GC 명세에 따라 모든 field를 기본값(zero)으로 설정한 새로운 struct instance를 생성합니다. v128은 Wasm SIMD와 Wasm GC에서 사용하는 128-bit SIMD 타입으로, 메모리 상에서 16바이트를 점유합니다. OMG tier는 JSC의 최상위 Wasm 최적화 JIT로, hot function을 B3 IR을 통해 컴파일합니다. OMG IR generator의 constant() 헬퍼는 타입이 지정된 B3 상수 값을 생성합니다. 16바이트 field에 constant(Int64, 0)을 사용하면 필요한 16바이트 중 8바이트만 처리되고, 나머지 상위 8바이트는 초기화되지 않은 상태로 남습니다.
Analysis
근본 원인은 size 기반 타입 dispatch에서 케이스가 누락된 것입니다. 초기화 로직은 먼저 ref type 여부를 확인하고, 다음으로 크기가 4바이트 이하인 field(Int32)를 처리한 뒤, 나머지는 모두 Int64(8바이트)로 처리했습니다. v128 field는 typeSizeInBytes == 16이므로 else 분기에 진입하여 8바이트 zero로 초기화됩니다. 결과적으로 16바이트 v128 슬롯의 상위 8바이트가 초기화되지 않습니다. JIT-compiled 코드는 16바이트 field에 8바이트 zero만 기록합니다. 이후 해당 field를 읽으면(i64x2.extract_lane 1 등), 초기화되지 않은 상위 절반에 남아 있던 값이 반환됩니다. backing store가 사전에 zero로 채워지지 않고 field별 초기화에만 의존하는 경우, 이전 heap 또는 stack의 내용이 JavaScript로 노출됩니다.
Aaa Aaaa Aaa Aaaaaaa Aaa Aaaaaa Aaaa Aaaaaa Aaa Aaaaaa Aaa Aa Aaaa Aaaaa Aaaaaaaaaaaaaaaaaaaa Aa a Aaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaa Aa Aaaaa Aa Aaa Aaaaaa Aaa Aaaa Aaaa Aa Aaaaaaaaaa Aaaa Aaa Aaaaaa Aaaaa a Aaaa Aa Aaaaaa Aaaaaa Aa Aaaa Aa Aaaaa Aa Aaaa Aaaa Aa Aa Aaa Aaaaaaa
Aaaa Aaaa Aaaaaa Aa Aaa Aaa Aaaaaaa Aaaaa Aaaa Aaaa Aa Aaaaa Aaaaaaaaaaa Aa Aaaaa Aaaaa Aa Aaaa Aaaa Aaaaaaaaaa Aaaaaa Aaa Aaa a Aaaaa Aaa Aaaa Aaaaaaaa Aaa Aaaaaa Aaaaaaaaaa Aaaaaaaaaaaaaa Aaaa Aaaa Aaa Aaa Aaaa Aaaaa
a Aaaaaaaaaaaaaa Aaaaaaaa Aaaaaaa Aaa Aaa Aaaa Aaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaaaaa Aa Aaaaaa Aaaaa Aaaa Aa Aaaaaa Aaaa Aa Aaaa Aa a Aa Aaa Aaaaaaaa Aa Aaa Aaaaaaaaaa Aaaaaaa Aaaaaaaa Aaaaa Aaaaa Aa Aaa Aaaaaaaa Aaa Aaaaaaaaaaaaa Aaaaaaaa Aa Aaaa a Aaaa Aaaaa
Aaaa Aa Aaa Aa Aaaaaaaaaaa Aa Aaaa Aaaaaa Aaaa Aa Aaa Aaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaaa Aaa Aaaaaa Aaaa Aa Aaaaaaaaa Aaa Aa a Aaaaaa Aaaaaaaaa Aaa Aaaaaa a Aaaaaa Aaa Aaaa Aaa Aaaaaaa Aaa Aaaa Aaa Aaa Aaaa Aaaa Aaaa Aaaa Aaa Aaaaa a Aa Aaa Aaaaa a Aaa Aaa Aaa Aaaa Aaaaa
Audit directions
a Aaa Aa Aaaaa Aaa Aaaaa Aaaa Aaaaaaaaa Aaaaaa Aaa Aaaa Aaaa Aa Aa Aaaaaaaaa a Aa Aaa Aaaa Aaaaaaaaaa Aaa Aa Aaaaaa Aa Aaaa Aa Aaaaaaaaaaaaaa Aaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaaa Aaaaa Aaaa Aa Aaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaa Aaaaaaaa Aaaaaa Aaaaaa Aaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aa Aaaaa Aaa Aaa Aaa Aaaa Aaa Aaaa Aaaaa Aaaa Aaaa
a Aaa Aaa Aaaa Aaa Aa Aaaa Aaa Aaaa Aa Aaaaaaaaa Aaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaa Aaaa Aaaa Aa Aaaa Aaaaa Aaaaa Aaa Aa Aaaa Aaaaa Aaaaa Aaaa Aaaaa Aaaaaa Aaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaa Aaaaaa
a Aaa Aaaaaaaaaaaa Aaaaaaaaaaa Aa Aaaa Aa Aa Aaa Aa Aaaaaaaaaa Aaaaaaa Aaaaaaaa Aa Aaa Aaa Aa Aaaaaaaaaaa Aaaaa Aaaa Aa Aaaa Aaaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaa Aaaaaaa Aaaaaa Aaa Aaaaa Aaaaaa Aaaaaa Aaaaa Aaaaa Aaaaaa Aaaa Aaaaa Aaa Aaa Aa Aaaa Aaaaaa