Skip to content

Commit

Permalink
Bug 1835907, part 1 - Add has storage access bit and triggering windo…
Browse files Browse the repository at this point in the history
…w id to the LoadInfo - r=smaug,necko-reviewers,kershaw,pbz

In the Storage Access API's latest draft, a few items were added to the user-agent state. Relevant here,
the source snapshot params gained two fields that are initialized from the sourceDocument during
snapshotting source params while navigating: "has storage access" and "environment id".

https://privacycg.github.io/storage-access/#ua-state

These are used to identify self-initiated navigations that come from documents that have obtained storage access.
Combined with a same-origin check, this determines if the destination document of the navigation should start
with storage access.

This is stricter than the current behavior, where if the permission is available, all documents start with storage access.
Instead, now a document will only have storage access if it requests it explicitly or if a same-origin document that has
storage access navigates itself to that document. This is seen as a security win.

Security discussion of this change was here: privacycg/storage-access#113
Artur at Google wrote up a great summary here: https://docs.google.com/document/d/1AsrETl-7XvnZNbG81Zy9BcZfKbqACQYBSrjM3VsIpjY/edit#

Differential Revision: https://phabricator.services.mozilla.com/D184821
  • Loading branch information
bvandersloot-mozilla committed Aug 14, 2023
1 parent eaf9096 commit 06a4432
Show file tree
Hide file tree
Showing 13 changed files with 182 additions and 5 deletions.
38 changes: 36 additions & 2 deletions docshell/base/nsDocShell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4014,6 +4014,13 @@ nsresult nsDocShell::LoadErrorPage(nsIURI* aErrorURI, nsIURI* aFailedURI,
loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
if (mBrowsingContext) {
loadState->SetTriggeringSandboxFlags(mBrowsingContext->GetSandboxFlags());
loadState->SetTriggeringWindowId(
mBrowsingContext->GetCurrentInnerWindowId());
nsPIDOMWindowInner* innerWin = mScriptGlobal->GetCurrentInnerWindow();
if (innerWin) {
loadState->SetTriggeringStorageAccess(
innerWin->HasStorageAccessPermissionGranted());
}
}
loadState->SetLoadType(LOAD_ERROR_PAGE);
loadState->SetFirstParty(true);
Expand Down Expand Up @@ -4200,6 +4207,8 @@ nsresult nsDocShell::ReloadDocument(nsDocShell* aDocShell, Document* aDocument,
nsIPrincipal* triggeringPrincipal = aDocument->NodePrincipal();
nsCOMPtr<nsIContentSecurityPolicy> csp = aDocument->GetCsp();
uint32_t triggeringSandboxFlags = aDocument->GetSandboxFlags();
uint64_t triggeringWindowId = aDocument->InnerWindowID();
bool triggeringStorageAccess = aDocument->HasStorageAccessPermissionGranted();

nsAutoString contentTypeHint;
aDocument->GetContentType(contentTypeHint);
Expand Down Expand Up @@ -4246,6 +4255,8 @@ nsresult nsDocShell::ReloadDocument(nsDocShell* aDocShell, Document* aDocument,
loadState->SetLoadReplace(loadReplace);
loadState->SetTriggeringPrincipal(triggeringPrincipal);
loadState->SetTriggeringSandboxFlags(triggeringSandboxFlags);
loadState->SetTriggeringWindowId(triggeringWindowId);
loadState->SetTriggeringStorageAccess(triggeringStorageAccess);
loadState->SetPrincipalToInherit(triggeringPrincipal);
loadState->SetCsp(csp);
loadState->SetInternalLoadFlags(flags);
Expand Down Expand Up @@ -5233,6 +5244,9 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal,
loadState->SetHasValidUserGestureActivation(
doc->HasValidTransientUserGestureActivation());
loadState->SetTriggeringSandboxFlags(doc->GetSandboxFlags());
loadState->SetTriggeringWindowId(doc->InnerWindowID());
loadState->SetTriggeringStorageAccess(
doc->HasStorageAccessPermissionGranted());
}

loadState->SetPrincipalIsExplicit(true);
Expand Down Expand Up @@ -8574,6 +8588,9 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) {
loadState->SetTriggeringPrincipal(aLoadState->TriggeringPrincipal());
loadState->SetTriggeringSandboxFlags(
aLoadState->TriggeringSandboxFlags());
loadState->SetTriggeringWindowId(aLoadState->TriggeringWindowId());
loadState->SetTriggeringStorageAccess(
aLoadState->TriggeringStorageAccess());
loadState->SetCsp(aLoadState->Csp());
loadState->SetInheritPrincipal(aLoadState->HasInternalLoadFlags(
INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL));
Expand Down Expand Up @@ -10511,9 +10528,16 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
}
}

if (mLoadType != LOAD_ERROR_PAGE && context && context->IsInProcess() &&
context->HasValidTransientUserGestureActivation()) {
if (mLoadType != LOAD_ERROR_PAGE && context && context->IsInProcess()) {
aLoadState->SetHasValidUserGestureActivation(true);
aLoadState->SetTriggeringWindowId(context->Id());
if (!aLoadState->TriggeringStorageAccess()) {
Document* contextDoc = context->GetExtantDoc();
if (contextDoc) {
aLoadState->SetTriggeringStorageAccess(
contextDoc->HasStorageAccessPermissionGranted());
}
}
}

// in case this docshell load was triggered by a valid transient user gesture,
Expand All @@ -10523,6 +10547,9 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
aLoadState->HasLoadFlags(LOAD_FLAGS_FROM_EXTERNAL)) {
loadInfo->SetHasValidUserGestureActivation(true);
}

loadInfo->SetTriggeringWindowId(aLoadState->TriggeringWindowId());
loadInfo->SetTriggeringStorageAccess(aLoadState->TriggeringStorageAccess());
loadInfo->SetTriggeringSandboxFlags(aLoadState->TriggeringSandboxFlags());
loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh());

Expand Down Expand Up @@ -13040,8 +13067,13 @@ nsresult nsDocShell::OnLinkClickSync(nsIContent* aContent,
}
}
uint32_t triggeringSandboxFlags = 0;
uint64_t triggeringWindowId = 0;
bool triggeringStorageAccess = false;
if (mBrowsingContext) {
triggeringSandboxFlags = aContent->OwnerDoc()->GetSandboxFlags();
triggeringWindowId = aContent->OwnerDoc()->InnerWindowID();
triggeringStorageAccess =
aContent->OwnerDoc()->HasStorageAccessPermissionGranted();
}

uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
Expand Down Expand Up @@ -13149,6 +13181,8 @@ nsresult nsDocShell::OnLinkClickSync(nsIContent* aContent,
RefPtr<WindowContext> context = mBrowsingContext->GetCurrentWindowContext();

aLoadState->SetTriggeringSandboxFlags(triggeringSandboxFlags);
aLoadState->SetTriggeringWindowId(triggeringWindowId);
aLoadState->SetTriggeringStorageAccess(triggeringStorageAccess);
aLoadState->SetReferrerInfo(referrerInfo);
aLoadState->SetInternalLoadFlags(flags);
aLoadState->SetTypeHint(NS_ConvertUTF16toUTF8(typeHint));
Expand Down
28 changes: 28 additions & 0 deletions docshell/base/nsDocShellLoadState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ nsDocShellLoadState::nsDocShellLoadState(
mPrincipalToInherit = aLoadState.PrincipalToInherit();
mPartitionedPrincipalToInherit = aLoadState.PartitionedPrincipalToInherit();
mTriggeringSandboxFlags = aLoadState.TriggeringSandboxFlags();
mTriggeringWindowId = aLoadState.TriggeringWindowId();
mTriggeringStorageAccess = aLoadState.TriggeringStorageAccess();
mTriggeringRemoteType = aLoadState.TriggeringRemoteType();
mCsp = aLoadState.Csp();
mOriginalURIString = aLoadState.OriginalURIString();
Expand Down Expand Up @@ -150,6 +152,8 @@ nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
mResultPrincipalURIIsSome(aOther.mResultPrincipalURIIsSome),
mTriggeringPrincipal(aOther.mTriggeringPrincipal),
mTriggeringSandboxFlags(aOther.mTriggeringSandboxFlags),
mTriggeringWindowId(aOther.mTriggeringWindowId),
mTriggeringStorageAccess(aOther.mTriggeringStorageAccess),
mCsp(aOther.mCsp),
mKeepResultPrincipalURIIfSet(aOther.mKeepResultPrincipalURIIfSet),
mLoadReplace(aOther.mLoadReplace),
Expand Down Expand Up @@ -204,6 +208,8 @@ nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI, uint64_t aLoadIdentifier)
: mURI(aURI),
mResultPrincipalURIIsSome(false),
mTriggeringSandboxFlags(0),
mTriggeringWindowId(0),
mTriggeringStorageAccess(false),
mKeepResultPrincipalURIIfSet(false),
mLoadReplace(false),
mInheritPrincipal(false),
Expand Down Expand Up @@ -443,6 +449,9 @@ nsresult nsDocShellLoadState::CreateFromLoadURIOptions(
loadState->SetHasValidUserGestureActivation(
aLoadURIOptions.mHasValidUserGestureActivation);
loadState->SetTriggeringSandboxFlags(aLoadURIOptions.mTriggeringSandboxFlags);
loadState->SetTriggeringWindowId(aLoadURIOptions.mTriggeringWindowId);
loadState->SetTriggeringStorageAccess(
aLoadURIOptions.mTriggeringStorageAccess);
loadState->SetPostDataStream(postData);
loadState->SetHeadersStream(aLoadURIOptions.mHeaders);
loadState->SetBaseURI(aLoadURIOptions.mBaseURI);
Expand Down Expand Up @@ -562,6 +571,23 @@ uint32_t nsDocShellLoadState::TriggeringSandboxFlags() const {
return mTriggeringSandboxFlags;
}

void nsDocShellLoadState::SetTriggeringWindowId(uint64_t aTriggeringWindowId) {
mTriggeringWindowId = aTriggeringWindowId;
}

uint64_t nsDocShellLoadState::TriggeringWindowId() const {
return mTriggeringWindowId;
}

void nsDocShellLoadState::SetTriggeringStorageAccess(
bool aTriggeringStorageAccess) {
mTriggeringStorageAccess = aTriggeringStorageAccess;
}

bool nsDocShellLoadState::TriggeringStorageAccess() const {
return mTriggeringStorageAccess;
}

bool nsDocShellLoadState::InheritPrincipal() const { return mInheritPrincipal; }

void nsDocShellLoadState::SetInheritPrincipal(bool aInheritPrincipal) {
Expand Down Expand Up @@ -1253,6 +1279,8 @@ DocShellLoadStateInit nsDocShellLoadState::Serialize(
loadState.PrincipalToInherit() = mPrincipalToInherit;
loadState.PartitionedPrincipalToInherit() = mPartitionedPrincipalToInherit;
loadState.TriggeringSandboxFlags() = mTriggeringSandboxFlags;
loadState.TriggeringWindowId() = mTriggeringWindowId;
loadState.TriggeringStorageAccess() = mTriggeringStorageAccess;
loadState.TriggeringRemoteType() = mTriggeringRemoteType;
loadState.Csp() = mCsp;
loadState.OriginalURIString() = mOriginalURIString;
Expand Down
14 changes: 14 additions & 0 deletions docshell/base/nsDocShellLoadState.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ class nsDocShellLoadState final {

void SetTriggeringSandboxFlags(uint32_t aTriggeringSandboxFlags);

uint64_t TriggeringWindowId() const;

void SetTriggeringWindowId(uint64_t aTriggeringWindowId);

bool TriggeringStorageAccess() const;

void SetTriggeringStorageAccess(bool aTriggeringStorageAccess);

nsIContentSecurityPolicy* Csp() const;

void SetCsp(nsIContentSecurityPolicy* aCsp);
Expand Down Expand Up @@ -413,6 +421,12 @@ class nsDocShellLoadState final {
// SandboxFlags of the document that started the load.
uint32_t mTriggeringSandboxFlags;

// The window ID and current "has storage access" value of the entity
// triggering the load. This allows the identification of self-initiated
// same-origin navigations that should propogate unpartitioned storage access.
uint64_t mTriggeringWindowId;
bool mTriggeringStorageAccess;

// The CSP of the load, that is, the CSP of the entity responsible for causing
// the load to occur. Most likely this is the CSP of the document that started
// the load. In case the entity starting the load did not use a CSP, then mCsp
Expand Down
2 changes: 2 additions & 0 deletions dom/ipc/DOMTypes.ipdlh
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ struct DocShellLoadStateInit
// The TriggineringSandboxFlags are the SandboxFlags of the entity
// responsible for causing the load to occur.
uint32_t TriggeringSandboxFlags;
uint64_t TriggeringWindowId;
bool TriggeringStorageAccess;
int32_t? CancelContentJSEpoch;

bool ResultPrincipalURIIsSome;
Expand Down
9 changes: 9 additions & 0 deletions dom/webidl/LoadURIOptions.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ dictionary LoadURIOptions {
*/
unsigned long triggeringSandboxFlags = 0;

/**
* The window id and storage access status of the window of the
* context that triggered the load. This is used to allow self-initiated
* same-origin navigations to propagate their "has storage access" bit
* to the next Document.
*/
unsigned long long triggeringWindowId = 0;
boolean triggeringStorageAccess = false;

/**
* The RemoteType of the entity that's responsible for the load. Defaults to
* the current process.
Expand Down
14 changes: 13 additions & 1 deletion ipc/glue/BackgroundUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,8 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
topLevelPrincipalInfo, optionalResultPrincipalURI, triggeringRemoteType,
aLoadInfo->GetSandboxedNullPrincipalID(), aLoadInfo->GetSecurityFlags(),
aLoadInfo->GetSandboxFlags(), aLoadInfo->GetTriggeringSandboxFlags(),
aLoadInfo->GetTriggeringWindowId(),
aLoadInfo->GetTriggeringStorageAccess(),
aLoadInfo->InternalContentPolicyType(),
static_cast<uint32_t>(aLoadInfo->GetTainting()),
aLoadInfo->GetBlockAllMixedContent(),
Expand Down Expand Up @@ -829,7 +831,8 @@ nsresult LoadInfoArgsToLoadInfo(const LoadInfoArgs& loadInfoArgs,
triggeringRemoteType, loadInfoArgs.sandboxedNullPrincipalID(), clientInfo,
reservedClientInfo, initialClientInfo, controller,
loadInfoArgs.securityFlags(), loadInfoArgs.sandboxFlags(),
loadInfoArgs.triggeringSandboxFlags(), loadInfoArgs.contentPolicyType(),
loadInfoArgs.triggeringSandboxFlags(), loadInfoArgs.triggeringWindowId(),
loadInfoArgs.triggeringStorageAccess(), loadInfoArgs.contentPolicyType(),
static_cast<LoadTainting>(loadInfoArgs.tainting()),
loadInfoArgs.blockAllMixedContent(),
loadInfoArgs.upgradeInsecureRequests(),
Expand Down Expand Up @@ -928,6 +931,8 @@ void LoadInfoToParentLoadInfoForwarder(
aLoadInfo->GetAllowDeprecatedSystemRequests(),
aLoadInfo->GetIsInDevToolsContext(), aLoadInfo->GetParserCreatedScript(),
aLoadInfo->GetTriggeringSandboxFlags(),
aLoadInfo->GetTriggeringWindowId(),
aLoadInfo->GetTriggeringStorageAccess(),
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
aLoadInfo->GetDocumentHasUserInteracted(),
aLoadInfo->GetAllowListFutureDocumentsCreatedFromThisRedirectChain(),
Expand Down Expand Up @@ -971,6 +976,13 @@ nsresult MergeParentLoadInfoForwarder(
aForwarderArgs.triggeringSandboxFlags());
NS_ENSURE_SUCCESS(rv, rv);

rv = aLoadInfo->SetTriggeringWindowId(aForwarderArgs.triggeringWindowId());
NS_ENSURE_SUCCESS(rv, rv);

rv = aLoadInfo->SetTriggeringStorageAccess(
aForwarderArgs.triggeringStorageAccess());
NS_ENSURE_SUCCESS(rv, rv);

rv = aLoadInfo->SetHasValidUserGestureActivation(
aForwarderArgs.hasValidUserGestureActivation());
NS_ENSURE_SUCCESS(rv, rv);
Expand Down
31 changes: 30 additions & 1 deletion netwerk/base/LoadInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
mSecurityFlags(rhs.mSecurityFlags),
mSandboxFlags(rhs.mSandboxFlags),
mTriggeringSandboxFlags(rhs.mTriggeringSandboxFlags),
mTriggeringWindowId(rhs.mTriggeringWindowId),
mTriggeringStorageAccess(rhs.mTriggeringStorageAccess),
mInternalContentPolicyType(rhs.mInternalContentPolicyType),
mTainting(rhs.mTainting),
mBlockAllMixedContent(rhs.mBlockAllMixedContent),
Expand Down Expand Up @@ -651,7 +653,8 @@ LoadInfo::LoadInfo(
const Maybe<ClientInfo>& aInitialClientInfo,
const Maybe<ServiceWorkerDescriptor>& aController,
nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags,
uint32_t aTriggeringSandboxFlags, nsContentPolicyType aContentPolicyType,
uint32_t aTriggeringSandboxFlags, uint64_t aTriggeringWindowId,
bool aTriggeringStorageAccess, nsContentPolicyType aContentPolicyType,
LoadTainting aTainting, bool aBlockAllMixedContent,
bool aUpgradeInsecureRequests, bool aBrowserUpgradeInsecureRequests,
bool aBrowserDidUpgradeInsecureRequests,
Expand Down Expand Up @@ -699,6 +702,8 @@ LoadInfo::LoadInfo(
mSecurityFlags(aSecurityFlags),
mSandboxFlags(aSandboxFlags),
mTriggeringSandboxFlags(aTriggeringSandboxFlags),
mTriggeringWindowId(aTriggeringWindowId),
mTriggeringStorageAccess(aTriggeringStorageAccess),
mInternalContentPolicyType(aContentPolicyType),
mTainting(aTainting),
mBlockAllMixedContent(aBlockAllMixedContent),
Expand Down Expand Up @@ -975,6 +980,30 @@ LoadInfo::SetTriggeringSandboxFlags(uint32_t aFlags) {
return NS_OK;
}

NS_IMETHODIMP
LoadInfo::GetTriggeringWindowId(uint64_t* aResult) {
*aResult = mTriggeringWindowId;
return NS_OK;
}

NS_IMETHODIMP
LoadInfo::SetTriggeringWindowId(uint64_t aFlags) {
mTriggeringWindowId = aFlags;
return NS_OK;
}

NS_IMETHODIMP
LoadInfo::GetTriggeringStorageAccess(bool* aResult) {
*aResult = mTriggeringStorageAccess;
return NS_OK;
}

NS_IMETHODIMP
LoadInfo::SetTriggeringStorageAccess(bool aFlags) {
mTriggeringStorageAccess = aFlags;
return NS_OK;
}

NS_IMETHODIMP
LoadInfo::GetSecurityMode(uint32_t* aFlags) {
*aFlags = (mSecurityFlags &
Expand Down
5 changes: 4 additions & 1 deletion netwerk/base/LoadInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ class LoadInfo final : public nsILoadInfo {
const Maybe<mozilla::dom::ClientInfo>& aInitialClientInfo,
const Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController,
nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags,
uint32_t aTriggeringSandboxFlags, nsContentPolicyType aContentPolicyType,
uint32_t aTriggeringSandboxFlags, uint64_t aTriggeringWindowId,
bool aTriggeringStorageAccess, nsContentPolicyType aContentPolicyType,
LoadTainting aTainting, bool aBlockAllMixedContent,
bool aUpgradeInsecureRequests, bool aBrowserUpgradeInsecureRequests,
bool aBrowserDidUpgradeInsecureRequests,
Expand Down Expand Up @@ -306,6 +307,8 @@ class LoadInfo final : public nsILoadInfo {
nsSecurityFlags mSecurityFlags;
uint32_t mSandboxFlags;
uint32_t mTriggeringSandboxFlags = 0;
uint64_t mTriggeringWindowId = 0;
bool mTriggeringStorageAccess = false;
nsContentPolicyType mInternalContentPolicyType;
LoadTainting mTainting = LoadTainting::Basic;
bool mBlockAllMixedContent = false;
Expand Down
18 changes: 18 additions & 0 deletions netwerk/base/TRRLoadInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@ TRRLoadInfo::SetTriggeringSandboxFlags(uint32_t aResult) {
return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP
TRRLoadInfo::GetTriggeringWindowId(uint64_t* aResult) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
TRRLoadInfo::SetTriggeringWindowId(uint64_t aResult) {
return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP
TRRLoadInfo::GetTriggeringStorageAccess(bool* aResult) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
TRRLoadInfo::SetTriggeringStorageAccess(bool aResult) {
return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP
TRRLoadInfo::GetSecurityMode(uint32_t* aFlags) {
return NS_ERROR_NOT_IMPLEMENTED;
Expand Down
10 changes: 10 additions & 0 deletions netwerk/base/nsILoadInfo.idl
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,16 @@ interface nsILoadInfo : nsISupports
*/
[infallible] attribute unsigned long triggeringSandboxFlags;


/**
* The window id and storage access status of the window of the
* context that triggered the load. This is used to allow self-initiated
* same-origin navigations to propogate their "has storage access" bit
* to the next Document.
*/
[infallible] attribute unsigned long long triggeringWindowId;
[infallible] attribute boolean triggeringStorageAccess;

/**
* Allows to query only the security mode bits from above.
*/
Expand Down
Loading

0 comments on commit 06a4432

Please sign in to comment.