[18] Navigation API null-deref via reload() in pageswap handler
Rated Medium because the diff fixes a renderer-reachable null deref via re-entrant
navigation.reload()inside apageswaphandler. Pre-fix, the nested reload cleared the provisionalDocumentLoaderthatHistoryController::updateForCommit()was about to dereference.
Source/WebCore/page/Navigation.cpp
Patch Details
Navigation::reload() now consults frame()->loader().isDispatchingPageSwapEvent() and rejects with InvalidStateError if true — the same guard already present in Navigation::navigate() per Bug 303364.
Missing re-entrancy guard on a Navigation API entry point invoked from inside a pageswap event handler, allowing nested code to invalidate provisional commit state the outer caller still depends on.
A reload reaching the committed phase fires pageswap; the handler synchronously calling navigation.reload() ran a sync policy check that cleared FrameLoader::m_provisionalDocumentLoader. When the handler returned, updateForCommit() dereferenced the now-null loader.
This is an explicit variant fix — the commit message names Bug 303364 (which applied the same guard to navigate()) and ports it to reload(). Variant fixes lagging the original by months is a recurring pattern in this subsystem.
This vulnerability weakens renderer process availability by allowing same-origin script to deterministically crash WebContent. Promotion beyond crash would require the dangling state to be reused for a memory-safety primitive, which is not directly evident from this diff.
Audit directions
- Other Navigation API entry points lacking the guard. Audit
traverseTo,back,forward,updateCurrentEntry, and entries-mutating helpers forframe()->loader().isDispatchingPageSwapEvent()consultation. - Native commit-pipeline functions dereferencing
provisionalDocumentLoader()after JS-observable events. AuditHistoryController::updateForCommit()and adjacent commit-time methods for every load-state pointer read after pageswap, beforeunload, unload, pagehide, navigate-event dispatch. isDispatching*predicates with partial coverage. Grep for the predicate and enumerate the API surface it's meant to protect.