From 94d309143f1211cb58b7167bae7f0e12dc387971 Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Mon, 22 Aug 2022 20:32:02 +0300 Subject: [PATCH] Backed out 5 changesets (bug 1694993) for bc failure on browser_cross_process_csp_inheritance.js Backed out changeset 1d21d911b3e7 (bug 1694993) Backed out changeset 3b412d5fbdcf (bug 1694993) Backed out changeset c9585ce37fe5 (bug 1694993) Backed out changeset 05d7cbbfe9e2 (bug 1694993) Backed out changeset 3821545ab46b (bug 1694993) --- docshell/test/navigation/mochitest.ini | 1 - .../test_open_javascript_noopener.html | 44 --- dom/base/nsGlobalWindowOuter.cpp | 18 +- dom/base/nsGlobalWindowOuter.h | 4 +- dom/base/nsPIDOMWindow.h | 8 +- .../storage_session_window_reopen.window.js | 26 -- .../windowwatcher/nsWindowWatcher.cpp | 342 ++++++++---------- xpfe/appshell/nsAppShellService.cpp | 46 +-- 8 files changed, 185 insertions(+), 304 deletions(-) delete mode 100644 docshell/test/navigation/test_open_javascript_noopener.html delete mode 100644 testing/web-platform/tests/webstorage/storage_session_window_reopen.window.js diff --git a/docshell/test/navigation/mochitest.ini b/docshell/test/navigation/mochitest.ini index 35baa39f33b3..38509b83aedb 100644 --- a/docshell/test/navigation/mochitest.ini +++ b/docshell/test/navigation/mochitest.ini @@ -215,4 +215,3 @@ skip-if = !sessionHistoryInParent support-files = file_ship_beforeunload_fired.html skip-if = !sessionHistoryInParent -[test_open_javascript_noopener.html] diff --git a/docshell/test/navigation/test_open_javascript_noopener.html b/docshell/test/navigation/test_open_javascript_noopener.html deleted file mode 100644 index 81a6b70d6185..000000000000 --- a/docshell/test/navigation/test_open_javascript_noopener.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index cd8aabd96a66..6b95fcd529cb 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -1756,18 +1756,22 @@ bool nsGlobalWindowOuter::WouldReuseInnerWindow(Document* aNewDocument) { return false; } -void nsGlobalWindowOuter::SetInitialPrincipal( - nsIPrincipal* aNewWindowPrincipal, nsIContentSecurityPolicy* aCSP, +void nsGlobalWindowOuter::SetInitialPrincipalToSubject( + nsIContentSecurityPolicy* aCSP, const Maybe& aCOEP) { + // First, grab the subject principal. + nsCOMPtr newWindowPrincipal = + nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller(); + // We should never create windows with an expanded principal. // If we have a system principal, make sure we're not using it for a content // docshell. // NOTE: Please keep this logic in sync with // nsAppShellService::JustCreateTopWindow - if (nsContentUtils::IsExpandedPrincipal(aNewWindowPrincipal) || - (aNewWindowPrincipal->IsSystemPrincipal() && + if (nsContentUtils::IsExpandedPrincipal(newWindowPrincipal) || + (newWindowPrincipal->IsSystemPrincipal() && GetBrowsingContext()->IsContent())) { - aNewWindowPrincipal = nullptr; + newWindowPrincipal = nullptr; } // If there's an existing document, bail if it either: @@ -1775,7 +1779,7 @@ void nsGlobalWindowOuter::SetInitialPrincipal( // (a) is not an initial about:blank document, or if (!mDoc->IsInitialDocument()) return; // (b) already has the correct principal. - if (mDoc->NodePrincipal() == aNewWindowPrincipal) return; + if (mDoc->NodePrincipal() == newWindowPrincipal) return; #ifdef DEBUG // If we have a document loaded at this point, it had better be about:blank. @@ -1791,7 +1795,7 @@ void nsGlobalWindowOuter::SetInitialPrincipal( // Use the subject (or system) principal as the storage principal too until // the new window finishes navigating and gets a real storage principal. nsDocShell::Cast(GetDocShell()) - ->CreateAboutBlankContentViewer(aNewWindowPrincipal, aNewWindowPrincipal, + ->CreateAboutBlankContentViewer(newWindowPrincipal, newWindowPrincipal, aCSP, nullptr, /* aIsInitialDocument */ true, aCOEP); diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h index b3ed30b18770..e8285b0fb892 100644 --- a/dom/base/nsGlobalWindowOuter.h +++ b/dom/base/nsGlobalWindowOuter.h @@ -305,8 +305,8 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, mozilla::dom::EventTarget* aChromeEventHandler) override; // Outer windows only. - virtual void SetInitialPrincipal( - nsIPrincipal* aNewWindowPrincipal, nsIContentSecurityPolicy* aCSP, + virtual void SetInitialPrincipalToSubject( + nsIContentSecurityPolicy* aCSP, const mozilla::Maybe& aCoep) override; diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 00a5b65ad1eb..0b013446c557 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -880,10 +880,10 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy { return mDoc; } - // Set the window up with an about:blank document with the given principal and - // potentially a CSP and a COEP. - virtual void SetInitialPrincipal( - nsIPrincipal* aNewWindowPrincipal, nsIContentSecurityPolicy* aCSP, + // Set the window up with an about:blank document with the current subject + // principal and potentially a CSP and a COEP. + virtual void SetInitialPrincipalToSubject( + nsIContentSecurityPolicy* aCSP, const mozilla::Maybe& aCoep) = 0; // Returns an object containing the window's state. This also suspends diff --git a/testing/web-platform/tests/webstorage/storage_session_window_reopen.window.js b/testing/web-platform/tests/webstorage/storage_session_window_reopen.window.js deleted file mode 100644 index 1ce17d47f1d8..000000000000 --- a/testing/web-platform/tests/webstorage/storage_session_window_reopen.window.js +++ /dev/null @@ -1,26 +0,0 @@ -test(function() { - var popup = window.open("", "sessionStorageTestWindow"); - - sessionStorage.setItem("FOO", "BAR"); - - var reopened = window.open("", "sessionStorageTestWindow"); - - assert_equals( - popup, - reopened, - "window.open with the same name should re-open the same window" - ); - - assert_equals( - sessionStorage.getItem("FOO"), - "BAR", - "local sessionStorage is correct" - ); - assert_equals( - popup.sessionStorage.getItem("FOO"), - null, - "popup sessionStorage is correct" - ); - - popup.close(); -}, "ensure that re-opening a named window doesn't copy sessionStorage"); diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp index 337b6d4339ff..3983d580cd11 100644 --- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp +++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp @@ -629,10 +629,10 @@ nsresult nsWindowWatcher::OpenWindowInternal( nsAutoString name; // string version of aName nsCOMPtr uriToLoad; // from aUrl, if any nsCOMPtr - parentTreeOwner; // from the parent window, if any - RefPtr targetBC; // from the new window + parentTreeOwner; // from the parent window, if any + RefPtr newBC; // from the new window - nsCOMPtr parentOuterWin = + nsCOMPtr parentWindow = aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr; NS_ENSURE_ARG_POINTER(aResult); @@ -643,8 +643,8 @@ nsresult nsWindowWatcher::OpenWindowInternal( return NS_ERROR_FAILURE; } - if (parentOuterWin) { - parentTreeOwner = parentOuterWin->GetTreeOwner(); + if (parentWindow) { + parentTreeOwner = parentWindow->GetTreeOwner(); } // We expect BrowserParent to have provided us the absolute URI of the window @@ -676,13 +676,9 @@ nsresult nsWindowWatcher::OpenWindowInternal( } RefPtr parentBC( - parentOuterWin ? parentOuterWin->GetBrowsingContext() : nullptr); + parentWindow ? parentWindow->GetBrowsingContext() : nullptr); nsCOMPtr parentDocShell(parentBC ? parentBC->GetDocShell() : nullptr); - RefPtr parentDoc(parentOuterWin ? parentOuterWin->GetDoc() - : nullptr); - nsCOMPtr parentInnerWin( - parentOuterWin ? parentOuterWin->GetCurrentInnerWindow() : nullptr); // Return null for any attempt to trigger a load from a discarded browsing // context. The spec is non-normative, and doesn't specify what should happen @@ -698,18 +694,18 @@ nsresult nsWindowWatcher::OpenWindowInternal( } // try to find an extant browsing context with the given name - targetBC = GetBrowsingContextByName(name, aForceNoOpener, parentBC); + newBC = GetBrowsingContextByName(name, aForceNoOpener, parentBC); // Do sandbox checks here, instead of waiting until nsIDocShell::LoadURI. // The state of the window can change before this call and if we are blocked // because of sandboxing, we wouldn't want that to happen. - if (parentBC && parentBC->IsSandboxedFrom(targetBC)) { + if (parentBC && parentBC->IsSandboxedFrom(newBC)) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } // If our target BrowsingContext is still pending initialization, ignore the // navigation request targeting it. - if (targetBC && NS_WARN_IF(targetBC->GetPendingInitialization())) { + if (newBC && NS_WARN_IF(newBC->GetPendingInitialization())) { return NS_ERROR_ABORT; } @@ -719,7 +715,8 @@ nsresult nsWindowWatcher::OpenWindowInternal( bool hasChromeParent = !XRE_IsContentProcess(); if (aParent) { // Check if the parent document has chrome privileges. - hasChromeParent = parentDoc && nsContentUtils::IsChromeDoc(parentDoc); + Document* doc = parentWindow->GetDoc(); + hasChromeParent = doc && nsContentUtils::IsChromeDoc(doc); } bool isCallerChrome = nsContentUtils::LegacyIsCallerChromeOrNativeCode(); @@ -811,56 +808,10 @@ nsresult nsWindowWatcher::OpenWindowInternal( } } - // Now that the jsapiChromeGuard has been set, fetch the system principal - // potentially configured by it. We want to make sure to respect any principal - // changes imposed by that guard throughout this function. - // - // Note: The check for the current JSContext isn't necessarily sensical. - // It's just designed to preserve old semantics during a mass-conversion - // patch. - // Bug 1498605 verify usages of systemPrincipal here - JSContext* cx = nsContentUtils::GetCurrentJSContext(); - nsCOMPtr subjectPrincipal = - cx ? nsContentUtils::SubjectPrincipal() - : nsContentUtils::GetSystemPrincipal(); - MOZ_ASSERT(subjectPrincipal); - - nsCOMPtr newWindowPrincipal; - if (!targetBC) { - if (windowTypeIsChrome) { - // If we are creating a chrome window, we must be called with a system - // principal, and should inherit that for the new chrome window. - MOZ_RELEASE_ASSERT(subjectPrincipal->IsSystemPrincipal(), - "Only system principals can create chrome windows"); - newWindowPrincipal = subjectPrincipal; - } else if (nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal)) { - // Don't allow initial about:blank documents to inherit a system or - // expanded principal, instead replace it with a null principal. We can't - // inherit origin attributes from the system principal, so use the parent - // BC if it's available. - if (parentBC) { - newWindowPrincipal = NullPrincipal::CreateWithInheritedAttributes( - parentBC->OriginAttributesRef()); - } else { - newWindowPrincipal = NullPrincipal::CreateWithoutOriginAttributes(); - } - } else if (aForceNoOpener) { - // If we're opening a new window with noopener, create a new opaque - // principal for the new window, rather than re-using the existing - // principal. - newWindowPrincipal = - NullPrincipal::CreateWithInheritedAttributes(subjectPrincipal); - } else { - // Finally, if there's an opener relationship and it's not a special - // principal, we should inherit that principal for the new window. - newWindowPrincipal = subjectPrincipal; - } - } - // Information used when opening new content windows. This object will be // passed through to the inner nsFrameLoader. RefPtr openWindowInfo; - if (!targetBC && !windowTypeIsChrome) { + if (!newBC && !windowTypeIsChrome) { openWindowInfo = new nsOpenWindowInfo(); openWindowInfo->mForceNoOpener = aForceNoOpener; openWindowInfo->mParent = parentBC; @@ -871,12 +822,17 @@ nsresult nsWindowWatcher::OpenWindowInternal( // want it to match the current remoteness. openWindowInfo->mIsRemote = XRE_IsContentProcess(); - // Inherit our OriginAttributes from the computed new window principal. - MOZ_ASSERT( - newWindowPrincipal && - !nsContentUtils::IsSystemOrExpandedPrincipal(newWindowPrincipal)); - openWindowInfo->mOriginAttributes = - newWindowPrincipal->OriginAttributesRef(); + // If we have a non-system non-expanded subject principal, we can inherit + // our OriginAttributes from it. + nsCOMPtr subjectPrincipal = + nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller(); + if (subjectPrincipal && + !nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal)) { + openWindowInfo->mOriginAttributes = + subjectPrincipal->OriginAttributesRef(); + } else if (parentBC) { + openWindowInfo->mOriginAttributes = parentBC->OriginAttributesRef(); + } MOZ_DIAGNOSTIC_ASSERT( !parentBC || openWindowInfo->mOriginAttributes.EqualsIgnoringFPD( @@ -887,7 +843,7 @@ nsresult nsWindowWatcher::OpenWindowInternal( uint32_t activeDocsSandboxFlags = 0; nsCOMPtr cspToInheritForAboutBlank; Maybe coepToInheritForAboutBlank; - if (!targetBC) { + if (!newBC) { // We're going to either open up a new window ourselves or ask a // nsIWindowProvider for one. In either case, we'll want to set the right // name on it. @@ -895,20 +851,22 @@ nsresult nsWindowWatcher::OpenWindowInternal( // If the parent trying to open a new window is sandboxed // without 'allow-popups', this is not allowed and we fail here. - if (parentDoc) { - // Save sandbox flags for copying to new browsing context (docShell). - activeDocsSandboxFlags = parentDoc->GetSandboxFlags(); + if (aParent) { + if (Document* doc = parentWindow->GetDoc()) { + // Save sandbox flags for copying to new browsing context (docShell). + activeDocsSandboxFlags = doc->GetSandboxFlags(); - if (!aForceNoOpener) { - cspToInheritForAboutBlank = parentDoc->GetCsp(); - coepToInheritForAboutBlank = parentDoc->GetEmbedderPolicy(); - } + if (!aForceNoOpener) { + cspToInheritForAboutBlank = doc->GetCsp(); + coepToInheritForAboutBlank = doc->GetEmbedderPolicy(); + } - // Check to see if this frame is allowed to navigate, but don't check if - // we're printing, as that's not a real navigation. - if (aPrintKind == PRINT_NONE && - (activeDocsSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION)) { - return NS_ERROR_DOM_INVALID_ACCESS_ERR; + // Check to see if this frame is allowed to navigate, but don't check if + // we're printing, as that's not a real navigation. + if (aPrintKind == PRINT_NONE && + (activeDocsSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION)) { + return NS_ERROR_DOM_INVALID_ACCESS_ERR; + } } } @@ -926,17 +884,17 @@ nsresult nsWindowWatcher::OpenWindowInternal( rv = provider->ProvideWindow( openWindowInfo, chromeFlags, aCalledFromJS, uriToLoad, name, featuresStr, aForceNoOpener, aForceNoReferrer, isPopupRequested, - aLoadState, &windowIsNew, getter_AddRefs(targetBC)); + aLoadState, &windowIsNew, getter_AddRefs(newBC)); - if (NS_SUCCEEDED(rv) && targetBC) { - nsCOMPtr newDocShell = targetBC->GetDocShell(); + if (NS_SUCCEEDED(rv) && newBC) { + nsCOMPtr newDocShell = newBC->GetDocShell(); // If this is a new window, but it's incompatible with the current // userContextId, we ignore it and we pretend that nothing has been // returned by ProvideWindow. if (!windowIsNew && newDocShell) { if (!CheckUserContextCompatibility(newDocShell)) { - targetBC = nullptr; + newBC = nullptr; windowIsNew = false; } } @@ -955,7 +913,7 @@ nsresult nsWindowWatcher::OpenWindowInternal( bool newWindowShouldBeModal = false; bool parentIsModal = false; - if (!targetBC) { + if (!newBC) { if (XRE_IsContentProcess()) { // If our window provider failed to provide a window in the content // process, we cannot recover. Reject the window open request and bail. @@ -1009,9 +967,9 @@ nsresult nsWindowWatcher::OpenWindowInternal( nsCOMPtr newChrome; nsCOMPtr parentTopInnerWindow; - if (parentOuterWin) { + if (parentWindow) { nsCOMPtr parentTopWindow = - parentOuterWin->GetInProcessTop(); + parentWindow->GetInProcessTop(); if (parentTopWindow) { parentTopInnerWindow = parentTopWindow->GetCurrentInnerWindow(); } @@ -1048,53 +1006,53 @@ nsresult nsWindowWatcher::OpenWindowInternal( if (!newDocShellItem) { rv = NS_ERROR_FAILURE; } - targetBC = newDocShellItem->GetBrowsingContext(); + newBC = newDocShellItem->GetBrowsingContext(); } } } // better have a window to use by this point - if (!targetBC) { + if (!newBC) { return rv; } // If our parent is sandboxed, set it as the one permitted sandboxed navigator // on the new window we're opening. if (activeDocsSandboxFlags && parentBC) { - MOZ_ALWAYS_SUCCEEDS(targetBC->SetOnePermittedSandboxedNavigator(parentBC)); + MOZ_ALWAYS_SUCCEEDS(newBC->SetOnePermittedSandboxedNavigator(parentBC)); } if (!aForceNoOpener && parentBC) { // If we've created a new content window, its opener should have been set // when its BrowsingContext was created, in order to ensure that the context // is loaded within the correct BrowsingContextGroup. - if (windowIsNew && targetBC->IsContent()) { + if (windowIsNew && newBC->IsContent()) { if (parentBC->IsDiscarded()) { // If the parent BC was discarded in a nested event loop before we got // to this point, we can't set it as the opener. Ideally we would still // set `HadOriginalOpener()` in that case, but that's somewhat // nontrivial, and not worth the effort given the nature of the corner // case (see comment in `nsFrameLoader::CreateBrowsingContext`. - MOZ_RELEASE_ASSERT(targetBC->GetOpenerId() == parentBC->Id() || - targetBC->GetOpenerId() == 0); + MOZ_RELEASE_ASSERT(newBC->GetOpenerId() == parentBC->Id() || + newBC->GetOpenerId() == 0); } else { - MOZ_RELEASE_ASSERT(targetBC->GetOpenerId() == parentBC->Id()); - MOZ_RELEASE_ASSERT(targetBC->HadOriginalOpener()); + MOZ_RELEASE_ASSERT(newBC->GetOpenerId() == parentBC->Id()); + MOZ_RELEASE_ASSERT(newBC->HadOriginalOpener()); } } else { // Update the opener for an existing or chrome BC. - targetBC->SetOpener(parentBC); + newBC->SetOpener(parentBC); } } - RefPtr targetDocShell(nsDocShell::Cast(targetBC->GetDocShell())); + RefPtr newDocShell(nsDocShell::Cast(newBC->GetDocShell())); // As required by spec, new windows always start out same-process, even if the // URL being loaded will eventually load in a new process. - MOZ_DIAGNOSTIC_ASSERT(!windowIsNew || targetDocShell); + MOZ_DIAGNOSTIC_ASSERT(!windowIsNew || newDocShell); // New top-level windows are only opened in the parent process and are, by // definition, always in-process. - MOZ_DIAGNOSTIC_ASSERT(!isNewToplevelWindow || targetDocShell); + MOZ_DIAGNOSTIC_ASSERT(!isNewToplevelWindow || newDocShell); // Copy sandbox flags to the new window if activeDocsSandboxFlags says to do // so. Note that it's only nonzero if the window is new, so clobbering @@ -1102,46 +1060,45 @@ nsresult nsWindowWatcher::OpenWindowInternal( if (activeDocsSandboxFlags & SANDBOX_PROPAGATES_TO_AUXILIARY_BROWSING_CONTEXTS) { MOZ_ASSERT(windowIsNew, "Should only get here for new windows"); - MOZ_ALWAYS_SUCCEEDS(targetBC->SetSandboxFlags(activeDocsSandboxFlags)); + MOZ_ALWAYS_SUCCEEDS(newBC->SetSandboxFlags(activeDocsSandboxFlags)); MOZ_ALWAYS_SUCCEEDS( - targetBC->SetInitialSandboxFlags(targetBC->GetSandboxFlags())); + newBC->SetInitialSandboxFlags(newBC->GetSandboxFlags())); } - RefPtr targetOuterWin( - nsGlobalWindowOuter::Cast(targetBC->GetDOMWindow())); + RefPtr win( + nsGlobalWindowOuter::Cast(newBC->GetDOMWindow())); #ifdef DEBUG - if (targetOuterWin && windowIsNew) { + if (win && windowIsNew) { // Assert that we're not loading things right now. If we are, when // that load completes it will clobber whatever principals we set up // on this new window! nsCOMPtr chan; - targetDocShell->GetDocumentChannel(getter_AddRefs(chan)); + newDocShell->GetDocumentChannel(getter_AddRefs(chan)); MOZ_ASSERT(!chan, "Why is there a document channel?"); - if (RefPtr doc = targetOuterWin->GetExtantDoc()) { + if (RefPtr doc = win->GetExtantDoc()) { MOZ_ASSERT(doc->IsInitialDocument(), "New window's document should be an initial document"); } } #endif - MOZ_ASSERT(targetOuterWin || !windowIsNew, - "New windows are always created in-process"); + MOZ_ASSERT(win || !windowIsNew, "New windows are always created in-process"); - *aResult = do_AddRef(targetBC).take(); + *aResult = do_AddRef(newBC).take(); if (isNewToplevelWindow) { nsCOMPtr newTreeOwner; - targetDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner)); + newDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner)); MaybeDisablePersistence(sizeSpec, newTreeOwner); } if (aDialog && aArgv) { - MOZ_ASSERT(targetOuterWin); - NS_ENSURE_TRUE(targetOuterWin, NS_ERROR_UNEXPECTED); + MOZ_ASSERT(win); + NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED); // Set the args on the new window. - MOZ_TRY(targetOuterWin->SetArguments(aArgv)); + MOZ_TRY(win->SetArguments(aArgv)); } /* allow a window that we found by name to keep its name (important for cases @@ -1149,40 +1106,52 @@ nsresult nsWindowWatcher::OpenWindowInternal( is not a window name. */ if (windowNeedsName) { if (nameSpecified && !name.LowerCaseEqualsLiteral("_blank")) { - MOZ_ALWAYS_SUCCEEDS(targetBC->SetName(name)); + MOZ_ALWAYS_SUCCEEDS(newBC->SetName(name)); } else { - MOZ_ALWAYS_SUCCEEDS(targetBC->SetName(u""_ns)); + MOZ_ALWAYS_SUCCEEDS(newBC->SetName(u""_ns)); } } // Now we have to set the right opener principal on the new window. Note // that we have to do this _before_ starting any URI loads, thanks to the // sync nature of javascript: loads. + // + // Note: The check for the current JSContext isn't necessarily sensical. + // It's just designed to preserve old semantics during a mass-conversion + // patch. + // Bug 1498605 verify usages of systemPrincipal here + JSContext* cx = nsContentUtils::GetCurrentJSContext(); + nsCOMPtr subjectPrincipal = + cx ? nsContentUtils::SubjectPrincipal() + : nsContentUtils::GetSystemPrincipal(); if (windowIsNew) { - MOZ_DIAGNOSTIC_ASSERT( - !targetBC->IsContent() || - newWindowPrincipal->OriginAttributesRef().EqualsIgnoringFPD( - targetBC->OriginAttributesRef())); + if (subjectPrincipal && + !nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal) && + newBC->IsContent()) { + MOZ_DIAGNOSTIC_ASSERT( + subjectPrincipal->OriginAttributesRef().EqualsIgnoringFPD( + newBC->OriginAttributesRef())); + } bool autoPrivateBrowsing = Preferences::GetBool("browser.privatebrowsing.autostart"); if (!autoPrivateBrowsing && (chromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW)) { - if (targetBC->IsChrome()) { - targetBC->SetUsePrivateBrowsing(false); + if (newBC->IsChrome()) { + newBC->SetUsePrivateBrowsing(false); } MOZ_DIAGNOSTIC_ASSERT( - !targetBC->UsePrivateBrowsing(), + !newBC->UsePrivateBrowsing(), "CHROME_NON_PRIVATE_WINDOW passed, but got private window"); } else if (autoPrivateBrowsing || (chromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW)) { - if (targetBC->IsChrome()) { - targetBC->SetUsePrivateBrowsing(true); + if (newBC->IsChrome()) { + newBC->SetUsePrivateBrowsing(true); } MOZ_DIAGNOSTIC_ASSERT( - targetBC->UsePrivateBrowsing(), + newBC->UsePrivateBrowsing(), "CHROME_PRIVATE_WINDOW passed, but got non-private window"); } @@ -1191,47 +1160,26 @@ nsresult nsWindowWatcher::OpenWindowInternal( // the JS stack, just use the principal of our parent window. In those // cases we do _not_ set the parent window principal as the owner of the // load--since we really don't know who the owner is, just leave it null. - NS_ASSERTION(targetOuterWin == targetDocShell->GetWindow(), - "Different windows??"); + NS_ASSERTION(win == newDocShell->GetWindow(), "Different windows??"); - // Initialize the principal of the initial about:blank document. For - // toplevel windows, this call may have already happened when the window was - // created, but SetInitialPrincipal is safe to call multiple times. - if (targetOuterWin) { + // The principal of the initial about:blank document gets set up in + // nsWindowWatcher::AddWindow. Make sure to call it. In the common case + // this call already happened when the window was created, but + // SetInitialPrincipalToSubject is safe to call multiple times. + if (win) { MOZ_ASSERT(windowIsNew); - MOZ_ASSERT(!targetOuterWin->GetSameProcessOpener() || - targetOuterWin->GetSameProcessOpener() == aParent); - targetOuterWin->SetInitialPrincipal(newWindowPrincipal, - cspToInheritForAboutBlank, - coepToInheritForAboutBlank); + MOZ_ASSERT(!win->GetSameProcessOpener() || + win->GetSameProcessOpener() == aParent); + win->SetInitialPrincipalToSubject(cspToInheritForAboutBlank, + coepToInheritForAboutBlank); if (aIsPopupSpam) { - MOZ_ASSERT(!targetBC->GetIsPopupSpam(), + MOZ_ASSERT(!newBC->GetIsPopupSpam(), "Who marked it as popup spam already???"); // Make sure we don't mess up our counter even if the above assert // fails. - if (!targetBC->GetIsPopupSpam()) { - MOZ_ALWAYS_SUCCEEDS(targetBC->SetIsPopupSpam(true)); - } - } - } - - // Copy the current session storage for the current domain. Don't perform - // the copy if we're forcing noopener, however. - if (!aForceNoOpener && subjectPrincipal && parentDocShell && - targetDocShell) { - const RefPtr parentStorageManager = - parentDocShell->GetBrowsingContext()->GetSessionStorageManager(); - const RefPtr newStorageManager = - targetDocShell->GetBrowsingContext()->GetSessionStorageManager(); - - if (parentStorageManager && newStorageManager) { - RefPtr storage; - parentStorageManager->GetStorage( - parentInnerWin, subjectPrincipal, subjectPrincipal, - targetBC->UsePrivateBrowsing(), getter_AddRefs(storage)); - if (storage) { - newStorageManager->CloneStorage(storage); + if (!newBC->GetIsPopupSpam()) { + MOZ_ALWAYS_SUCCEEDS(newBC->SetIsPopupSpam(true)); } } } @@ -1240,12 +1188,15 @@ nsresult nsWindowWatcher::OpenWindowInternal( // We rely on CalculateChromeFlags to decide whether remote (out-of-process) // tabs should be used. MOZ_DIAGNOSTIC_ASSERT( - targetBC->UseRemoteTabs() == + newBC->UseRemoteTabs() == !!(chromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW)); MOZ_DIAGNOSTIC_ASSERT( - targetBC->UseRemoteSubframes() == + newBC->UseRemoteSubframes() == !!(chromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW)); + nsCOMPtr pInnerWin = + parentWindow ? parentWindow->GetCurrentInnerWindow() : nullptr; + ; RefPtr loadState = aLoadState; if (uriToLoad && loadState) { // If a URI was passed to this function, open that, not what was passed in @@ -1253,7 +1204,7 @@ nsresult nsWindowWatcher::OpenWindowInternal( loadState->SetURI(uriToLoad); } else if (uriToLoad && aNavigate && !loadState) { RefPtr context = - parentInnerWin ? parentInnerWin->GetWindowContext() : nullptr; + pInnerWin ? pInnerWin->GetWindowContext() : nullptr; loadState = new nsDocShellLoadState(uriToLoad); loadState->SetSourceBrowsingContext(parentBC); @@ -1280,8 +1231,8 @@ nsresult nsWindowWatcher::OpenWindowInternal( screw up focus in the hidden window; see bug 36016. */ RefPtr doc = GetEntryDocument(); - if (!doc) { - doc = parentDoc; + if (!doc && parentWindow) { + doc = parentWindow->GetExtantDoc(); } if (doc) { auto referrerInfo = MakeRefPtr(*doc); @@ -1304,14 +1255,14 @@ nsresult nsWindowWatcher::OpenWindowInternal( nsCOMPtr obsSvc = mozilla::services::GetObserverService(); if (obsSvc) { - obsSvc->NotifyObservers(ToSupports(targetOuterWin), - "toplevel-window-ready", nullptr); + obsSvc->NotifyObservers(ToSupports(win), "toplevel-window-ready", + nullptr); } } // Before loading the URI we want to be 100% sure that we use the correct // userContextId. - MOZ_ASSERT_IF(targetDocShell, CheckUserContextCompatibility(targetDocShell)); + MOZ_ASSERT_IF(newDocShell, CheckUserContextCompatibility(newDocShell)); // If this tab or window has been opened by a window.open call, we have to // provide all the data needed to send a @@ -1331,7 +1282,7 @@ nsresult nsWindowWatcher::OpenWindowInternal( props->SetPropertyAsInterface(u"sourceTabDocShell"_ns, parentDocShell); props->SetPropertyAsInterface(u"createdTabDocShell"_ns, - ToSupports(targetDocShell)); + ToSupports(newDocShell)); obsSvc->NotifyObservers(static_cast(props), "webNavigation-createdNavigationTarget-from-js", @@ -1340,38 +1291,49 @@ nsresult nsWindowWatcher::OpenWindowInternal( } if (uriToLoad && aNavigate) { - uint32_t loadFlags = nsIWebNavigation::LOAD_FLAGS_NONE; - if (windowIsNew) { - loadFlags |= nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD; - - // Per spec, the explicit navigation to about:blank after the initial - // about:blank document in a new window does not occur, so there is no - // opportunity for it to inherit the source document's principal. This - // doesn't perfectly model this, as a noopener creation of `about:blank` - // will replace the global due to a principal mismatch, but it should be - // unobservable (bug 1694993). - if (aForceNoOpener) { - loadFlags |= nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL; - } - } - loadState->SetLoadFlags(loadFlags); + // XXXBFCache Per spec this should effectively use + // LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL when noopener is passed to + // window.open(). Bug 1694993. + loadState->SetLoadFlags( + windowIsNew + ? static_cast(nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) + : static_cast(nsIWebNavigation::LOAD_FLAGS_NONE)); loadState->SetFirstParty(true); // Should this pay attention to errors returned by LoadURI? - targetBC->LoadURI(loadState); + newBC->LoadURI(loadState); + } + + // Copy the current session storage for the current domain. Don't perform the + // copy if we're forcing noopener, however. + if (!aForceNoOpener && subjectPrincipal && parentDocShell && newDocShell) { + const RefPtr parentStorageManager = + parentDocShell->GetBrowsingContext()->GetSessionStorageManager(); + const RefPtr newStorageManager = + newDocShell->GetBrowsingContext()->GetSessionStorageManager(); + + if (parentStorageManager && newStorageManager) { + RefPtr storage; + parentStorageManager->GetStorage( + pInnerWin, subjectPrincipal, subjectPrincipal, + newBC->UsePrivateBrowsing(), getter_AddRefs(storage)); + if (storage) { + newStorageManager->CloneStorage(storage); + } + } } if (isNewToplevelWindow) { nsCOMPtr newTreeOwner; - targetDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner)); + newDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner)); SizeOpenedWindow(newTreeOwner, aParent, isCallerChrome, sizeSpec); } if (windowIsModal) { - NS_ENSURE_TRUE(targetDocShell, NS_ERROR_NOT_IMPLEMENTED); + NS_ENSURE_TRUE(newDocShell, NS_ERROR_NOT_IMPLEMENTED); nsCOMPtr newTreeOwner; - targetDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner)); + newDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner)); nsCOMPtr newChrome(do_GetInterface(newTreeOwner)); // Throw an exception here if no web browser chrome is available, @@ -1385,7 +1347,7 @@ nsresult nsWindowWatcher::OpenWindowInternal( // Make sure we maintain the state on an outer window, because // that's where it lives; inner windows assert if you try to // maintain the state on them. - nsAutoWindowStateHelper windowStateHelper(parentOuterWin); + nsAutoWindowStateHelper windowStateHelper(parentWindow); if (!windowStateHelper.DefaultEnabled()) { // Default to cancel not opening the modal window. @@ -1417,8 +1379,8 @@ nsresult nsWindowWatcher::OpenWindowInternal( } // If a website opens a popup exit DOM fullscreen if (StaticPrefs::full_screen_api_exit_on_windowOpen() && aCalledFromJS && - !hasChromeParent && !isCallerChrome && parentOuterWin) { - Document::AsyncExitFullscreen(parentOuterWin->GetDoc()); + !hasChromeParent && !isCallerChrome && parentWindow) { + Document::AsyncExitFullscreen(parentWindow->GetDoc()); } if (aForceNoOpener && windowIsNew) { diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index d47a38052c87..d31fba38017d 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -746,27 +746,24 @@ nsresult nsAppShellService::JustCreateTopWindow( nsIWebBrowserChrome::CHROME_FISSION_WINDOW); // Eagerly create an about:blank content viewer with the right principal - // here, rather than letting it happen in the upcoming call to - // SetInitialPrincipal. This avoids creating the about:blank document and - // then blowing it away with a second one, which can cause problems for the - // top-level chrome window case. See bug 789773. - // Toplevel chrome windows always have a system principal, so ensure the - // initial window is created with that principal. - // We need to do this even when creating a chrome window to load a content - // window, see bug 799348 comment 13 for details about what previously - // happened here due to it using the subject principal. + // here, rather than letting it happening in the upcoming call to + // SetInitialPrincipalToSubject. This avoids creating the about:blank + // document and then blowing it away with a second one, which can cause + // problems for the top-level chrome window case. See bug 789773. Note that + // we don't accept expanded principals here, similar to + // SetInitialPrincipalToSubject. if (nsContentUtils::IsInitialized()) { // Sometimes this happens really // early. See bug 793370. - MOZ_DIAGNOSTIC_ASSERT( - nsContentUtils::LegacyIsCallerChromeOrNativeCode(), - "Previously, this method would use the subject principal rather than " - "hardcoding the system principal"); - // Use the system principal as the storage principal too until the new - // window finishes navigating and gets a real storage principal. + nsCOMPtr principal = + nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller(); + if (nsContentUtils::IsExpandedPrincipal(principal)) { + principal = nullptr; + } + // Use the subject (or system) principal as the storage principal too + // until the new window finishes navigating and gets a real storage + // principal. rv = docShell->CreateAboutBlankContentViewer( - nsContentUtils::GetSystemPrincipal(), - nsContentUtils::GetSystemPrincipal(), - /* aCsp = */ nullptr, /* aBaseURI = */ nullptr, + principal, principal, /* aCsp = */ nullptr, /* aBaseURI = */ nullptr, /* aIsInitialDocument = */ true); NS_ENSURE_SUCCESS(rv, rv); RefPtr doc = docShell->GetDocument(); @@ -850,18 +847,7 @@ nsAppShellService::RegisterTopLevelWindow(nsIAppWindow* aWindow) { nsCOMPtr domWindow(docShell->GetWindow()); NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); - - // Toplevel chrome windows always have a system principal, so ensure the - // initial window is created with that principal. - // We need to do this even when creating a chrome window to load a content - // window, see bug 799348 comment 13 for details about what previously - // happened here due to it using the subject principal. - MOZ_DIAGNOSTIC_ASSERT( - nsContentUtils::LegacyIsCallerChromeOrNativeCode(), - "Previously, this method would use the subject principal rather than " - "hardcoding the system principal"); - domWindow->SetInitialPrincipal(nsContentUtils::GetSystemPrincipal(), nullptr, - Nothing()); + domWindow->SetInitialPrincipalToSubject(nullptr, Nothing()); // tell the window mediator about the new window nsCOMPtr mediator(