← All issues

[23] XMLHttpRequest GC-thread UAF on m_responseDocument

Severity: Medium | Component: WebCore XMLHttpRequest bindings | a814080

JSC GC marking thread가 동기화 없이 m_responseDocument를 역참조하는 동안, main thread에서 responseXML()/clearResponseBuffers()를 통해 이를 null로 설정할 수 있는 cross-thread race를 수정합니다. Medium으로 평가된 이유입니다.

JSXMLHttpRequest::visitAdditionalChildrenInGCThread는 동기화 없이 wrapped().optionalResponseXML()optionalUpload()를 읽습니다. 이때 main thread에서는 m_responseDocument = nullptr;을 수행할 수 있는데, 이는 기존 reference를 해제하는 RefPtr 재할당에 해당합니다.

Source/WebCore/xml/XMLHttpRequest.h

+ Lock m_gcLock;
+ const std::unique_ptr<XMLHttpRequestUpload> m_upload WTF_GUARDED_BY_LOCK(m_gcLock);
- RefPtr<Document> m_responseDocument;
+ RefPtr<Document> m_responseDocument WTF_GUARDED_BY_LOCK(m_gcLock);
+template<typename Visitor>
+void XMLHttpRequest::visitAdditionalChildrenInGCThread(Visitor& visitor)
+{
+ Locker locker { m_gcLock };
+ if (m_upload)
+ addWebCoreOpaqueRoot(visitor, *m_upload);
+ if (auto* document = m_responseDocument.get())
+ addWebCoreOpaqueRoot(visitor, *document);
+}

Main thread가 barrier 없이 null로 설정하거나 재할당할 수 있는 refcounted DOM pointer를, GC thread가 동기화 없이 읽는 패턴입니다. 이로 인해 JS opaque root에서 data-race UAF가 발생합니다.

두 멤버에 접근하는 main thread의 모든 경로는 Locker { m_gcLock }으로 보호되어 있습니다. 아울러 더 이상 사용되지 않는 인라인 getter인 optionalResponseXML()optionalUpload()는 헤더에서 제거되었습니다.

🔒

A multi-threading hazard between JSC's marking phase and main-thread DOM mutation — the analysis walks through how the visitor's view of an owned DOM pointer can race a re-entrant nullification.

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

🔒

Four reusable audit patterns covering GC-visitor thread-safety across WebKit JS bindings, with concrete grep starting points for variant discovery.

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