Bug 1650089 - Part 1: Add a remoteTypeOverride option for about:blank loads triggered by chrome, r=annyG,kmag

After the changes in this bug, about:blank loads triggered by chrome will
finish in a "web" content process, as they have an untrusted null principal
without a precursor. In a few places throughout the codebase, however, we
perform about:blank loads with the explicit expectation that they do not change
processes. This new remoteTypeOverride option allows the intended final process
to be explicitly specified in this situation.

For security & simplicity reasons, this new attribute is limited to only be
usable on system-principal triggered loads of about:blank in toplevel browsing
contexts.

Differential Revision: https://phabricator.services.mozilla.com/D120671
This commit is contained in:
Nika Layzell
2021-08-10 14:31:16 +00:00
parent ae1b1b01dc
commit e836c49649
11 changed files with 84 additions and 3 deletions

View File

@@ -1493,8 +1493,14 @@ function _loadURI(browser, uri, params = {}) {
uri = "about:blank"; uri = "about:blank";
} }
let { triggeringPrincipal, referrerInfo, postData, userContextId, csp } = let {
params || {}; triggeringPrincipal,
referrerInfo,
postData,
userContextId,
csp,
remoteTypeOverride,
} = params || {};
let loadFlags = let loadFlags =
params.loadFlags || params.flags || Ci.nsIWebNavigation.LOAD_FLAGS_NONE; params.loadFlags || params.flags || Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
let hasValidUserGestureActivation = let hasValidUserGestureActivation =
@@ -1539,6 +1545,7 @@ function _loadURI(browser, uri, params = {}) {
referrerInfo, referrerInfo,
postData, postData,
hasValidUserGestureActivation, hasValidUserGestureActivation,
remoteTypeOverride,
}; };
try { try {
browser.webNavigation.loadURI(uri, loadURIOptions); browser.webNavigation.loadURI(uri, loadURIOptions);

View File

@@ -218,6 +218,10 @@ ContentRestoreInternal.prototype = {
let loadURIOptions = { let loadURIOptions = {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY,
// Specify an override to force the load to finish in the current
// process, as tests rely on this behaviour for non-fission session
// restore.
remoteTypeOverride: Services.appinfo.remoteType,
}; };
webNavigation.loadURI("about:blank", loadURIOptions); webNavigation.loadURI("about:blank", loadURIOptions);
} }

View File

@@ -3649,6 +3649,7 @@ var SessionStoreInternal = {
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({ triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({
userContextId: aTab.userContextId, userContextId: aTab.userContextId,
}), }),
remoteTypeOverride: E10SUtils.NOT_REMOTE,
}); });
let data = TabState.collect(aTab, TAB_CUSTOM_VALUES.get(aTab)); let data = TabState.collect(aTab, TAB_CUSTOM_VALUES.get(aTab));

View File

@@ -88,6 +88,7 @@ nsDocShellLoadState::nsDocShellLoadState(
aLoadState.loadingSessionHistoryInfo().ref()); aLoadState.loadingSessionHistoryInfo().ref());
} }
mUnstrippedURI = aLoadState.UnstrippedURI(); mUnstrippedURI = aLoadState.UnstrippedURI();
mRemoteTypeOverride = aLoadState.RemoteTypeOverride();
} }
nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther) nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
@@ -133,7 +134,8 @@ nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
mLoadIdentifier(aOther.mLoadIdentifier), mLoadIdentifier(aOther.mLoadIdentifier),
mChannelInitialized(aOther.mChannelInitialized), mChannelInitialized(aOther.mChannelInitialized),
mIsMetaRefresh(aOther.mIsMetaRefresh), mIsMetaRefresh(aOther.mIsMetaRefresh),
mUnstrippedURI(aOther.mUnstrippedURI) { mUnstrippedURI(aOther.mUnstrippedURI),
mRemoteTypeOverride(aOther.mRemoteTypeOverride) {
if (aOther.mLoadingSessionHistoryInfo) { if (aOther.mLoadingSessionHistoryInfo) {
mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>( mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>(
*aOther.mLoadingSessionHistoryInfo); *aOther.mLoadingSessionHistoryInfo);
@@ -369,6 +371,11 @@ nsresult nsDocShellLoadState::CreateFromLoadURIOptions(
nsDocShell::MaybeNotifyKeywordSearchLoading(searchProvider, keyword); nsDocShell::MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
} }
if (aLoadURIOptions.mRemoteTypeOverride.WasPassed()) {
loadState->SetRemoteTypeOverride(
aLoadURIOptions.mRemoteTypeOverride.Value());
}
loadState.forget(aResult); loadState.forget(aResult);
return NS_OK; return NS_OK;
} }
@@ -1046,6 +1053,7 @@ DocShellLoadStateInit nsDocShellLoadState::Serialize() {
loadState.loadingSessionHistoryInfo().emplace(*mLoadingSessionHistoryInfo); loadState.loadingSessionHistoryInfo().emplace(*mLoadingSessionHistoryInfo);
} }
loadState.UnstrippedURI() = mUnstrippedURI; loadState.UnstrippedURI() = mUnstrippedURI;
loadState.RemoteTypeOverride() = mRemoteTypeOverride;
return loadState; return loadState;
} }

View File

@@ -304,6 +304,14 @@ class nsDocShellLoadState final {
bool IsMetaRefresh() const { return mIsMetaRefresh; } bool IsMetaRefresh() const { return mIsMetaRefresh; }
const mozilla::Maybe<nsCString>& GetRemoteTypeOverride() const {
return mRemoteTypeOverride;
}
void SetRemoteTypeOverride(const nsCString& aRemoteTypeOverride) {
mRemoteTypeOverride = mozilla::Some(aRemoteTypeOverride);
}
// When loading a document through nsDocShell::LoadURI(), a special set of // When loading a document through nsDocShell::LoadURI(), a special set of
// flags needs to be set based on other values in nsDocShellLoadState. This // flags needs to be set based on other values in nsDocShellLoadState. This
// function calculates those flags, before the LoadState is passed to // function calculates those flags, before the LoadState is passed to
@@ -524,6 +532,9 @@ class nsDocShellLoadState final {
// The original URI before query stripping happened. If it's present, it shows // The original URI before query stripping happened. If it's present, it shows
// the query stripping happened. Otherwise, it will be a nullptr. // the query stripping happened. Otherwise, it will be a nullptr.
nsCOMPtr<nsIURI> mUnstrippedURI; nsCOMPtr<nsIURI> mUnstrippedURI;
// If set, the remote type which the load should be completed within.
mozilla::Maybe<nsCString> mRemoteTypeOverride;
}; };
#endif /* nsDocShellLoadState_h__ */ #endif /* nsDocShellLoadState_h__ */

View File

@@ -719,6 +719,16 @@ nsresult nsFrameLoader::ReallyStartLoadingInternal() {
loadState->SetLoadFlags(flags); loadState->SetLoadFlags(flags);
loadState->SetFirstParty(false); loadState->SetFirstParty(false);
// If we're loading the default about:blank document in a <browser> element,
// prevent the load from causing a process switch by explicitly overriding
// remote type selection.
if (mPendingBrowsingContext->IsTopContent() &&
mOwnerContent->IsXULElement(nsGkAtoms::browser) &&
NS_IsAboutBlank(mURIToLoad) &&
loadState->TriggeringPrincipal()->IsSystemPrincipal()) {
loadState->SetRemoteTypeOverride(mRemoteType);
}
} }
if (IsRemoteFrame()) { if (IsRemoteFrame()) {

View File

@@ -303,6 +303,8 @@ struct DocShellLoadStateInit
bool IsMetaRefresh; bool IsMetaRefresh;
nsIURI UnstrippedURI; nsIURI UnstrippedURI;
nsCString? RemoteTypeOverride;
}; };
struct TimedChannelInfo struct TimedChannelInfo

View File

@@ -79,4 +79,14 @@ dictionary LoadURIOptions {
* when initiating the load. * when initiating the load.
*/ */
long cancelContentJSEpoch = 0; long cancelContentJSEpoch = 0;
/**
* If this is passed, it will control which remote type is used to finish this
* load. Ignored for non-`about:` loads.
*
* NOTE: This is _NOT_ defaulted to `null`, as `null` is the value for
* `NOT_REMOTE_TYPE`, and we need to determine the difference between no
* `remoteTypeOverride` and a `remoteTypeOverride` of `NOT_REMOTE_TYPE`.
*/
UTF8String? remoteTypeOverride;
}; };

View File

@@ -539,6 +539,21 @@ auto DocumentLoadListener::Open(nsDocShellLoadState* aLoadState,
} }
} }
if (aLoadState->GetRemoteTypeOverride()) {
if (!mIsDocumentLoad || !NS_IsAboutBlank(aLoadState->URI()) ||
!loadingContext->IsTopContent()) {
LOG(
("DocumentLoadListener::Open with invalid remoteTypeOverride "
"[this=%p]",
this));
*aRv = NS_ERROR_DOM_SECURITY_ERR;
mParentChannelListener = nullptr;
return nullptr;
}
mRemoteTypeOverride = aLoadState->GetRemoteTypeOverride();
}
if (!nsDocShell::CreateAndConfigureRealChannelForLoadState( if (!nsDocShell::CreateAndConfigureRealChannelForLoadState(
loadingContext, aLoadState, aLoadInfo, mParentChannelListener, loadingContext, aLoadState, aLoadInfo, mParentChannelListener,
nullptr, attrs, aLoadFlags, aCacheKey, *aRv, nullptr, attrs, aLoadFlags, aCacheKey, *aRv,
@@ -1574,6 +1589,11 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
nsAutoCString preferredRemoteType(currentRemoteType); nsAutoCString preferredRemoteType(currentRemoteType);
RemotenessChangeOptions options; RemotenessChangeOptions options;
// If there is a remote type override, default to it.
if (mRemoteTypeOverride) {
preferredRemoteType = *mRemoteTypeOverride;
}
// Update the preferred final process for our load based on the // Update the preferred final process for our load based on the
// Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers. // Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers.
{ {
@@ -2520,6 +2540,10 @@ DocumentLoadListener::AsyncOnChannelRedirect(
// the new URI and set these again. // the new URI and set these again.
mIParentChannelFunctions.Clear(); mIParentChannelFunctions.Clear();
// If we had a remote type override, ensure it's been cleared after a
// redirect, as it can't apply anymore.
mRemoteTypeOverride.reset();
#ifdef ANDROID #ifdef ANDROID
nsCOMPtr<nsIURI> uriBeingLoaded = nsCOMPtr<nsIURI> uriBeingLoaded =
AntiTrackingUtils::MaybeGetDocumentURIBeingLoaded(mChannel); AntiTrackingUtils::MaybeGetDocumentURIBeingLoaded(mChannel);

View File

@@ -544,6 +544,8 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
bool mSupportsRedirectToRealChannel = true; bool mSupportsRedirectToRealChannel = true;
Maybe<nsCString> mRemoteTypeOverride;
// The process id of the content process that we are being called from // The process id of the content process that we are being called from
// or 0 initiated from a parent process load. // or 0 initiated from a parent process load.
base::ProcessId mOtherPid = 0; base::ProcessId mOtherPid = 0;

View File

@@ -814,6 +814,7 @@
postData, postData,
headers, headers,
csp, csp,
remoteTypeOverride,
} = aParams; } = aParams;
let loadFlags = let loadFlags =
aParams.loadFlags || aParams.loadFlags ||
@@ -826,6 +827,7 @@
loadFlags, loadFlags,
postData, postData,
headers, headers,
remoteTypeOverride,
}; };
this._wrapURIChangeCall(() => this._wrapURIChangeCall(() =>
this.webNavigation.loadURI(aURI, loadURIOptions) this.webNavigation.loadURI(aURI, loadURIOptions)