tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit fd219ed8433994befcbfa5d3b8387597de836bde
parent 055609159c4dac7a1c108377ae88890d8129b275
Author: Vincent Hilla <vhilla@mozilla.com>
Date:   Mon,  5 Jan 2026 14:31:53 +0000

Bug 2007897 - Use normal load path when initial about:blank doesn't match remote type. r=hsivonen,dom-core

Differential Revision: https://phabricator.services.mozilla.com/D277764

Diffstat:
Mdocshell/base/nsDocShell.cpp | 76++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mdocshell/base/nsDocShell.h | 5+++--
Mdocshell/test/browser/browser.toml | 6++++++
Adocshell/test/browser/browser_bug2007897.js | 48++++++++++++++++++++++++++++++++++++++++++++++++
Adocshell/test/browser/file_2007897.html | 1+
Mdom/base/nsObjectLoadingContent.cpp | 16+++++++++++-----
6 files changed, 115 insertions(+), 37 deletions(-)

diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp @@ -10685,18 +10685,51 @@ nsIPrincipal* nsDocShell::GetInheritedPrincipal( return true; } -bool nsDocShell::IsAboutBlankLoadOntoInitialAboutBlank( - nsIURI* aURI, nsIPrincipal* aPrincipalToInherit) { +bool nsDocShell::ShouldDoInitialAboutBlankSyncLoad( + nsIURI* aURI, nsDocShellLoadState* aLoadState, + nsIPrincipal* aPrincipalToInherit) { MOZ_ASSERT(mDocumentViewer); - bool ret = !mHasStartedLoadingOtherThanInitialBlankURI && - mDocumentViewer->GetDocument()->IsUncommittedInitialDocument() && - NS_IsAboutBlankAllowQueryAndFragment(aURI); - if (ret && !aPrincipalToInherit) { + + if (!NS_IsAboutBlankAllowQueryAndFragment(aURI)) { + return false; + } + + if (aLoadState->IsInitialAboutBlankHandlingProhibited()) { + return false; + } + + if (mHasStartedLoadingOtherThanInitialBlankURI || + !mDocumentViewer->GetDocument()->IsUncommittedInitialDocument()) { + return false; + } + + if (!aPrincipalToInherit) { MOZ_ASSERT( mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal(), "Load looks like first load but does not want principal inheritance."); + } else { + if (XRE_IsContentProcess() && + !ValidatePrincipalCouldPotentiallyBeLoadedBy( + aPrincipalToInherit, ContentChild::GetSingleton()->GetRemoteType(), + {})) { + // Principal doesn't match our remote type, so the we need the normal + // load path to do a process switch. + return false; + } + + // If a page opens about:blank, it will have a content principal. + // If it is then restored after a restart, we might not have initialized + // UsesOAC for it. If this is the case, do a normal load (bug 2004165). + // XXX bug 2005205 tracks removing this workaround. + if (aLoadState->LoadIsFromSessionHistory() && + !mBrowsingContext->Group() + ->UsesOriginAgentCluster(aPrincipalToInherit) + .isSome()) { + return false; + } } - return ret; + + return true; } void nsDocShell::UnsuppressPaintingIfNoNavigationAwayFromAboutBlank( @@ -10977,29 +11010,14 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState, inheritPrincipal = inheritAttrs && !uri->SchemeIs("data"); } - // If a page opens about:blank, it will have a content principal. - // If it is then restored after a restart, we might not have initialized - // UsesOAC for it. If this is the case, do a normal load (bug 2004647). - // XXX bug 2005205 tracks removing this workaround. - const auto shouldSkipSyncLoadForSHRestore = [&] { - return aLoadState->LoadIsFromSessionHistory() && - aLoadState->PrincipalToInherit() && - !mBrowsingContext->Group() - ->UsesOriginAgentCluster(aLoadState->PrincipalToInherit()) - .isSome(); - }; - MOZ_ASSERT_IF(NS_IsAboutBlankAllowQueryAndFragment(uri) && aLoadState->PrincipalToInherit(), inheritPrincipal); // See https://bugzilla.mozilla.org/show_bug.cgi?id=1736570 - const bool isAboutBlankLoadOntoInitialAboutBlank = - !aLoadState->IsInitialAboutBlankHandlingProhibited() && - IsAboutBlankLoadOntoInitialAboutBlank(uri, - aLoadState->PrincipalToInherit()) && - !shouldSkipSyncLoadForSHRestore(); + const bool doInitialSyncLoad = ShouldDoInitialAboutBlankSyncLoad( + uri, aLoadState, aLoadState->PrincipalToInherit()); - if (!isAboutBlankLoadOntoInitialAboutBlank) { + if (!doInitialSyncLoad) { // https://wicg.github.io/document-picture-in-picture/#close-on-navigate if (Document* doc = GetExtantDocument()) { NS_DispatchToMainThread(NS_NewRunnableFunction( @@ -11017,8 +11035,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState, // in more places. if (aLoadState->GetLoadingSessionHistoryInfo()) { SetLoadingSessionHistoryInfo(*aLoadState->GetLoadingSessionHistoryInfo()); - } else if (isAboutBlankLoadOntoInitialAboutBlank && - mozilla::SessionHistoryInParent()) { + } else if (doInitialSyncLoad && mozilla::SessionHistoryInParent()) { // Materialize LoadingSessionHistoryInfo here, because DocumentChannel // loads have it, and later history behavior depends on it existing. UniquePtr<SessionHistoryInfo> entry = MakeUnique<SessionHistoryInfo>( @@ -11148,7 +11165,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState, } RefPtr<WindowContext> context = mBrowsingContext->GetCurrentWindowContext(); - if (isAboutBlankLoadOntoInitialAboutBlank) { + if (doInitialSyncLoad) { // Stay on the eagerly created document and adjust it to match what we would // be loading. return CompleteInitialAboutBlankLoad(aLoadState, loadInfo); @@ -11232,8 +11249,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState, mBrowsingContext, uriModified, Some(isEmbeddingBlockedError)); nsCOMPtr<nsIChannel> channel; - if (DocumentChannel::CanUseDocumentChannel(uri) && - !isAboutBlankLoadOntoInitialAboutBlank) { + if (DocumentChannel::CanUseDocumentChannel(uri)) { channel = DocumentChannel::CreateForDocument( aLoadState, loadInfo, loadFlags, this, cacheKey, uriModified, isEmbeddingBlockedError); diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h @@ -677,8 +677,9 @@ class nsDocShell final : public nsDocLoader, bool aNotifiedBeforeUnloadListeners = false); public: - bool IsAboutBlankLoadOntoInitialAboutBlank(nsIURI* aURI, - nsIPrincipal* aPrincipalToInherit); + bool ShouldDoInitialAboutBlankSyncLoad(nsIURI* aURI, + nsDocShellLoadState* aLoadState, + nsIPrincipal* aPrincipalToInherit); void UnsuppressPaintingIfNoNavigationAwayFromAboutBlank( mozilla::PresShell* aPresShell); diff --git a/docshell/test/browser/browser.toml b/docshell/test/browser/browser.toml @@ -3,6 +3,7 @@ support-files = [ "Bug422543Child.sys.mjs", "dummy_page.html", "favicon_bug655270.ico", + "file_2007897.html", "file_bug234628-1-child.html", "file_bug234628-1.html", "file_bug234628-10-child.xhtml", @@ -281,6 +282,11 @@ skip-if = [ "debug", # bug 2005202 ] +["browser_bug2007897.js"] +skip-if = [ + "debug", # bug 2005202 +] + ["browser_click_link_within_view_source.js"] ["browser_closewatcher_integration.js"] diff --git a/docshell/test/browser/browser_bug2007897.js b/docshell/test/browser/browser_bug2007897.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { TabStateFlusher } = ChromeUtils.importESModule( + "resource:///modules/sessionstore/TabStateFlusher.sys.mjs" +); + +// Restore a page containing a cross-origin about:blank iframe +add_task(async function test_restore_with_cross_origin_blank_iframe() { + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "https://example.com/browser/docshell/test/browser/file_2007897.html" + ); + + const blankLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, { + wantLoad: "about:blank", + includeSubFrames: true, + }); + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + const ifr = content.document.querySelector("iframe"); + await SpecialPowers.spawn(ifr, [], () => { + // Must use wrappedJSObject so we use the right content principal + content.wrappedJSObject.location = "about:blank"; + }); + }); + await blankLoaded; + + await TabStateFlusher.flush(tab.linkedBrowser); + + const sessionStoreClosedObjectsChanged = TestUtils.topicObserved( + "sessionstore-closed-objects-changed" + ); + gBrowser.removeTab(tab); + await sessionStoreClosedObjectsChanged; + const restoredTab = SessionStore.undoCloseTab(window, 0); + await BrowserTestUtils.waitForEvent(restoredTab, "SSTabRestored"); + + // The crash doesn't cause the test to fail, so check if the iframe was restored + await SpecialPowers.spawn(restoredTab.linkedBrowser, [], async () => { + const ifr = content.document.querySelector("iframe"); + Assert.ok(ifr, "did not crash"); + Assert.ok(!ifr.contentDocument && !ifr.document, "iframe is restricted"); + }); + + BrowserTestUtils.removeTab(restoredTab); +}); diff --git a/docshell/test/browser/file_2007897.html b/docshell/test/browser/file_2007897.html @@ -0,0 +1 @@ +<iframe src="https://example.org"></iframe> diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp @@ -1404,11 +1404,17 @@ nsresult nsObjectLoadingContent::CloseChannel() { bool nsObjectLoadingContent::IsAboutBlankLoadOntoInitialAboutBlank( nsIURI* aURI, bool aInheritPrincipal, nsIPrincipal* aPrincipalToInherit) { - return NS_IsAboutBlank(aURI) && aInheritPrincipal && - (!mFrameLoader || !mFrameLoader->GetExistingDocShell() || - mFrameLoader->GetExistingDocShell() - ->IsAboutBlankLoadOntoInitialAboutBlank(aURI, - aPrincipalToInherit)); + if (!NS_IsAboutBlankAllowQueryAndFragment(aURI) || !aInheritPrincipal) { + return false; + } + + if (!mFrameLoader || !mFrameLoader->GetExistingDocShell()) { + return false; + } + + RefPtr<nsDocShellLoadState> dummyLoadState = new nsDocShellLoadState(mURI); + return mFrameLoader->GetExistingDocShell()->ShouldDoInitialAboutBlankSyncLoad( + aURI, dummyLoadState, aPrincipalToInherit); } nsresult nsObjectLoadingContent::OpenChannel() {