Bug 1576407: Part 3 - Return window opener as a WindowProxyHolder or BrowsingContext. r=farre

Also adds a legacy `GetSameProcessOpener()` method for callers which can only
deal with in-process windows and may need to be updated for Fission.

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

--HG--
extra : source : 0ddbc451dcab431c2a1d934fa9baa5e8efc71545
This commit is contained in:
Kris Maglione 2019-08-28 18:07:38 +00:00
parent fcd9f00395
commit 99bc492498
8 changed files with 62 additions and 75 deletions

View File

@ -16,6 +16,7 @@
#include "nsError.h"
#include "nsContentSecurityManager.h"
#include "nsDocShellLoadTypes.h"
#include "nsGlobalWindowOuter.h"
#include "nsIInterfaceRequestor.h"
#include "nsIMultiPartChannel.h"
@ -48,10 +49,11 @@ nsIInterfaceRequestor* MaybeCloseWindowHelper::MaybeCloseWindow() {
if (mShouldCloseWindow) {
// Reset the window context to the opener window so that the dependent
// dialogs have a parent
nsCOMPtr<nsPIDOMWindowOuter> opener = window->GetOpener();
nsCOMPtr<nsPIDOMWindowOuter> opener =
nsGlobalWindowOuter::Cast(window)->GetSameProcessOpener();
if (opener && !opener->Closed()) {
mContentContext = do_GetInterface(opener);
mContentContext = do_QueryInterface(opener);
// Now close the old window. Do it on a timer so that we don't run
// into issues trying to close the window before it has fully opened.

View File

@ -14863,12 +14863,12 @@ void Document::MaybeAllowStorageForOpenerAfterUserInteraction() {
return;
}
nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
auto* outer = nsGlobalWindowOuter::Cast(inner->GetOuterWindow());
if (NS_WARN_IF(!outer)) {
return;
}
nsCOMPtr<nsPIDOMWindowOuter> outerOpener = outer->GetOpener();
nsCOMPtr<nsPIDOMWindowOuter> outerOpener = outer->GetSameProcessOpener();
if (!outerOpener) {
return;
}

View File

@ -3034,20 +3034,23 @@ nsresult nsGlobalWindowInner::GetControllers(nsIControllers** aResult) {
return rv.StealNSResult();
}
nsPIDOMWindowOuter* nsGlobalWindowInner::GetOpenerWindow(ErrorResult& aError) {
Nullable<WindowProxyHolder> nsGlobalWindowInner::GetOpenerWindow(
ErrorResult& aError) {
FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr);
}
void nsGlobalWindowInner::GetOpener(JSContext* aCx,
JS::MutableHandle<JS::Value> aRetval,
ErrorResult& aError) {
nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindow(aError);
if (aError.Failed() || !opener) {
Nullable<WindowProxyHolder> opener = GetOpenerWindow(aError);
if (aError.Failed() || opener.IsNull()) {
aRetval.setNull();
return;
}
aError = nsContentUtils::WrapNative(aCx, opener, aRetval);
if (!ToJSValue(aCx, opener.Value(), aRetval)) {
aError.NoteJSContextException(aCx);
}
}
void nsGlobalWindowInner::SetOpener(JSContext* aCx,

View File

@ -622,7 +622,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
void InitWasOffline();
public:
nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError);
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetOpenerWindow(
mozilla::ErrorResult& aError);
void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aError);
void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,

View File

@ -3290,63 +3290,44 @@ nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED);
}
nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSanitizedOpener(
nsPIDOMWindowOuter* aOpener) {
if (!aOpener) {
already_AddRefed<BrowsingContext>
nsGlobalWindowOuter::GetOpenerBrowsingContext() {
RefPtr<BrowsingContext> opener = GetBrowsingContext()->GetOpener();
MOZ_DIAGNOSTIC_ASSERT(!opener ||
opener->Group() == GetBrowsingContext()->Group());
if (!opener || opener->Group() != GetBrowsingContext()->Group()) {
return nullptr;
}
nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(aOpener);
// First, ensure that we're not handing back a chrome window to content:
if (win->IsChromeWindow()) {
return nullptr;
}
// We don't want to reveal the opener if the opener is a mail window,
// because opener can be used to spoof the contents of a message (bug 105050).
// So, we look in the opener's root docshell to see if it's a mail window.
nsCOMPtr<nsIDocShell> openerDocShell = aOpener->GetDocShell();
if (openerDocShell) {
nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
openerDocShell->GetInProcessRootTreeItem(getter_AddRefs(openerRootItem));
nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
if (openerRootDocShell) {
nsIDocShell::AppType appType = openerRootDocShell->GetAppType();
if (appType != nsIDocShell::APP_TYPE_MAIL) {
return aOpener;
}
// Catch the case where we're chrome but the opener is not...
if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
GetPrincipal() == nsContentUtils::GetSystemPrincipal()) {
auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow());
if (!openerWin ||
openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
return nullptr;
}
}
return opener.forget();
}
nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() {
if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
return opener->GetDOMWindow();
}
return nullptr;
}
nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOpenerWindowOuter() {
nsCOMPtr<nsPIDOMWindowOuter> opener = do_QueryReferent(mOpener);
if (!opener) {
return nullptr;
Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpenerWindowOuter() {
if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
return WindowProxyHolder(opener.forget());
}
// First, check if we were called from a privileged chrome script
if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
// Catch the case where we're chrome but the opener is not...
if (GetPrincipal() == nsContentUtils::GetSystemPrincipal() &&
nsGlobalWindowOuter::Cast(opener)->GetPrincipal() !=
nsContentUtils::GetSystemPrincipal()) {
return nullptr;
}
return opener;
}
return GetSanitizedOpener(opener);
return nullptr;
}
already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetOpener() {
nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindowOuter();
return opener.forget();
Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpener() {
return GetOpenerWindowOuter();
}
void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
@ -4962,13 +4943,15 @@ void nsGlobalWindowOuter::FocusOuter() {
nsCOMPtr<nsPIDOMWindowInner> caller = do_QueryInterface(GetEntryGlobal());
nsPIDOMWindowOuter* callerOuter = caller ? caller->GetOuterWindow() : nullptr;
nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpener();
BrowsingContext* callerBC =
callerOuter ? callerOuter->GetBrowsingContext() : nullptr;
RefPtr<BrowsingContext> openerBC = GetOpenerBrowsingContext();
// Enforce dom.disable_window_flip (for non-chrome), but still allow the
// window which opened us to raise us at times when popups are allowed
// (bugs 355482 and 369306).
bool canFocus = CanSetProperty("dom.disable_window_flip") ||
(opener == callerOuter &&
(openerBC == callerBC &&
RevisePopupAbuseLevel(PopupBlocker::GetPopupControlState()) <
PopupBlocker::openBlocked);
@ -7771,11 +7754,11 @@ mozilla::dom::TabGroup* nsGlobalWindowOuter::TabGroupOuter() {
// because a document is getting its NodePrincipal, and asking for the
// TabGroup to determine its DocGroup.
if (!mTabGroup) {
// Get mOpener ourselves, instead of relying on GetOpenerWindowOuter,
// Get the opener ourselves, instead of relying on GetOpenerWindowOuter,
// because that way we dodge the LegacyIsCallerChromeOrNativeCode() call
// which we want to return false.
nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
RefPtr<BrowsingContext> openerBC = GetBrowsingContext()->GetOpener();
nsPIDOMWindowOuter* opener = openerBC ? openerBC->GetDOMWindow() : nullptr;
nsPIDOMWindowOuter* parent = GetInProcessScriptableParentOrNull();
MOZ_ASSERT(!parent || !opener,
"Only one of parent and opener may be provided");
@ -7813,9 +7796,11 @@ mozilla::dom::TabGroup* nsGlobalWindowOuter::TabGroupOuter() {
// Sanity check that our tabgroup matches our opener or parent.
RefPtr<nsPIDOMWindowOuter> parent = GetInProcessScriptableParentOrNull();
MOZ_ASSERT_IF(parent, parent->TabGroup() == mTabGroup);
nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
MOZ_ASSERT_IF(opener && nsGlobalWindowOuter::Cast(opener) != this,
RefPtr<BrowsingContext> openerBC = GetBrowsingContext()->GetOpener();
nsPIDOMWindowOuter* opener =
openerBC ? openerBC->GetDOMWindow() : nullptr;
MOZ_ASSERT_IF(opener && Cast(opener) != this,
opener->TabGroup() == mTabGroup);
}
mIsValidatingTabGroup = false;

View File

@ -550,14 +550,15 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
protected:
nsPIDOMWindowOuter* GetOpenerWindowOuter();
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder>
GetOpenerWindowOuter();
// Initializes the mWasOffline member variable
void InitWasOffline();
public:
nsPIDOMWindowOuter* GetSanitizedOpener(nsPIDOMWindowOuter* aOpener);
already_AddRefed<nsPIDOMWindowOuter> GetOpener() override;
nsPIDOMWindowOuter* GetSameProcessOpener();
already_AddRefed<mozilla::dom::BrowsingContext> GetOpenerBrowsingContext();
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetOpener() override;
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetParentOuter();
already_AddRefed<nsPIDOMWindowOuter> GetInProcessParent() override;
nsPIDOMWindowOuter* GetInProcessScriptableParent() override;

View File

@ -1047,7 +1047,8 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy {
virtual nsresult GetPrompter(nsIPrompt** aPrompt) = 0;
virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
virtual already_AddRefed<mozilla::dom::Selection> GetSelection() = 0;
virtual already_AddRefed<nsPIDOMWindowOuter> GetOpener() = 0;
virtual mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder>
GetOpener() = 0;
// aLoadState will be passed on through to the windowwatcher.
// aForceNoOpener will act just like a "noopener" feature in aOptions except

View File

@ -2701,14 +2701,8 @@ nsresult WebSocketImpl::GetLoadingPrincipal(nsIPrincipal** aPrincipal) {
// We are at the top. Let's see if we have an opener window.
if (innerWindow == currentInnerWindow) {
ErrorResult error;
parentWindow =
nsGlobalWindowInner::Cast(innerWindow)->GetOpenerWindow(error);
if (NS_WARN_IF(error.Failed())) {
error.SuppressException();
return NS_ERROR_DOM_SECURITY_ERR;
}
parentWindow = nsGlobalWindowOuter::Cast(innerWindow->GetOuterWindow())
->GetSameProcessOpener();
if (!parentWindow) {
break;
}