[1] DFG proto-fold type confusion via TOCTOU race in GetByStatus condition validation
Severity: High | Component: JSC DFG JIT | 3330a93
관찰 가능한 영향이 web content에서 도달 가능한 type-confused property access를 생성하는 DFG speculation failure이며, primitive(혼동된 backing storage에 대한 controlled read/write)는 regression test에서 확인된 structure-check elision을 근거로 confidence 0.92로 산정되었기 때문에 High로 평가되었습니다. 다만 DFGConstantFoldingPhase.cpp와 DFGAbstractInterpreterInlines.h에서의 downstream consumer 동작에 관한 일부 내용은 diff에 드러나지 않으며, 핵심 trigger의 신뢰성을 약화시키지는 않습니다.
DFG prototype property folding에 사용되는 condition set의 ObjectPropertyCondition 항목들이 각 condition의 object 현재 structure와 대조해 재검증되도록 수정되었습니다. GetByStatus::computeFor에 네 가지 bail-out 검사가 추가되었습니다. null object, overridesGetOwnPropertySlot, non-cacheable property access, 그리고 hasPolyProto가 그 대상입니다. 이 검사들은 condition 생성 이후 prototype chain에 교체된 object가 호환되지 않는 property lookup semantics를 가진 structure를 도입하는 상황을 차단합니다.
Source/JavaScriptCore/bytecode/GetByStatus.cpp
for (auto& condition : conditionSet) {
+ auto* object = condition.object();
+ if (!object)
+ return std::nullopt;
+
+ auto* currentStructure = object->structure();
+ if (currentStructure->typeInfo().overridesGetOwnPropertySlot())
+ return std::nullopt;
+
+ if (!currentStructure->propertyAccessesAreCacheable())
+ return std::nullopt;
+
if ((i + 1) == totalSize) {
// The last condition
if (condition.kind() != PropertyCondition::Presence)
...
}
+ if (currentStructure->hasPolyProto())
+ return std::nullopt;
+
if (condition.kind() != PropertyCondition::Absence)
return std::nullopt;
JSTests/stress/dfg-proto-fold-invalidate3.js
+ const objectX = createClonedArguments();
+ Object.setPrototypeOf(objectX, objectD);
+ ...
+ // 변경 전: A -> B -> C -> D -> E
+ // 변경 후: A -> B -> X -> D -> E
+ Reflect.setPrototypeOf(objectD, objectE);
+ Reflect.setPrototypeOf(objectB, objectX);
+
+ await sleep(1000);
+
+ opt(objectA, /* exitEarly */ false);
+
+ shouldBe(createClonedArguments[0], 2.3023e-320);
Patch Details
GetByStatus::computeFor의 for (auto& condition : conditionSet) 루프 안에 네 가지 guard 검사가 추가되었습니다. 각 ObjectPropertyCondition에 대해, condition의 object와 현재 structure를 조회한 뒤, 다음 조건 중 하나라도 해당하면 std::nullopt를 반환해 status 계산을 중단합니다. (1) object가 null인 경우, (2) structure의 typeInfo().overridesGetOwnPropertySlot()이 true인 경우, (3) structure의 propertyAccessesAreCacheable()이 false인 경우, (4) structure에 hasPolyProto()가 설정된 경우입니다. 이 검사들은 기존의 Absence/Presence kind 검증보다 앞서 실행됩니다.
Before: After:
for (condition : conditionSet) for (condition : conditionSet)
└─► check Absence/Presence kind ├─► get object->structure()
└─► build status ├─► bail if overridesGetOwnPropertySlot
├─► bail if !propertyAccessesAreCacheable
├─► bail if hasPolyProto
└─► check Absence/Presence kind
└─► build status
Background
GetByStatus::computeFor는 DFG constant folding phase 또는 abstract interpreter에서 호출될 때 ObjectPropertyCondition 항목들을 순회하며 해당 property access를 fold할 수 있는지 검증합니다. fold가 가능하다고 판단되면 JIT는 runtime lookup을 수행하는 대신 property 값이나 offset을 직접 hardcode합니다. 각 condition은 prototype chain 상의 특정 object를 참조하고, 해당 object의 structure에 대한 주장을 담고 있습니다. 예를 들어 Absence는 해당 prototype에 대상 property가 없음을, Presence는 존재함을 의미합니다. 이 condition들은 bytecode 분석 시점에 생성되었다가 DFG 컴파일 단계에서 나중에 소비됩니다.
ClonedArguments는 특정 calling convention에서 arguments에 접근할 때 생성되는 특수한 JSC object 타입입니다. getOwnPropertySlot을 override해 처리되는 synthetic callee property를 가지고 있어, 일반적인 inline cache 기반의 caching 가정이 적용되지 않습니다. structure의 overridesGetOwnPropertySlot 플래그는 이와 같은 커스텀 property lookup 로직을 나타냅니다. 이 플래그가 설정된 object는 표준 structure 기반 경로와 다른 방식으로 property를 처리할 수 있기 때문에, inline cache나 DFG에 의한 fold가 안전하지 않습니다.
DFG prototype folding은 컴파일러가 prototype chain을 순회하면서 중간 object 각각에 대상 property가 없음(Absence)을, 마지막 object에는 존재함(Presence)을 확인한 뒤 resolved된 값이나 offset을 컴파일된 코드에 직접 hardcode하는 최적화입니다. 이를 통해 접근마다 chain을 탐색하는 runtime 비용을 절감합니다.
Analysis
DFG prototype condition 검증의 TOCTOU race — condition 생성과 소비 사이에 structure 특성이 안정적이라고 가정했으나, prototype chain 변조를 통해 우회 가능.
패치 이전에는 GetByStatus::computeFor가 ObjectPropertyCondition set을 순회할 때 각 condition의 object에 대한 현재 structure를 재검증하지 않았습니다. condition들은 bytecode 분석 단계에서 생성되는데, 생성 시점과 DFG 컴파일 단계에서의 소비 시점 사이에 공격자가 Reflect.setPrototypeOf를 통해 prototype chain의 object를 교체할 수 있었습니다. 이후 코드는 교체된 object의 structure 특성이 호환 가능한지 검증하지 않은 채로 stale condition들을 그대로 사용해 prototype property access를 fold했습니다.
이것은 prototype chain 관련 DFG folding invalidation 버그의 세 번째 사례로, 테스트 파일 이름이 명시적으로 dfg-proto-fold-invalidate3.js로 붙어 있습니다. 패턴은 일관됩니다. GetByStatus::computeFor는 prototype chain의 특정 시점 스냅샷을 기반으로 property condition을 구성하지만, chain이 변조된 이후 시점에 이를 소비합니다. 각 변형은 코드가 재검증하지 못한 새로운 structure 특성을 발견합니다. 근본적인 문제는 ObjectPropertyCondition이 특정 시점의 assertion을 캡처하지만, 소비 시점에서 참조된 object의 현재 상태를 다시 확인하지 않고 그 assertion을 신뢰한다는 점입니다. 이번 변형은 이전 두 버그에 대한 variant analysis를 통해 발견되었으며, condition 루프에서 재검증되지 않은 추가적인 structure 특성이 식별되었습니다.
Aaa Aaaa Aaa Aaaaaaaa Aaaaaa Aaaa Aa a a a a a a a Aa Aaa Aaaaaaaaa Aaaaaa Aaaaaa Aaa Aaaaaaaaa Aaaa Aaaaaa Aaaa Aaaaa Aaaaaaa Aaa Aaaa Aaaaa Aaa Aa Aaaaaaaa Aaaaaaa Aaaaa Aa Aaa Aaaaa Aaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaa Aaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaaaa Aaaaaa Aaaaa Aaaa Aa Aaaaaa Aaaaaaaaaaaaa Aaa a Aaaaaaaaaaaaaaa Aaaaaa Aaaa Aaaa Aaa Aaaaaa Aaaa Aaa Aaa Aaa Aaaaaaaaa Aaa Aaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaa Aaaaaaa Aaaaaa a Aa Aaa Aaaaaaa Aaaaaaaa Aaaaa Aaaa Aaaaaaaaaa Aaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa a Aaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaaa Aaa Aaaaaa
Aaa
Aaaaaaa Aaaaaaaaa
Aa Aaaaa Aaaaaa a a a a a a a a a Aaaaaaa a Aaa Aaaa Aa Aa
Aa Aaaa Aaaaa a Aaa Aaaaa Aaaaaa Aaaaaaa Aaaaa
Aa Aaaaa a a a a Aaaaaaaaaaaaaaaaaa a a a a
Aa Aaaaa Aaaaaaaaaaa a Aaa Aaaaaaaaaa Aaaa Aaaaa Aaaaaaaaaa
Aa Aaaaaaaaaaaa a Aaaaa Aaaa Aaaaaaaa Aaaaaa Aaaaa
Aaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaa Aa Aaa Aaaa
Aaa Aaaaaaaaaaaaa Aaaaaa Aaaaa Aaaaaaaaaaa
Aaa
Aaaaa Aaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaa Aaaaaaaaaa Aaaaaaaaaa Aaaaaa Aaaaaaaaaa Aaaaaaaaaa Aaa Aaaa Aaaaa Aaaa Aaaaaaaaa Aaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaa Aa Aaa Aaaa Aaaaa Aaaaa Aaaaaaa Aaaaaaaaa Aaa Aaaaaa Aaa Aaa Aaaaa Aa Aaa Aaaa Aaaaaaaa Aaaaaaa Aa Aaa Aaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaa Aaa a Aaaaa Aaaaaa Aaaaaaaa Aaa Aa Aaaa Aaaaaaa Aaaaa Aaa Aaaaaaaaaaa Aaa Aaa Aaaaa Aa Aaaaaa Aa a Aaa Aaa Aaaaaa Aaaaaaa Aaa Aa Aa Aaaaa Aaaaaaaaaa Aaaa Aaa Aa Aaaaa Aaa Aaa Aa Aaaaaa Aa Aaaa Aaaaaa Aaaaaaa Aa Aaaaaa
a Aaaaaaaaaaaaaa Aaa Aaaa Aaaaaaa Aaa Aaa Aaa Aaaaaaa Aaa Aaaaa Aaaaa Aaaaaaaaaa Aaa Aaaaaaaaa Aaaaaaaa Aaaaaaa Aaaaaaa Aaaaaaa Aaaaa Aaaaa Aaa Aaaa Aa Aa Aaaaaa a Aaaaaaaaaa Aaaa Aaaa Aaaa a Aaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaa Aaaaaaa Aaaaaaaa Aa Aaaaa Aaaaaaaaa Aaaaa Aaaa Aaaaaaaaaa Aaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaa Aa a Aaaaa Aaaaaaaa Aaaaaaaa Aaaaaaa Aaa Aaaaa Aaa Aaaa Aaa Aaaaaaa Aaaaaaa Aaaaaa
🔒Explores the DFG prototype folding race window and the type confusion primitive it produces, with feasibility assessment under realistic timing conditions
더 확인하려면 구독해 주세요
Audit directions
a Aaa Aaa Aaaaaa Aaa Aaaaaa a Aaaaaaaaa Aaaa Aaaaa Aaaaaaa Aa Aaaaaaaaa Aaa Aa Aaaaaa Aaa Aa Aa Aaaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaa Aa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaa Aaaa Aaa Aaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aa Aaa Aaaaaaa
a Aaa Aaaaaaaaa Aaaaa Aaa Aa Aaa Aa Aaa a Aaaaaaaaa Aaaaa Aa Aaa Aaaa Aaa Aa Aaa Aaaaaaaaaa Aaaaaaaa Aaaaaaa Aaaaaaa Aaaaaaa Aa Aaaa Aaa Aaaaaaaaaaaa Aaaaaaaaaaa Aaaaa Aaa Aa Aaaaaaaaa Aaa Aaaa Aa Aa Aaa a Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaa Aaa Aaaaaaaaa Aaaa Aaaaaaa Aaa Aaaaaaa Aaaaaa Aaaaa Aaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaa Aaaaaaa
a Aaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aa Aaaaaa Aaaaaaaa Aaaaaaaaa Aaaaaa Aaa Aaaaaa Aaaaaaa Aaa Aaaa Aaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a Aaaaaaaaa Aaaaaa Aaaa Aa Aa Aaaaa Aaaaa Aa Aaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aa Aa Aaa Aa Aa Aaaa Aaaaaaa
Aaaaaaaaa Aa Aa Aaaaa Aa Aaa Aaaaaaaa Aaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaaaa Aaaa Aaaaa Aa Aaaaaaaaaaaaa Aaa Aaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aa Aa Aaa Aaaaa Aaa Aaaaaaaa Aa Aaaa Aaa Aaaaa Aaa Aaaaaa Aa Aaaaaaaa Aaaa Aaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaa Aaaaa Aaaaaa Aa Aaaa Aaaaaaa
🔒Multiple reusable audit patterns identified across JSC's bytecode status computation infrastructure, with concrete search targets for variant discovery
더 확인하려면 구독해 주세요