← All issues

Clear-Site-Data "cache" failed to evict BFCache/MemoryCache via SecurityOriginHash ODR violation

20790ef

C++ ODR은 하나의 template이 모든 translation unit에서 정확히 하나의 정의만 가져야 한다는 규칙입니다. HashSet<Ref<SecurityOrigin>>에는 두 가지 DefaultHash specialization 후보가 존재합니다. 하나는 SecurityOriginHash.h에서 제공하는 내용 기반의 SecurityOriginHash이고, 다른 하나는 항상 사용 가능한 포인터 기반의 PtrHash입니다. SecurityOriginHash.h를 포함하지 않은 translation unit이 HashSet을 인스턴스화하면, 서로 다른 hashing semantics를 가진 add()/contains() inline 정의가 binary 안에 모두 포함되고, linker는 그중 하나를 조용히 선택합니다.

Source/WebCore/page/SecurityOrigin.h

+namespace WTF {
+// Ref<SecurityOrigin>에 대한 내용 기반 DefaultHash specialization은
+// 여기서 선언되지만 실제 정의는 SecurityOriginHash.h에만 존재합니다.
+// 따라서 SecurityOriginHash.h를 포함하지 않고 Ref<SecurityOrigin>을
+// hash-table key로 사용하면, 포인터 hashing으로 조용히 fallback되는
+// 대신 명시적인 compile error가 발생합니다.
+template<typename> struct DefaultHash;
+template<> struct DefaultHash<Ref<WebCore::SecurityOrigin>>; // SecurityOriginHash.h에서 정의
+} // namespace WTF

WebProcess.cpp는 포인터 기반 hashing으로 origin set을 구성했고, WebCore는 새로 생성한 SecurityOrigin 객체를 내용 기반 hashing으로 조회했습니다. 서로 다른 hashing 방식이 적용된 만큼 포인터 주소가 일치할 수는 없었고, contains()는 항상 false를 반환했습니다. 결과적으로 어떤 cache도 비워지지 않은 셈입니다. 이 ODR 위반이 실질적인 영향을 미치게 된 것은 commit 307882@main에서 컨테이너를 RefPtr에서 Ref로 변환하면서부터입니다. 이번 수정은 SecurityOrigin.h에서 DefaultHash<Ref<SecurityOrigin>>를 불완전한 타입으로 forward-declare하여, 향후 발생할 수 있는 조용한 miscompile을 명시적인 compile error로 전환합니다.

서버는 로그아웃 시 Clear-Site-Data: "cache"를 통해 캐시된 리소스를 삭제합니다. 그러나 이 기능이 조용히 실패하면서, 로그아웃 이후의 BFCache 및 memory-cache 항목이 그대로 접근 가능한 상태로 남게 되었습니다. commit 307882@main부터 이번 수정이 적용되기 전까지 처리된 모든 응답이 이 영향을 받았습니다.

🔒

The scope of the silent failure and the class of similar ODR violations elsewhere in the codebase are both worth investigating.

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