gecko-dev/docshell/base/nsDocShellLoadState.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1267 строки
45 KiB
C++
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsDocShellLoadState.h"
#include "nsIDocShell.h"
#include "nsDocShell.h"
#include "nsISHEntry.h"
#include "nsIURIFixup.h"
#include "nsIWebNavigation.h"
#include "nsIChannel.h"
#include "nsIURLQueryStringStripper.h"
#include "nsNetUtil.h"
#include "nsQueryObject.h"
#include "ReferrerInfo.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Components.h"
#include "mozilla/dom/BrowsingContext.h"
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/LoadURIOptionsBinding.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/Telemetry.h"
#include "mozilla/OriginAttributes.h"
#include "mozilla/NullPrincipal.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/PContent.h"
using namespace mozilla;
using namespace mozilla::dom;
// Global reference to the URI fixup service.
static mozilla::StaticRefPtr<nsIURIFixup> sURIFixup;
nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI)
: nsDocShellLoadState(aURI, nsContentUtils::GenerateLoadIdentifier()) {}
nsDocShellLoadState::nsDocShellLoadState(
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
const DocShellLoadStateInit& aLoadState, mozilla::ipc::IProtocol* aActor,
bool* aReadSuccess)
: mNotifiedBeforeUnloadListeners(false),
mLoadIdentifier(aLoadState.LoadIdentifier()) {
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
// If we return early, we failed to read in the data.
*aReadSuccess = false;
if (!aLoadState.URI()) {
MOZ_ASSERT_UNREACHABLE("Cannot create a LoadState with a null URI!");
return;
}
mResultPrincipalURI = aLoadState.ResultPrincipalURI();
mResultPrincipalURIIsSome = aLoadState.ResultPrincipalURIIsSome();
mKeepResultPrincipalURIIfSet = aLoadState.KeepResultPrincipalURIIfSet();
mLoadReplace = aLoadState.LoadReplace();
mInheritPrincipal = aLoadState.InheritPrincipal();
mPrincipalIsExplicit = aLoadState.PrincipalIsExplicit();
mForceAllowDataURI = aLoadState.ForceAllowDataURI();
mIsExemptFromHTTPSOnlyMode = aLoadState.IsExemptFromHTTPSOnlyMode();
mOriginalFrameSrc = aLoadState.OriginalFrameSrc();
mIsFormSubmission = aLoadState.IsFormSubmission();
mLoadType = aLoadState.LoadType();
mTarget = aLoadState.Target();
mTargetBrowsingContext = aLoadState.TargetBrowsingContext();
mLoadFlags = aLoadState.LoadFlags();
mInternalLoadFlags = aLoadState.InternalLoadFlags();
mFirstParty = aLoadState.FirstParty();
mHasValidUserGestureActivation = aLoadState.HasValidUserGestureActivation();
mAllowFocusMove = aLoadState.AllowFocusMove();
mTypeHint = aLoadState.TypeHint();
mFileName = aLoadState.FileName();
mIsFromProcessingFrameAttributes =
aLoadState.IsFromProcessingFrameAttributes();
mReferrerInfo = aLoadState.ReferrerInfo();
mURI = aLoadState.URI();
mOriginalURI = aLoadState.OriginalURI();
mSourceBrowsingContext = aLoadState.SourceBrowsingContext();
mBaseURI = aLoadState.BaseURI();
mTriggeringPrincipal = aLoadState.TriggeringPrincipal();
mPrincipalToInherit = aLoadState.PrincipalToInherit();
mPartitionedPrincipalToInherit = aLoadState.PartitionedPrincipalToInherit();
mTriggeringSandboxFlags = aLoadState.TriggeringSandboxFlags();
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
mTriggeringRemoteType = aLoadState.TriggeringRemoteType();
mCsp = aLoadState.Csp();
mOriginalURIString = aLoadState.OriginalURIString();
mCancelContentJSEpoch = aLoadState.CancelContentJSEpoch();
mPostDataStream = aLoadState.PostDataStream();
mHeadersStream = aLoadState.HeadersStream();
mSrcdocData = aLoadState.SrcdocData();
mChannelInitialized = aLoadState.ChannelInitialized();
mIsMetaRefresh = aLoadState.IsMetaRefresh();
if (aLoadState.loadingSessionHistoryInfo().isSome()) {
mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>(
aLoadState.loadingSessionHistoryInfo().ref());
}
mUnstrippedURI = aLoadState.UnstrippedURI();
mRemoteTypeOverride = aLoadState.RemoteTypeOverride();
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
// We know this was created remotely, as we just received it over IPC.
mWasCreatedRemotely = true;
// If we're in the parent process, potentially validate against a LoadState
// which we sent to the source content process.
if (XRE_IsParentProcess()) {
mozilla::ipc::IToplevelProtocol* top = aActor->ToplevelProtocol();
if (!top ||
top->GetProtocolId() != mozilla::ipc::ProtocolId::PContentMsgStart ||
top->GetSide() != mozilla::ipc::ParentSide) {
aActor->FatalError("nsDocShellLoadState must be received over PContent");
return;
}
ContentParent* cp = static_cast<ContentParent*>(top);
// If this load was sent down to the content process as a navigation
// request, ensure it still matches the one we sent down.
if (RefPtr<nsDocShellLoadState> originalState =
cp->TakePendingLoadStateForId(mLoadIdentifier)) {
if (const char* mismatch = ValidateWithOriginalState(originalState)) {
aActor->FatalError(
nsPrintfCString(
"nsDocShellLoadState %s changed while in content process",
mismatch)
.get());
return;
}
} else if (mTriggeringRemoteType != cp->GetRemoteType()) {
// If we don't have a previous load to compare to, the content process
// must be the triggering process.
aActor->FatalError(
"nsDocShellLoadState with invalid triggering remote type");
return;
}
}
// We successfully read in the data - return a success value.
*aReadSuccess = true;
}
nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
: mReferrerInfo(aOther.mReferrerInfo),
mURI(aOther.mURI),
mOriginalURI(aOther.mOriginalURI),
mResultPrincipalURI(aOther.mResultPrincipalURI),
mResultPrincipalURIIsSome(aOther.mResultPrincipalURIIsSome),
mTriggeringPrincipal(aOther.mTriggeringPrincipal),
mTriggeringSandboxFlags(aOther.mTriggeringSandboxFlags),
mCsp(aOther.mCsp),
mKeepResultPrincipalURIIfSet(aOther.mKeepResultPrincipalURIIfSet),
mLoadReplace(aOther.mLoadReplace),
mInheritPrincipal(aOther.mInheritPrincipal),
mPrincipalIsExplicit(aOther.mPrincipalIsExplicit),
mNotifiedBeforeUnloadListeners(aOther.mNotifiedBeforeUnloadListeners),
mPrincipalToInherit(aOther.mPrincipalToInherit),
mPartitionedPrincipalToInherit(aOther.mPartitionedPrincipalToInherit),
mForceAllowDataURI(aOther.mForceAllowDataURI),
mIsExemptFromHTTPSOnlyMode(aOther.mIsExemptFromHTTPSOnlyMode),
mOriginalFrameSrc(aOther.mOriginalFrameSrc),
mIsFormSubmission(aOther.mIsFormSubmission),
mLoadType(aOther.mLoadType),
mSHEntry(aOther.mSHEntry),
mTarget(aOther.mTarget),
mTargetBrowsingContext(aOther.mTargetBrowsingContext),
mPostDataStream(aOther.mPostDataStream),
mHeadersStream(aOther.mHeadersStream),
mSrcdocData(aOther.mSrcdocData),
mSourceBrowsingContext(aOther.mSourceBrowsingContext),
mBaseURI(aOther.mBaseURI),
mLoadFlags(aOther.mLoadFlags),
mInternalLoadFlags(aOther.mInternalLoadFlags),
mFirstParty(aOther.mFirstParty),
mHasValidUserGestureActivation(aOther.mHasValidUserGestureActivation),
mAllowFocusMove(aOther.mAllowFocusMove),
mTypeHint(aOther.mTypeHint),
mFileName(aOther.mFileName),
mIsFromProcessingFrameAttributes(aOther.mIsFromProcessingFrameAttributes),
mPendingRedirectedChannel(aOther.mPendingRedirectedChannel),
mOriginalURIString(aOther.mOriginalURIString),
mCancelContentJSEpoch(aOther.mCancelContentJSEpoch),
mLoadIdentifier(aOther.mLoadIdentifier),
mChannelInitialized(aOther.mChannelInitialized),
mIsMetaRefresh(aOther.mIsMetaRefresh),
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
mWasCreatedRemotely(aOther.mWasCreatedRemotely),
mUnstrippedURI(aOther.mUnstrippedURI),
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
mRemoteTypeOverride(aOther.mRemoteTypeOverride),
mTriggeringRemoteType(aOther.mTriggeringRemoteType) {
MOZ_DIAGNOSTIC_ASSERT(
XRE_IsParentProcess(),
"Cloning a nsDocShellLoadState with the same load identifier is only "
"allowed in the parent process, as it could break triggering remote type "
"tracking in content.");
if (aOther.mLoadingSessionHistoryInfo) {
mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>(
*aOther.mLoadingSessionHistoryInfo);
}
}
nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI, uint64_t aLoadIdentifier)
: mURI(aURI),
mResultPrincipalURIIsSome(false),
mTriggeringSandboxFlags(0),
mKeepResultPrincipalURIIfSet(false),
mLoadReplace(false),
mInheritPrincipal(false),
mPrincipalIsExplicit(false),
mNotifiedBeforeUnloadListeners(false),
mForceAllowDataURI(false),
mIsExemptFromHTTPSOnlyMode(false),
mOriginalFrameSrc(false),
mIsFormSubmission(false),
mLoadType(LOAD_NORMAL),
mTarget(),
mSrcdocData(VoidString()),
mLoadFlags(0),
mInternalLoadFlags(0),
mFirstParty(false),
mHasValidUserGestureActivation(false),
mAllowFocusMove(false),
mTypeHint(VoidCString()),
mFileName(VoidString()),
mIsFromProcessingFrameAttributes(false),
mLoadIdentifier(aLoadIdentifier),
mChannelInitialized(false),
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
mIsMetaRefresh(false),
mWasCreatedRemotely(false),
mTriggeringRemoteType(XRE_IsContentProcess()
? ContentChild::GetSingleton()->GetRemoteType()
: NOT_REMOTE_TYPE) {
MOZ_ASSERT(aURI, "Cannot create a LoadState with a null URI!");
}
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
nsDocShellLoadState::~nsDocShellLoadState() {
if (mWasCreatedRemotely && XRE_IsContentProcess()) {
ContentChild::GetSingleton()->SendCleanupPendingLoadState(mLoadIdentifier);
}
}
nsresult nsDocShellLoadState::CreateFromPendingChannel(
nsIChannel* aPendingChannel, uint64_t aLoadIdentifier,
uint64_t aRegistrarId, nsDocShellLoadState** aResult) {
// Create the nsDocShellLoadState object with default state pulled from the
// passed-in channel.
nsCOMPtr<nsIURI> uri;
nsresult rv = aPendingChannel->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
RefPtr<nsDocShellLoadState> loadState =
new nsDocShellLoadState(uri, aLoadIdentifier);
loadState->mPendingRedirectedChannel = aPendingChannel;
loadState->mChannelRegistrarId = aRegistrarId;
// Pull relevant state from the channel, and store it on the
// nsDocShellLoadState.
nsCOMPtr<nsIURI> originalUri;
rv = aPendingChannel->GetOriginalURI(getter_AddRefs(originalUri));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
loadState->SetOriginalURI(originalUri);
nsCOMPtr<nsILoadInfo> loadInfo = aPendingChannel->LoadInfo();
loadState->SetTriggeringPrincipal(loadInfo->TriggeringPrincipal());
// Return the newly created loadState.
loadState.forget(aResult);
return NS_OK;
}
static uint32_t WebNavigationFlagsToFixupFlags(nsIURI* aURI,
const nsACString& aURIString,
uint32_t aNavigationFlags) {
if (aURI) {
aNavigationFlags &= ~nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
}
uint32_t fixupFlags = nsIURIFixup::FIXUP_FLAG_NONE;
if (aNavigationFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
}
if (aNavigationFlags & nsIWebNavigation::LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
}
return fixupFlags;
};
nsresult nsDocShellLoadState::CreateFromLoadURIOptions(
BrowsingContext* aBrowsingContext, const nsAString& aURI,
const LoadURIOptions& aLoadURIOptions, nsDocShellLoadState** aResult) {
uint32_t loadFlags = aLoadURIOptions.mLoadFlags;
NS_ASSERTION(
(loadFlags & nsDocShell::INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0,
"Unexpected flags");
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_OK;
NS_ConvertUTF16toUTF8 uriString(aURI);
// Cleanup the empty spaces that might be on each end.
uriString.Trim(" ");
// Eliminate embedded newlines, which single-line text fields now allow:
uriString.StripCRLF();
NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
// Just create a URI and see what happens...
rv = NS_NewURI(getter_AddRefs(uri), uriString);
bool fixup = true;
if (NS_SUCCEEDED(rv) && uri &&
(uri->SchemeIs("about") || uri->SchemeIs("chrome"))) {
// Avoid third party fixup as a performance optimization.
loadFlags &= ~nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
fixup = false;
} else if (!sURIFixup && !XRE_IsContentProcess()) {
nsCOMPtr<nsIURIFixup> uriFixup = components::URIFixup::Service();
if (uriFixup) {
sURIFixup = uriFixup;
ClearOnShutdown(&sURIFixup);
} else {
fixup = false;
}
}
nsAutoString searchProvider, keyword;
RefPtr<nsIInputStream> fixupStream;
if (fixup) {
uint32_t fixupFlags =
WebNavigationFlagsToFixupFlags(uri, uriString, loadFlags);
// If we don't allow keyword lookups for this URL string, make sure to
// update loadFlags to indicate this as well.
if (!(fixupFlags & nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP)) {
loadFlags &= ~nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
}
// Ensure URIFixup will use the right search engine in Private Browsing.
if (aBrowsingContext->UsePrivateBrowsing()) {
fixupFlags |= nsIURIFixup::FIXUP_FLAG_PRIVATE_CONTEXT;
}
if (!XRE_IsContentProcess()) {
nsCOMPtr<nsIURIFixupInfo> fixupInfo;
sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
getter_AddRefs(fixupInfo));
if (fixupInfo) {
// We could fix the uri, clear NS_ERROR_MALFORMED_URI.
rv = NS_OK;
fixupInfo->GetPreferredURI(getter_AddRefs(uri));
fixupInfo->SetConsumer(aBrowsingContext);
fixupInfo->GetKeywordProviderName(searchProvider);
fixupInfo->GetKeywordAsSent(keyword);
// GetFixupURIInfo only returns a post data stream if it succeeded
// and changed the URI, in which case we should override the
// passed-in post data by passing this as an override arg to
// our internal method.
fixupInfo->GetPostData(getter_AddRefs(fixupStream));
if (fixupInfo &&
loadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
if (serv) {
serv->NotifyObservers(fixupInfo, "keyword-uri-fixup",
PromiseFlatString(aURI).get());
}
}
nsDocShell::MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
}
}
}
if (rv == NS_ERROR_MALFORMED_URI) {
MOZ_ASSERT(!uri);
return rv;
}
if (NS_FAILED(rv) || !uri) {
return NS_ERROR_FAILURE;
}
RefPtr<nsDocShellLoadState> loadState;
rv = CreateFromLoadURIOptions(
aBrowsingContext, uri, aLoadURIOptions, loadFlags,
fixupStream ? fixupStream : aLoadURIOptions.mPostData,
getter_AddRefs(loadState));
NS_ENSURE_SUCCESS(rv, rv);
loadState->SetOriginalURIString(uriString);
loadState.forget(aResult);
return NS_OK;
}
nsresult nsDocShellLoadState::CreateFromLoadURIOptions(
BrowsingContext* aBrowsingContext, nsIURI* aURI,
const LoadURIOptions& aLoadURIOptions, nsDocShellLoadState** aResult) {
return CreateFromLoadURIOptions(aBrowsingContext, aURI, aLoadURIOptions,
aLoadURIOptions.mLoadFlags,
aLoadURIOptions.mPostData, aResult);
}
nsresult nsDocShellLoadState::CreateFromLoadURIOptions(
BrowsingContext* aBrowsingContext, nsIURI* aURI,
const LoadURIOptions& aLoadURIOptions, uint32_t aLoadFlagsOverride,
nsIInputStream* aPostDataOverride, nsDocShellLoadState** aResult) {
nsresult rv = NS_OK;
uint32_t loadFlags = aLoadFlagsOverride;
RefPtr<nsIInputStream> postData = aPostDataOverride;
uint64_t available;
if (postData) {
rv = postData->Available(&available);
NS_ENSURE_SUCCESS(rv, rv);
if (available == 0) {
return NS_ERROR_INVALID_ARG;
}
}
if (aLoadURIOptions.mHeaders) {
rv = aLoadURIOptions.mHeaders->Available(&available);
NS_ENSURE_SUCCESS(rv, rv);
if (available == 0) {
return NS_ERROR_INVALID_ARG;
}
}
bool forceAllowDataURI =
loadFlags & nsIWebNavigation::LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
// Don't pass certain flags that aren't needed and end up confusing
// ConvertLoadTypeToDocShellInfoLoadType. We do need to ensure that they are
// passed to LoadURI though, since it uses them.
uint32_t extraFlags = (loadFlags & EXTRA_LOAD_FLAGS);
loadFlags &= ~EXTRA_LOAD_FLAGS;
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aURI);
loadState->SetReferrerInfo(aLoadURIOptions.mReferrerInfo);
loadState->SetLoadType(MAKE_LOAD_TYPE(LOAD_NORMAL, loadFlags));
loadState->SetLoadFlags(extraFlags);
loadState->SetFirstParty(true);
loadState->SetHasValidUserGestureActivation(
aLoadURIOptions.mHasValidUserGestureActivation);
loadState->SetTriggeringSandboxFlags(aLoadURIOptions.mTriggeringSandboxFlags);
loadState->SetPostDataStream(postData);
loadState->SetHeadersStream(aLoadURIOptions.mHeaders);
loadState->SetBaseURI(aLoadURIOptions.mBaseURI);
loadState->SetTriggeringPrincipal(aLoadURIOptions.mTriggeringPrincipal);
loadState->SetCsp(aLoadURIOptions.mCsp);
loadState->SetForceAllowDataURI(forceAllowDataURI);
if (aLoadURIOptions.mCancelContentJSEpoch) {
loadState->SetCancelContentJSEpoch(aLoadURIOptions.mCancelContentJSEpoch);
}
if (aLoadURIOptions.mTriggeringRemoteType.WasPassed()) {
if (XRE_IsParentProcess()) {
loadState->SetTriggeringRemoteType(
aLoadURIOptions.mTriggeringRemoteType.Value());
} else if (ContentChild::GetSingleton()->GetRemoteType() !=
aLoadURIOptions.mTriggeringRemoteType.Value()) {
NS_WARNING("Invalid TriggeringRemoteType from LoadURIOptions in content");
return NS_ERROR_INVALID_ARG;
}
}
if (aLoadURIOptions.mRemoteTypeOverride.WasPassed()) {
loadState->SetRemoteTypeOverride(
aLoadURIOptions.mRemoteTypeOverride.Value());
}
loadState.forget(aResult);
return NS_OK;
}
nsIReferrerInfo* nsDocShellLoadState::GetReferrerInfo() const {
return mReferrerInfo;
}
void nsDocShellLoadState::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
mReferrerInfo = aReferrerInfo;
}
nsIURI* nsDocShellLoadState::URI() const { return mURI; }
void nsDocShellLoadState::SetURI(nsIURI* aURI) { mURI = aURI; }
nsIURI* nsDocShellLoadState::OriginalURI() const { return mOriginalURI; }
void nsDocShellLoadState::SetOriginalURI(nsIURI* aOriginalURI) {
mOriginalURI = aOriginalURI;
}
nsIURI* nsDocShellLoadState::ResultPrincipalURI() const {
return mResultPrincipalURI;
}
void nsDocShellLoadState::SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
mResultPrincipalURI = aResultPrincipalURI;
}
bool nsDocShellLoadState::ResultPrincipalURIIsSome() const {
return mResultPrincipalURIIsSome;
}
void nsDocShellLoadState::SetResultPrincipalURIIsSome(bool aIsSome) {
mResultPrincipalURIIsSome = aIsSome;
}
bool nsDocShellLoadState::KeepResultPrincipalURIIfSet() const {
return mKeepResultPrincipalURIIfSet;
}
void nsDocShellLoadState::SetKeepResultPrincipalURIIfSet(bool aKeep) {
mKeepResultPrincipalURIIfSet = aKeep;
}
bool nsDocShellLoadState::LoadReplace() const { return mLoadReplace; }
void nsDocShellLoadState::SetLoadReplace(bool aLoadReplace) {
mLoadReplace = aLoadReplace;
}
nsIPrincipal* nsDocShellLoadState::TriggeringPrincipal() const {
return mTriggeringPrincipal;
}
void nsDocShellLoadState::SetTriggeringPrincipal(
nsIPrincipal* aTriggeringPrincipal) {
mTriggeringPrincipal = aTriggeringPrincipal;
}
nsIPrincipal* nsDocShellLoadState::PrincipalToInherit() const {
return mPrincipalToInherit;
}
void nsDocShellLoadState::SetPrincipalToInherit(
nsIPrincipal* aPrincipalToInherit) {
mPrincipalToInherit = aPrincipalToInherit;
}
nsIPrincipal* nsDocShellLoadState::PartitionedPrincipalToInherit() const {
return mPartitionedPrincipalToInherit;
}
void nsDocShellLoadState::SetPartitionedPrincipalToInherit(
nsIPrincipal* aPartitionedPrincipalToInherit) {
mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
}
void nsDocShellLoadState::SetCsp(nsIContentSecurityPolicy* aCsp) {
mCsp = aCsp;
}
nsIContentSecurityPolicy* nsDocShellLoadState::Csp() const { return mCsp; }
void nsDocShellLoadState::SetTriggeringSandboxFlags(uint32_t flags) {
mTriggeringSandboxFlags = flags;
}
uint32_t nsDocShellLoadState::TriggeringSandboxFlags() const {
return mTriggeringSandboxFlags;
}
bool nsDocShellLoadState::InheritPrincipal() const { return mInheritPrincipal; }
void nsDocShellLoadState::SetInheritPrincipal(bool aInheritPrincipal) {
mInheritPrincipal = aInheritPrincipal;
}
bool nsDocShellLoadState::PrincipalIsExplicit() const {
return mPrincipalIsExplicit;
}
void nsDocShellLoadState::SetPrincipalIsExplicit(bool aPrincipalIsExplicit) {
mPrincipalIsExplicit = aPrincipalIsExplicit;
}
bool nsDocShellLoadState::NotifiedBeforeUnloadListeners() const {
return mNotifiedBeforeUnloadListeners;
}
void nsDocShellLoadState::SetNotifiedBeforeUnloadListeners(
bool aNotifiedBeforeUnloadListeners) {
mNotifiedBeforeUnloadListeners = aNotifiedBeforeUnloadListeners;
}
bool nsDocShellLoadState::ForceAllowDataURI() const {
return mForceAllowDataURI;
}
void nsDocShellLoadState::SetForceAllowDataURI(bool aForceAllowDataURI) {
mForceAllowDataURI = aForceAllowDataURI;
}
bool nsDocShellLoadState::IsExemptFromHTTPSOnlyMode() const {
return mIsExemptFromHTTPSOnlyMode;
}
void nsDocShellLoadState::SetIsExemptFromHTTPSOnlyMode(
bool aIsExemptFromHTTPSOnlyMode) {
mIsExemptFromHTTPSOnlyMode = aIsExemptFromHTTPSOnlyMode;
}
bool nsDocShellLoadState::OriginalFrameSrc() const { return mOriginalFrameSrc; }
void nsDocShellLoadState::SetOriginalFrameSrc(bool aOriginalFrameSrc) {
mOriginalFrameSrc = aOriginalFrameSrc;
}
bool nsDocShellLoadState::IsFormSubmission() const { return mIsFormSubmission; }
void nsDocShellLoadState::SetIsFormSubmission(bool aIsFormSubmission) {
mIsFormSubmission = aIsFormSubmission;
}
uint32_t nsDocShellLoadState::LoadType() const { return mLoadType; }
void nsDocShellLoadState::SetLoadType(uint32_t aLoadType) {
mLoadType = aLoadType;
}
nsISHEntry* nsDocShellLoadState::SHEntry() const { return mSHEntry; }
void nsDocShellLoadState::SetSHEntry(nsISHEntry* aSHEntry) {
mSHEntry = aSHEntry;
nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(aSHEntry);
if (she) {
mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>(she);
} else {
mLoadingSessionHistoryInfo = nullptr;
}
}
void nsDocShellLoadState::SetLoadingSessionHistoryInfo(
const mozilla::dom::LoadingSessionHistoryInfo& aLoadingInfo) {
SetLoadingSessionHistoryInfo(
MakeUnique<mozilla::dom::LoadingSessionHistoryInfo>(aLoadingInfo));
}
void nsDocShellLoadState::SetLoadingSessionHistoryInfo(
mozilla::UniquePtr<mozilla::dom::LoadingSessionHistoryInfo> aLoadingInfo) {
mLoadingSessionHistoryInfo = std::move(aLoadingInfo);
Bug 1570255 - Reboot session history in parent part 1. r=smaug,necko-reviewers,valentin This adds a new implementation of nsISHEntry (mozilla::dom::SessionHistoryEntry). When session history in the parent is turned on, we'll instantiate the existing nsSHistory in the parent process, but it will store entries of this new type. The nsSHistory in the child process will also be instantiated for now, to avoid breaking too many assumptions, and we try to keep parent and child implementations in sync. mozilla::dom::SessionHistoryEntry stores most of its data in a new structure (mozilla::dom::SessionHistoryInfo) which can be sent over IPC. When a load starts through the DocumentChannel we create an entry of this new type for it in the parent process in DocumentLoadListener::Open. The SessionHistoryInfo for that entry (with an associated ID) is then sent over IPC in the RedirectToRealChannelArgs to the process that does the actual load, where we store it in the nsDocShell in mLoadingEntry (and mLoadingEntryId). The parent process keeps track of outstanding loading entries in an array (mLoadingEntries) in the CanonicalBrowsingContext. When a load finishes the nsDocShell transfers mLoadingEntry into mActiveEntry, and notifies the parent process through an IPC message (HistoryCommit) with the id of that entry. The CanonicalBrowsingContext then removes the entry from the array and stores it in its mActiveEntry, and adds the entry to the nsSHistory object. There are a number of things in this patch that are broken, and a lot of FIXME comments. However, with the pref turned off things should just be working as before. The goal is to land this first part, and then iterate on the new implementation until we can switch over. Differential Revision: https://phabricator.services.mozilla.com/D65329
2020-05-20 12:09:12 +03:00
}
const mozilla::dom::LoadingSessionHistoryInfo*
nsDocShellLoadState::GetLoadingSessionHistoryInfo() const {
return mLoadingSessionHistoryInfo.get();
}
void nsDocShellLoadState::SetLoadIsFromSessionHistory(
int32_t aOffset, bool aLoadingCurrentEntry) {
if (mLoadingSessionHistoryInfo) {
mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory = true;
mLoadingSessionHistoryInfo->mOffset = aOffset;
mLoadingSessionHistoryInfo->mLoadingCurrentEntry = aLoadingCurrentEntry;
}
Bug 1570255 - Reboot session history in parent part 1. r=smaug,necko-reviewers,valentin This adds a new implementation of nsISHEntry (mozilla::dom::SessionHistoryEntry). When session history in the parent is turned on, we'll instantiate the existing nsSHistory in the parent process, but it will store entries of this new type. The nsSHistory in the child process will also be instantiated for now, to avoid breaking too many assumptions, and we try to keep parent and child implementations in sync. mozilla::dom::SessionHistoryEntry stores most of its data in a new structure (mozilla::dom::SessionHistoryInfo) which can be sent over IPC. When a load starts through the DocumentChannel we create an entry of this new type for it in the parent process in DocumentLoadListener::Open. The SessionHistoryInfo for that entry (with an associated ID) is then sent over IPC in the RedirectToRealChannelArgs to the process that does the actual load, where we store it in the nsDocShell in mLoadingEntry (and mLoadingEntryId). The parent process keeps track of outstanding loading entries in an array (mLoadingEntries) in the CanonicalBrowsingContext. When a load finishes the nsDocShell transfers mLoadingEntry into mActiveEntry, and notifies the parent process through an IPC message (HistoryCommit) with the id of that entry. The CanonicalBrowsingContext then removes the entry from the array and stores it in its mActiveEntry, and adds the entry to the nsSHistory object. There are a number of things in this patch that are broken, and a lot of FIXME comments. However, with the pref turned off things should just be working as before. The goal is to land this first part, and then iterate on the new implementation until we can switch over. Differential Revision: https://phabricator.services.mozilla.com/D65329
2020-05-20 12:09:12 +03:00
}
void nsDocShellLoadState::ClearLoadIsFromSessionHistory() {
if (mLoadingSessionHistoryInfo) {
mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory = false;
}
mSHEntry = nullptr;
}
bool nsDocShellLoadState::LoadIsFromSessionHistory() const {
return mLoadingSessionHistoryInfo
? mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory
: !!mSHEntry;
}
void nsDocShellLoadState::MaybeStripTrackerQueryStrings(
BrowsingContext* aContext) {
MOZ_ASSERT(aContext);
// Return early if the triggering principal doesn't exist. This could happen
// when loading a URL by using a browsing context in the Browser Toolbox.
if (!TriggeringPrincipal()) {
return;
}
// We don't need to strip for sub frames because the query string has been
// stripped in the top-level content. Also, we don't apply stripping if it
// is triggered by addons.
//
// Note that we don't need to do the stripping if the channel has been
// initialized. This means that this has been loaded speculatively in the
// parent process before and the stripping was happening by then.
if (GetChannelInitialized() || !aContext->IsTopContent() ||
BasePrincipal::Cast(TriggeringPrincipal())->AddonPolicy()) {
return;
}
// We don't strip the URI if it's the same-site navigation. Note that we will
// consider the system principal triggered load as third-party in case the
// user copies and pastes a URL which has tracking query parameters or an
// loading from external applications, such as clicking a link in an email
// client.
bool isThirdPartyURI = false;
if (!TriggeringPrincipal()->IsSystemPrincipal() &&
(NS_FAILED(
TriggeringPrincipal()->IsThirdPartyURI(URI(), &isThirdPartyURI)) ||
!isThirdPartyURI)) {
return;
}
Telemetry::AccumulateCategorical(
Telemetry::LABELS_QUERY_STRIPPING_COUNT::Navigation);
nsCOMPtr<nsIURI> strippedURI;
nsresult rv;
nsCOMPtr<nsIURLQueryStringStripper> queryStripper =
components::URLQueryStringStripper::Service(&rv);
NS_ENSURE_SUCCESS_VOID(rv);
uint32_t numStripped;
queryStripper->Strip(URI(), aContext->UsePrivateBrowsing(),
getter_AddRefs(strippedURI), &numStripped);
if (numStripped) {
if (!mUnstrippedURI) {
mUnstrippedURI = URI();
}
SetURI(strippedURI);
Telemetry::AccumulateCategorical(
Telemetry::LABELS_QUERY_STRIPPING_COUNT::StripForNavigation);
Telemetry::Accumulate(Telemetry::QUERY_STRIPPING_PARAM_COUNT, numStripped);
}
#ifdef DEBUG
// Make sure that unstripped URI is the same as URI() but only the query
// string could be different.
if (mUnstrippedURI) {
nsCOMPtr<nsIURI> uri;
Unused << queryStripper->Strip(mUnstrippedURI,
aContext->UsePrivateBrowsing(),
getter_AddRefs(uri), &numStripped);
bool equals = false;
Unused << URI()->Equals(uri, &equals);
MOZ_ASSERT(equals);
}
#endif
}
const nsString& nsDocShellLoadState::Target() const { return mTarget; }
void nsDocShellLoadState::SetTarget(const nsAString& aTarget) {
mTarget = aTarget;
}
nsIInputStream* nsDocShellLoadState::PostDataStream() const {
return mPostDataStream;
}
void nsDocShellLoadState::SetPostDataStream(nsIInputStream* aStream) {
mPostDataStream = aStream;
}
nsIInputStream* nsDocShellLoadState::HeadersStream() const {
return mHeadersStream;
}
void nsDocShellLoadState::SetHeadersStream(nsIInputStream* aHeadersStream) {
mHeadersStream = aHeadersStream;
}
const nsString& nsDocShellLoadState::SrcdocData() const { return mSrcdocData; }
void nsDocShellLoadState::SetSrcdocData(const nsAString& aSrcdocData) {
mSrcdocData = aSrcdocData;
}
void nsDocShellLoadState::SetSourceBrowsingContext(
BrowsingContext* aSourceBrowsingContext) {
mSourceBrowsingContext = aSourceBrowsingContext;
}
void nsDocShellLoadState::SetTargetBrowsingContext(
BrowsingContext* aTargetBrowsingContext) {
mTargetBrowsingContext = aTargetBrowsingContext;
}
nsIURI* nsDocShellLoadState::BaseURI() const { return mBaseURI; }
void nsDocShellLoadState::SetBaseURI(nsIURI* aBaseURI) { mBaseURI = aBaseURI; }
void nsDocShellLoadState::GetMaybeResultPrincipalURI(
mozilla::Maybe<nsCOMPtr<nsIURI>>& aRPURI) const {
bool isSome = ResultPrincipalURIIsSome();
aRPURI.reset();
if (!isSome) {
return;
}
nsCOMPtr<nsIURI> uri = ResultPrincipalURI();
aRPURI.emplace(std::move(uri));
}
void nsDocShellLoadState::SetMaybeResultPrincipalURI(
mozilla::Maybe<nsCOMPtr<nsIURI>> const& aRPURI) {
SetResultPrincipalURI(aRPURI.refOr(nullptr));
SetResultPrincipalURIIsSome(aRPURI.isSome());
}
uint32_t nsDocShellLoadState::LoadFlags() const { return mLoadFlags; }
void nsDocShellLoadState::SetLoadFlags(uint32_t aLoadFlags) {
mLoadFlags = aLoadFlags;
}
void nsDocShellLoadState::SetLoadFlag(uint32_t aFlag) { mLoadFlags |= aFlag; }
void nsDocShellLoadState::UnsetLoadFlag(uint32_t aFlag) {
mLoadFlags &= ~aFlag;
}
bool nsDocShellLoadState::HasLoadFlags(uint32_t aFlags) {
return (mLoadFlags & aFlags) == aFlags;
}
uint32_t nsDocShellLoadState::InternalLoadFlags() const {
return mInternalLoadFlags;
}
void nsDocShellLoadState::SetInternalLoadFlags(uint32_t aLoadFlags) {
mInternalLoadFlags = aLoadFlags;
}
void nsDocShellLoadState::SetInternalLoadFlag(uint32_t aFlag) {
mInternalLoadFlags |= aFlag;
}
void nsDocShellLoadState::UnsetInternalLoadFlag(uint32_t aFlag) {
mInternalLoadFlags &= ~aFlag;
}
bool nsDocShellLoadState::HasInternalLoadFlags(uint32_t aFlags) {
return (mInternalLoadFlags & aFlags) == aFlags;
}
bool nsDocShellLoadState::FirstParty() const { return mFirstParty; }
void nsDocShellLoadState::SetFirstParty(bool aFirstParty) {
mFirstParty = aFirstParty;
}
bool nsDocShellLoadState::HasValidUserGestureActivation() const {
return mHasValidUserGestureActivation;
}
void nsDocShellLoadState::SetHasValidUserGestureActivation(
bool aHasValidUserGestureActivation) {
mHasValidUserGestureActivation = aHasValidUserGestureActivation;
}
const nsCString& nsDocShellLoadState::TypeHint() const { return mTypeHint; }
void nsDocShellLoadState::SetTypeHint(const nsCString& aTypeHint) {
mTypeHint = aTypeHint;
}
const nsString& nsDocShellLoadState::FileName() const { return mFileName; }
void nsDocShellLoadState::SetFileName(const nsAString& aFileName) {
MOZ_DIAGNOSTIC_ASSERT(aFileName.FindChar(char16_t(0)) == kNotFound,
"The filename should never contain null characters");
mFileName = aFileName;
}
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
const nsCString& nsDocShellLoadState::GetEffectiveTriggeringRemoteType() const {
// Consider non-errorpage loads from session history as being triggred by the
// parent process, as we'll validate them against the history entry.
//
// NOTE: Keep this check in-sync with the session-history validation check in
// `DocumentLoadListener::Open`!
if (LoadIsFromSessionHistory() && LoadType() != LOAD_ERROR_PAGE) {
return NOT_REMOTE_TYPE;
}
return mTriggeringRemoteType;
}
void nsDocShellLoadState::SetTriggeringRemoteType(
const nsACString& aTriggeringRemoteType) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(), "only settable in parent");
mTriggeringRemoteType = aTriggeringRemoteType;
}
nsresult nsDocShellLoadState::SetupInheritingPrincipal(
BrowsingContext::Type aType,
const mozilla::OriginAttributes& aOriginAttributes) {
// We need a principalToInherit.
//
// If principalIsExplicit is not set there are 4 possibilities:
// (1) If the system principal or an expanded principal was passed
// in and we're a typeContent docshell, inherit the principal
// from the current document instead.
// (2) In all other cases when the principal passed in is not null,
// use that principal.
// (3) If the caller has allowed inheriting from the current document,
// or if we're being called from system code (eg chrome JS or pure
// C++) then inheritPrincipal should be true and InternalLoad will get
// a principal from the current document. If none of these things are
// true, then
// (4) we don't pass a principal into the channel, and a principal will be
// created later from the channel's internal data.
//
// If principalIsExplicit *is* set, there are 4 possibilities
// (1) If the system principal or an expanded principal was passed in
// and we're a typeContent docshell, return an error.
// (2) In all other cases when the principal passed in is not null,
// use that principal.
// (3) If the caller has allowed inheriting from the current document,
// then inheritPrincipal should be true and InternalLoad will get
// a principal from the current document. If none of these things are
// true, then
// (4) we dont' pass a principal into the channel, and a principal will be
// created later from the channel's internal data.
mPrincipalToInherit = mTriggeringPrincipal;
if (mPrincipalToInherit && aType != BrowsingContext::Type::Chrome) {
if (mPrincipalToInherit->IsSystemPrincipal()) {
if (mPrincipalIsExplicit) {
return NS_ERROR_DOM_SECURITY_ERR;
}
mPrincipalToInherit = nullptr;
mInheritPrincipal = true;
} else if (nsContentUtils::IsExpandedPrincipal(mPrincipalToInherit)) {
if (mPrincipalIsExplicit) {
return NS_ERROR_DOM_SECURITY_ERR;
}
// Don't inherit from the current page. Just do the safe thing
// and pretend that we were loaded by a nullprincipal.
//
// We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
// have origin attributes.
mPrincipalToInherit = NullPrincipal::Create(aOriginAttributes);
mInheritPrincipal = false;
}
}
if (!mPrincipalToInherit && !mInheritPrincipal && !mPrincipalIsExplicit) {
// See if there's system or chrome JS code running
mInheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
}
if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
mInheritPrincipal = false;
// Create a new null principal URI based on our precursor principal.
nsCOMPtr<nsIURI> nullPrincipalURI =
NullPrincipal::CreateURI(mPrincipalToInherit);
// If mFirstParty is true and the pref 'privacy.firstparty.isolate' is
// enabled, we will set firstPartyDomain on the origin attributes.
OriginAttributes attrs(aOriginAttributes);
if (mFirstParty) {
attrs.SetFirstPartyDomain(true, nullPrincipalURI);
}
mPrincipalToInherit = NullPrincipal::Create(attrs, nullPrincipalURI);
}
return NS_OK;
}
nsresult nsDocShellLoadState::SetupTriggeringPrincipal(
const mozilla::OriginAttributes& aOriginAttributes) {
// If the triggeringPrincipal is not set, we first try to create a principal
// from the referrer, since the referrer URI reflects the web origin that
// triggered the load. If there is no referrer URI, we fall back to using the
// SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
// and no referrer simulate a load that was triggered by the system. It's
// important to note that this block of code needs to appear *after* the block
// where we munge the principalToInherit, because otherwise we would never
// enter code blocks checking if the principalToInherit is null and we will
// end up with a wrong inheritPrincipal flag.
if (!mTriggeringPrincipal) {
if (mReferrerInfo) {
nsCOMPtr<nsIURI> referrer = mReferrerInfo->GetOriginalReferrer();
mTriggeringPrincipal =
BasePrincipal::CreateContentPrincipal(referrer, aOriginAttributes);
if (!mTriggeringPrincipal) {
return NS_ERROR_FAILURE;
}
} else {
mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal();
}
}
return NS_OK;
}
void nsDocShellLoadState::CalculateLoadURIFlags() {
if (mInheritPrincipal) {
MOZ_ASSERT(
!mPrincipalToInherit || !mPrincipalToInherit->IsSystemPrincipal(),
"Should not inherit SystemPrincipal");
mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
}
if (mReferrerInfo && !mReferrerInfo->GetSendReferrer()) {
mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
}
if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
mInternalLoadFlags |=
nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
}
if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) {
mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD;
}
if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CLASSIFIER) {
mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
}
if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
}
if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE) {
mInternalLoadFlags |=
nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE;
}
if (!mSrcdocData.IsVoid()) {
mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
}
if (mForceAllowDataURI) {
mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
}
if (mOriginalFrameSrc) {
mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC;
}
}
nsLoadFlags nsDocShellLoadState::CalculateChannelLoadFlags(
BrowsingContext* aBrowsingContext, Maybe<bool> aUriModified,
Maybe<bool> aIsXFOError) {
MOZ_ASSERT(aBrowsingContext);
nsLoadFlags loadFlags = aBrowsingContext->GetDefaultLoadFlags();
if (FirstParty()) {
// tag first party URL loads
loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
}
const uint32_t loadType = LoadType();
// These values aren't available for loads initiated in the Parent process.
MOZ_ASSERT_IF(loadType == LOAD_HISTORY, aUriModified.isSome());
MOZ_ASSERT_IF(loadType == LOAD_ERROR_PAGE, aIsXFOError.isSome());
if (loadType == LOAD_ERROR_PAGE) {
// Error pages are LOAD_BACKGROUND, unless it's an
// XFO error for which we want an error page to load
// but additionally want the onload() event to fire.
if (!*aIsXFOError) {
loadFlags |= nsIChannel::LOAD_BACKGROUND;
}
}
// Mark the channel as being a document URI and allow content sniffing...
loadFlags |=
nsIChannel::LOAD_DOCUMENT_URI | nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
if (nsDocShell::SandboxFlagsImplyCookies(
aBrowsingContext->GetSandboxFlags())) {
loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE;
}
// Load attributes depend on load type...
switch (loadType) {
case LOAD_HISTORY: {
// Only send VALIDATE_NEVER if mLSHE's URI was never changed via
// push/replaceState (bug 669671).
if (!*aUriModified) {
loadFlags |= nsIRequest::VALIDATE_NEVER;
}
break;
}
case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE:
case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE:
loadFlags |=
nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::LOAD_FRESH_CONNECTION;
[[fallthrough]];
case LOAD_REFRESH:
loadFlags |= nsIRequest::VALIDATE_ALWAYS;
break;
case LOAD_NORMAL_BYPASS_CACHE:
case LOAD_NORMAL_BYPASS_PROXY:
case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
case LOAD_RELOAD_BYPASS_CACHE:
case LOAD_RELOAD_BYPASS_PROXY:
case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
case LOAD_REPLACE_BYPASS_CACHE:
loadFlags |=
nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::LOAD_FRESH_CONNECTION;
break;
case LOAD_RELOAD_NORMAL:
if (!StaticPrefs::
browser_soft_reload_only_force_validate_top_level_document()) {
loadFlags |= nsIRequest::VALIDATE_ALWAYS;
break;
}
[[fallthrough]];
case LOAD_NORMAL:
case LOAD_LINK:
// Set cache checking flags
switch (StaticPrefs::browser_cache_check_doc_frequency()) {
case 0:
loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
break;
case 1:
loadFlags |= nsIRequest::VALIDATE_ALWAYS;
break;
case 2:
loadFlags |= nsIRequest::VALIDATE_NEVER;
break;
}
break;
}
if (HasInternalLoadFlags(nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER)) {
loadFlags |= nsIChannel::LOAD_BYPASS_URL_CLASSIFIER;
}
// If the user pressed shift-reload, then do not allow ServiceWorker
// interception to occur. See step 12.1 of the SW HandleFetch algorithm.
if (IsForceReloadType(loadType)) {
loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
}
return loadFlags;
}
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
const char* nsDocShellLoadState::ValidateWithOriginalState(
nsDocShellLoadState* aOriginalState) {
MOZ_ASSERT(mLoadIdentifier == aOriginalState->mLoadIdentifier);
// Check that `aOriginalState` is sufficiently similar to this state that
// they're performing the same load.
auto uriEq = [](nsIURI* a, nsIURI* b) -> bool {
bool eq = false;
return a == b || (a && b && NS_SUCCEEDED(a->Equals(b, &eq)) && eq);
};
if (!uriEq(mURI, aOriginalState->mURI)) {
return "URI";
}
if (!uriEq(mUnstrippedURI, aOriginalState->mUnstrippedURI)) {
return "UnstrippedURI";
}
if (!uriEq(mOriginalURI, aOriginalState->mOriginalURI)) {
return "OriginalURI";
}
if (!uriEq(mBaseURI, aOriginalState->mBaseURI)) {
return "BaseURI";
}
if (!mTriggeringPrincipal->Equals(aOriginalState->mTriggeringPrincipal)) {
return "TriggeringPrincipal";
}
if (mTriggeringSandboxFlags != aOriginalState->mTriggeringSandboxFlags) {
return "TriggeringSandboxFlags";
}
if (mTriggeringRemoteType != aOriginalState->mTriggeringRemoteType) {
return "TriggeringRemoteType";
}
if (mOriginalURIString != aOriginalState->mOriginalURIString) {
return "OriginalURIString";
}
if (mRemoteTypeOverride != aOriginalState->mRemoteTypeOverride) {
return "RemoteTypeOverride";
}
if (mSourceBrowsingContext.ContextId() !=
aOriginalState->mSourceBrowsingContext.ContextId()) {
return "SourceBrowsingContext";
}
// FIXME: Consider calculating less information in the target process so that
// we can validate more properties more easily.
// FIXME: Identify what other flags will not change when sent through a
// content process.
return nullptr;
}
DocShellLoadStateInit nsDocShellLoadState::Serialize(
mozilla::ipc::IProtocol* aActor) {
MOZ_ASSERT(aActor);
DocShellLoadStateInit loadState;
loadState.ResultPrincipalURI() = mResultPrincipalURI;
loadState.ResultPrincipalURIIsSome() = mResultPrincipalURIIsSome;
loadState.KeepResultPrincipalURIIfSet() = mKeepResultPrincipalURIIfSet;
loadState.LoadReplace() = mLoadReplace;
loadState.InheritPrincipal() = mInheritPrincipal;
loadState.PrincipalIsExplicit() = mPrincipalIsExplicit;
loadState.ForceAllowDataURI() = mForceAllowDataURI;
loadState.IsExemptFromHTTPSOnlyMode() = mIsExemptFromHTTPSOnlyMode;
loadState.OriginalFrameSrc() = mOriginalFrameSrc;
loadState.IsFormSubmission() = mIsFormSubmission;
loadState.LoadType() = mLoadType;
loadState.Target() = mTarget;
loadState.TargetBrowsingContext() = mTargetBrowsingContext;
loadState.LoadFlags() = mLoadFlags;
loadState.InternalLoadFlags() = mInternalLoadFlags;
loadState.FirstParty() = mFirstParty;
loadState.HasValidUserGestureActivation() = mHasValidUserGestureActivation;
loadState.AllowFocusMove() = mAllowFocusMove;
loadState.TypeHint() = mTypeHint;
loadState.FileName() = mFileName;
loadState.IsFromProcessingFrameAttributes() =
mIsFromProcessingFrameAttributes;
loadState.URI() = mURI;
loadState.OriginalURI() = mOriginalURI;
loadState.SourceBrowsingContext() = mSourceBrowsingContext;
loadState.BaseURI() = mBaseURI;
loadState.TriggeringPrincipal() = mTriggeringPrincipal;
loadState.PrincipalToInherit() = mPrincipalToInherit;
loadState.PartitionedPrincipalToInherit() = mPartitionedPrincipalToInherit;
loadState.TriggeringSandboxFlags() = mTriggeringSandboxFlags;
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
loadState.TriggeringRemoteType() = mTriggeringRemoteType;
loadState.Csp() = mCsp;
loadState.OriginalURIString() = mOriginalURIString;
loadState.CancelContentJSEpoch() = mCancelContentJSEpoch;
loadState.ReferrerInfo() = mReferrerInfo;
loadState.PostDataStream() = mPostDataStream;
loadState.HeadersStream() = mHeadersStream;
loadState.SrcdocData() = mSrcdocData;
loadState.ResultPrincipalURI() = mResultPrincipalURI;
loadState.LoadIdentifier() = mLoadIdentifier;
loadState.ChannelInitialized() = mChannelInitialized;
loadState.IsMetaRefresh() = mIsMetaRefresh;
if (mLoadingSessionHistoryInfo) {
loadState.loadingSessionHistoryInfo().emplace(*mLoadingSessionHistoryInfo);
}
loadState.UnstrippedURI() = mUnstrippedURI;
loadState.RemoteTypeOverride() = mRemoteTypeOverride;
Bug 1538028 - Part 2: Track TriggeringRemoteType through nsDocShellLoadState and LoadInfo, r=smaug,ckerschb,necko-reviewers,valentin This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
2022-11-29 23:41:45 +03:00
if (XRE_IsParentProcess()) {
mozilla::ipc::IToplevelProtocol* top = aActor->ToplevelProtocol();
MOZ_RELEASE_ASSERT(top &&
top->GetProtocolId() ==
mozilla::ipc::ProtocolId::PContentMsgStart &&
top->GetSide() == mozilla::ipc::ParentSide,
"nsDocShellLoadState must be sent over PContent");
ContentParent* cp = static_cast<ContentParent*>(top);
cp->StorePendingLoadState(this);
}
return loadState;
}
nsIURI* nsDocShellLoadState::GetUnstrippedURI() const { return mUnstrippedURI; }
void nsDocShellLoadState::SetUnstrippedURI(nsIURI* aUnstrippedURI) {
mUnstrippedURI = aUnstrippedURI;
}