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:
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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__ */
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -303,6 +303,8 @@ struct DocShellLoadStateInit
|
|||||||
bool IsMetaRefresh;
|
bool IsMetaRefresh;
|
||||||
|
|
||||||
nsIURI UnstrippedURI;
|
nsIURI UnstrippedURI;
|
||||||
|
|
||||||
|
nsCString? RemoteTypeOverride;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TimedChannelInfo
|
struct TimedChannelInfo
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user