[10] DocumentLoader ScriptDisallowedScope Bypass via PluginView Destruction
Severity: Medium | Component: WebCore document loader | 7fec184
Rated Medium because the observable effect is JavaScript execution during a ScriptDisallowedScope (assertion failure in debug builds, silent re-entrancy in release builds), and the projected escalation — memory corruption via DOM mutation during style recalculation — would require the attacker's JS callback to hit specific stale references on the recalculation call stack, which is plausible but unverified.
Patch Details
In DocumentLoader::removePlugInStreamLoader(), the synchronous call to checkLoadComplete() is replaced with an asynchronous task queued on the document's event loop. The new code guards on m_frame and m_frame->document() being non-null, and captures Ref { *this } to prevent the DocumentLoader from being destroyed before the task runs.
Source/WebCore/loader/DocumentLoader.cpp
void DocumentLoader::removePlugInStreamLoader(ResourceLoader& loader)
{
ASSERT(m_plugInStreamLoaders.contains(&loader));
-
m_plugInStreamLoaders.remove(&loader);
- checkLoadComplete();
+ if (m_frame && m_frame->document()) {
+ protect(m_frame->document())->eventLoop().queueTask(TaskSource::Networking, [protectedThis = Ref { *this }]() {
+ protectedThis->checkLoadComplete();
+ });
+ }
}
LayoutTests/fast/pdf-plugin-destruction-dispatches-print-event-crash.html
+<embed id="embed" style="top: 200vmin; visibility: hidden;" type="application/pdf" src="about:blank"></embed>
+<script>
+ window.testRunner?.dumpAsText();
+ window.testRunner?.waitUntilDone();
+ window.addEventListener("load", _ => {
+ embed.setAttribute("onsubmit", "");
+ window.print();
+ requestAnimationFrame(_ => requestAnimationFrame(_ => window.testRunner?.notifyDone()));
+ });
+</script>
Synchronous script-triggering callback from within a ScriptDisallowedScope during style recalculation.
Background
ScriptDisallowedScope is a RAII guard used in WebKit that asserts no JavaScript execution occurs on the main thread for the scope's lifetime. It is enforced via assertions in debug builds; in release builds, the check may not prevent execution, making violations a real attack surface rather than just a debug crash.
Document::updateStyleIfNeeded() triggers style recalculation for the document. During this operation, a ScriptDisallowedScope is active because the style/layout tree may be in an intermediate state. PluginView represents an embedded plugin (e.g., PDF viewer). When a PluginView is destroyed — for instance, because a style update determines the plugin element is no longer rendered — its associated stream loaders are cleaned up via DocumentLoader::removePlugInStreamLoader(). checkLoadComplete() is a DocumentLoader method that checks whether all subresources have finished loading and may trigger completion callbacks, including event dispatch.
Analysis
Before the fix, removePlugInStreamLoader() called checkLoadComplete() synchronously. This function could be reached during updateStyleIfNeeded(), which creates a ScriptDisallowedScope. When a style update triggered the destruction of a PluginView (the PDF embed in the test case), the chain updateStyleIfNeeded() → PluginView destruction → removePlugInStreamLoader() → checkLoadComplete() → dispatchPrintEvent fired JavaScript event listeners inside the ScriptDisallowedScope. In release builds, where ScriptDisallowedScope does not enforce the invariant, JavaScript executes while the DOM/style tree is in an intermediate, inconsistent state during style recalculation.
Aaa Aaaa Aaaa Aaaaaa a Aaa Aaaaaa Aaaa Aaaaaaaaaaaa Aaaaaaa Aaa Aaaaa Aaaaaaaaaaaaaaaa Aaaaaa Aaaaa Aaa Aaaaa Aaaaa Aaaaaaaa Aaaaa Aaaaa Aaaaaaa Aaa Aaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaaa Aa Aaaaaaaaaa Aa Aaaaaaaa Aaaaaaa Aaaaaa Aaaa Aaaaaaaaaaa Aaaaaa Aaaaa Aaaaaa Aaa Aaa Aaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaa Aaaaaaa Aaaaa Aaaaaaaa Aaaaaaaa Aaa Aaaaaaaaa Aa Aaa Aaaaa Aaaaaaaaaaaaa Aaaa Aaaaa Aaa Aaaaa Aaaaa Aa Aaa Aaaaaaaa Aaaaaaaa Aaaaaaa Aaaaa Aaaaaaaa Aa Aaaaaaaaaa Aa Aaa Aaaaaaaaaaaaaa Aaaa Aaaaa Aaaa Aa Aaaaaaaaaaaaaa Aa Aaaaaaaaaaaaa Aaaaaaaaaaa Aaaaaaaaaa a Aaaaaa Aaaaaaaaaaaa a Aaaaaaaa Aaaaaa Aaaaaaaaaa Aaaaaaaaa Aaaaa Aaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaa Aaaaaaaaa Aaaaaaaa Aaaaa Aaaaaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaaaa Aaaa Aaaaaaaaaaa Aaaaaaaa Aaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaa Aa Aaaaaaa Aaaaaa Aaaaa Aaaaa Aaaa Aaa Aaaaaaaa Aaaaaaaaaaa Aa Aaaaaaaaaaa
Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaa a Aaaaaaaaa Aaaaaaa Aa Aaaaaa Aaaaa Aaaaaa Aaaaaaaaa Aaaaaaaaa Aaaaaaaaaaaaa Aaaaaaa Aaaaa Aaaaaaaa Aaaaaa Aaaaaaaaaa Aaaa Aaaaaa Aa Aaaaaa Aaa Aaaa Aaa Aaa Aaaaaaa a Aaaaaaaaa Aaa Aaaaaaaaaa Aaaaa Aa Aa Aaaaa Aaaaa Aaaa Aaaa a Aa Aaa Aaaaaaaaa Aaaaaaaaaaa
🔒Explores the re-entrancy implications and what an attacker could achieve with script execution during style recalculation
Subscribe to read more
Audit directions
a Aaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaa Aaaaaaaaa Aaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaa Aaa Aaaaaaa Aaaaa Aaaaaaaaaaa Aaaaa Aaa Aaaaaaaaaa Aa Aaaaaaa Aaaaaa Aaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaaa Aaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaa Aaaaa Aaaaaaa Aaa Aaaaaa Aa Aaaaaaaaa Aaaa a Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaa Aaaa Aaaaaaaa
a Aaaaaaaa Aaaaaaaaaaa Aaaaaa Aaaaa Aaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaaaaaa Aaaa Aaaaaaaaaa Aaaaaaaaaa Aa Aaa Aaaaa Aaa Aaa Aaaaaaa Aaaa a Aaaaaaaaaa Aaaa Aaaaaaaaaa Aaaaaa Aa Aaaa Aaaaaaaaaa Aaaaaaaa Aa Aaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaaa Aaa Aaaaa Aaaaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaa Aaaaa Aaaaaaaaa Aaaa Aaaaaaaaaaa Aa Aaaaaaa Aaaaaaaaa Aaaaaa Aaaaaaaaaaaa Aaaaaaaaaaa
a Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aa Aaaaaaa Aaaaaaaaa Aaaaaaaaaa Aaaaaaaaaa Aaa Aaaaaaaaaaaaaaa Aaaaaaa Aaaa Aaaaaaaa Aaaaaaa Aa Aaaaaaaaaaa Aaaaaaaaaaa Aaaaaaa Aaaaaaa Aaaaaaaaaaa Aaaaa Aa Aaaaa Aaaaaa Aaaaaaaaaaaa Aaaa Aaaaa Aaaaaaaa Aaaa Aa a Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aa Aaaaaa Aaaaaaaaaaaa
🔒Multiple audit patterns identified for finding similar ScriptDisallowedScope violations across WebKit's object lifecycle and event dispatch paths
Subscribe to read more