Move async same document navigation special-case to DocumentLoader Normally, same document navigations are synchronous. However, if the same document navigation is requested by a cross-origin document, we perform it asynchronously to make it harder to leak url information to the initiator. This moves that special-case from NavigationScheduler, which is going away, to DocumentLoader and makes it an implementation detail of DocumentLoader::CommitSameDocumentNavigation. Bug: 914587 Change-Id: I78b2d49d23fec4ad2a83139cc4a4ce39f22de4de Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1584367 Reviewed-by: Dmitry Gozman <dgozman@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/master@{#654919}
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index 5d1a52a..0a312155 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -984,9 +984,24 @@ } } - CommitSameDocumentNavigationInternal(url, frame_load_type, history_item, - client_redirect_policy, origin_document, - has_event, std::move(extra_data)); + // If the requesting document is cross-origin, perform the navigation + // asynchronously to minimize the navigator's ability to execute timing + // attacks. + if (origin_document && !origin_document->GetSecurityOrigin()->CanAccess( + frame_->GetDocument()->GetSecurityOrigin())) { + frame_->GetTaskRunner(TaskType::kInternalLoading) + ->PostTask( + FROM_HERE, + WTF::Bind(&DocumentLoader::CommitSameDocumentNavigationInternal, + WrapWeakPersistent(this), url, frame_load_type, + WrapPersistent(history_item), client_redirect_policy, + WrapPersistent(origin_document), has_event, + std::move(extra_data))); + } else { + CommitSameDocumentNavigationInternal( + url, frame_load_type, history_item, client_redirect_policy, + origin_document, has_event, std::move(extra_data)); + } return mojom::CommitResult::Ok; } @@ -998,6 +1013,11 @@ Document* initiating_document, bool has_event, std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) { + // If this function was scheduled to run asynchronously, this DocumentLoader + // might have been detached before the task ran. + if (!frame_) + return; + if (!IsBackForwardLoadType(frame_load_type)) { SetNavigationType(has_event ? kWebNavigationTypeLinkClicked : kWebNavigationTypeOther);
diff --git a/third_party/blink/renderer/core/loader/navigation_scheduler.cc b/third_party/blink/renderer/core/loader/navigation_scheduler.cc index 51646494..2529329 100644 --- a/third_party/blink/renderer/core/loader/navigation_scheduler.cc +++ b/third_party/blink/renderer/core/loader/navigation_scheduler.cc
@@ -250,23 +250,15 @@ frame_load_type = WebFrameLoadType::kReplaceCurrentItem; base::TimeTicks input_timestamp = InputTimestamp(); - // If the URL we're going to navigate to is the same as the current one, - // except for the fragment part, we don't need to schedule the location - // change. We'll skip this optimization for cross-origin navigations to - // minimize the navigator's ability to execute timing attacks. - if (origin_document->GetSecurityOrigin()->CanAccess( - frame_->GetDocument()->GetSecurityOrigin())) { - if (url.HasFragmentIdentifier() && - EqualIgnoringFragmentIdentifier(frame_->GetDocument()->Url(), url)) { - FrameLoadRequest request(origin_document, ResourceRequest(url), "_self"); - request.SetInputStartTime(input_timestamp); - if (frame_load_type == WebFrameLoadType::kReplaceCurrentItem) { - request.SetClientRedirectReason( - ClientNavigationReason::kFrameNavigation); - } - frame_->Loader().StartNavigation(request, frame_load_type); - return; + if (url.HasFragmentIdentifier() && + EqualIgnoringFragmentIdentifier(frame_->GetDocument()->Url(), url)) { + FrameLoadRequest request(origin_document, ResourceRequest(url), "_self"); + request.SetInputStartTime(input_timestamp); + if (frame_load_type == WebFrameLoadType::kReplaceCurrentItem) { + request.SetClientRedirectReason(ClientNavigationReason::kFrameNavigation); } + frame_->Loader().StartNavigation(request, frame_load_type); + return; } Schedule(ScheduledFrameNavigation::Create(origin_document, url,