← All issues

[3] JSC PutByVal IC IndexingHeader Corruption via Non-String Primitive Key Transition

Severity: High | Component: JSC Inline Cache | 4731033

High로 평가된 이유는 다음과 같습니다. 웹 콘텐츠에서 간단한 방법으로 도달 가능한 typed array view의 IndexingHeader 메타데이터가 직접 손상된다는 점이 주요 근거입니다. 트리거는 resizable ArrayBuffer에 primitive key를 할당하는 단순한 형태입니다. 예상되는 primitive — ArrayBuffer backing store에 대한 OOB access — 는 zeroed bounds 메타데이터 및 commit 메시지에서 언급하는 "잘못된" 후속 indexed access 설명과 일치합니다. 다만 zeroed 메타데이터 상태에서 downstream bounds check가 정확히 어떻게 동작하는지는 확인되지 않습니다.

이 패치는 InlineCacheCompiler.cpp에 새로운 템플릿 함수 putByValNonStringPrimitiveKeyTransitionOutOfLineHandlerImpl을 추가합니다. 이 함수는 operationReallocateButterflyAndTransition을 호출하여 IndexingHeader를 가진 객체의 butterfly reallocation을 올바르게 처리합니다. 아울러 DEFINE_CONSTANT_KEY_PUTBYVAL_HANDLERS 매크로도 수정되었습니다. non-string primitive key (undefined, null, true, false)에 대한 TransitionReallocatingOutOfLineHandler 항목이 기존 IndexingHeader를 보존하지 않고 butterfly를 zero-fill하는 inline allocation 경로 대신, 새로 추가된 핸들러로 dispatch하도록 변경되었습니다.

Source/JavaScriptCore/bytecode/InlineCacheCompiler.cpp

+template<NonStringPrimitiveKeyType keyType>
+static MacroAssemblerCodeRef<JITThunkPtrTag> putByValNonStringPrimitiveKeyTransitionOutOfLineHandlerImpl(VM& vm)
+{
+ CCallHelpers jit;
+ ...
+ fallThrough.append(emitNonStringPrimitiveKeyCheck<keyType>(jit, propertyJSR));
+ fallThrough.append(InlineCacheCompiler::emitDataICCheckStructure(jit, baseJSR.payloadGPR(), scratch1GPR));
+ ...
+ jit.setupArguments<decltype(operationReallocateButterflyAndTransition)>(CCallHelpers::TrustedImmPtr(&vm), baseJSR.payloadGPR(), GPRInfo::handlerGPR, valueJSR);
+ jit.callOperation<OperationPtrTag>(operationReallocateButterflyAndTransition);
+ ...
+}
MacroAssemblerCodeRef<JITThunkPtrTag> putByValWith##KeyName##KeyTransitionReallocatingOutOfLineHandler(VM& vm) \
- { return putByValNonStringPrimitiveKeyTransitionHandlerImpl<true, false, NonStringPrimitiveKeyType::keyType>(vm); }
+ { return putByValNonStringPrimitiveKeyTransitionOutOfLineHandlerImpl<NonStringPrimitiveKeyType::keyType>(vm); }

JSTests/stress/resizable-typed-array-non-string-primitive-key-transition.js

+for (let i = 0; i < 1000; i++) {
+ const buf = new ArrayBuffer(7, { maxByteLength: 3378 });
+ const ta = new Int8Array(buf);
+ ta[undefined] = 42;
+ ta[0];
+}

IC transition handler가 ArrayBuffer view에 필요한 IndexingHeader를 파괴하는 inline butterfly allocator로 dispatch됩니다.

JSC의 inline cache (IC) 시스템은 객체 구조를 기반으로 property 연산에 특화된 machine-code stub을 생성합니다. property 저장 시 butterfly reallocation이 필요한 구조 전환이 발생하면, IC는 새로운 butterfly를 할당하고 기존 데이터를 복사해야 합니다. butterfly는 JSC의 out-of-line property 및 indexed element storage로, JSObject에 연결된 연속적인 메모리 영역입니다. IndexingHeader를 가진 객체 — ArrayBuffer로 뒷받침되는 typed array view가 대표적인 예입니다 — 의 경우, butterfly header 영역에는 이후 indexed element access의 bounds check에 사용되는 메타데이터가 저장됩니다. resizable typed array의 byte length가 그 예에 해당합니다.

operationReallocateButterflyAndTransition은 IndexingHeader 보존을 포함하여 butterfly reallocation을 올바르게 처리하는 runtime 함수입니다. Commit 310410@main은 non-string primitive key (undefined, null, true, false)에 대한 PutByVal IC 지원을 추가했습니다. 이 키들은 문자열 property 이름(예: "undefined")으로 변환되어 named property로 저장되며, butterfly reallocation이 필요한 구조 전환을 유발할 수 있습니다.

310410@main에서 추가된 non-string primitive key PutByVal IC의 TransitionReallocatingOutOfLineHandler는 inline allocation 핸들러(putByValNonStringPrimitiveKeyTransitionHandlerImpl<true, false, keyType>)로 잘못 dispatch하도록 구현되어 있었습니다. 이 핸들러는 기존 butterfly의 IndexingHeader를 복사하지 않고 새로 할당된 butterfly를 zero-fill합니다. 이는 fix 패턴에서 강하게 추론된 사항이며, 구 핸들러의 본문은 diff에서 확인되지 않습니다. IndexingHeader를 가진 객체 — 특히 typed array 같은 ArrayBuffer view — 의 경우, IndexingHeader에는 핵심 메타데이터(예: resizable typed array의 byte length)가 포함됩니다. IC가 동작하여 butterfly가 zeroed IndexingHeader로 재할당된 이후에는, typed array에 대한 이후 indexed access가 손상된 메타데이터를 기반으로 동작하게 됩니다.

string-key 핸들러에는 이미 올바른 분기가 마련되어 있었습니다. inline allocation(IndexingHeader 없음)에는 putByValTransitionHandlerImpl이, IndexingHeader 보존이 필요한 경우에는 operationReallocateButterflyAndTransition을 호출하는 putByValTransitionOutOfLineHandlerImpl이 각각 사용되었습니다. 반면 non-string primitive key 핸들러는 두 경우 모두에 inline allocation 경로를 그대로 적용하여 out-of-line 변형을 누락했습니다. 새로운 기능이 기존 기능을 모방하는 과정에서 발생하는 전형적인 "incomplete pattern replication" 버그입니다.

🔒

Detailed analysis of how zeroed IndexingHeader metadata interacts with typed array bounds checking, and whether the corruption yields a usable memory access primitive

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

🔒

Multiple audit patterns identified for IC handler completeness and butterfly reallocation correctness, with concrete search targets

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