Bug 1835907, part 1 - Add has storage access bit and triggering window 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: https://github.com/privacycg/storage-access/issues/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
This commit is contained in:
Benjamin VanderSloot 2023-08-15 13:04:04 +00:00
Родитель 8349767311
Коммит 58d36f75d6
13 изменённых файлов: 185 добавлений и 6 удалений

Просмотреть файл

@ -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);
@ -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);
@ -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);
@ -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);
@ -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));
@ -10511,9 +10528,18 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
}
}
if (mLoadType != LOAD_ERROR_PAGE && context && context->IsInProcess() &&
context->HasValidTransientUserGestureActivation()) {
aLoadState->SetHasValidUserGestureActivation(true);
if (mLoadType != LOAD_ERROR_PAGE && context && context->IsInProcess()) {
if (context->HasValidTransientUserGestureActivation()) {
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,
@ -10523,6 +10549,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());
@ -13040,8 +13069,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;
@ -13149,6 +13183,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));

Просмотреть файл

@ -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();
@ -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),
@ -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),
@ -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);
@ -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) {
@ -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;

Просмотреть файл

@ -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);
@ -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

Просмотреть файл

@ -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;

Просмотреть файл

@ -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.

Просмотреть файл

@ -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(),
@ -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(),
@ -928,6 +931,8 @@ void LoadInfoToParentLoadInfoForwarder(
aLoadInfo->GetAllowDeprecatedSystemRequests(),
aLoadInfo->GetIsInDevToolsContext(), aLoadInfo->GetParserCreatedScript(),
aLoadInfo->GetTriggeringSandboxFlags(),
aLoadInfo->GetTriggeringWindowId(),
aLoadInfo->GetTriggeringStorageAccess(),
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
aLoadInfo->GetDocumentHasUserInteracted(),
aLoadInfo->GetAllowListFutureDocumentsCreatedFromThisRedirectChain(),
@ -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);

Просмотреть файл

@ -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),
@ -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,
@ -699,6 +702,8 @@ LoadInfo::LoadInfo(
mSecurityFlags(aSecurityFlags),
mSandboxFlags(aSandboxFlags),
mTriggeringSandboxFlags(aTriggeringSandboxFlags),
mTriggeringWindowId(aTriggeringWindowId),
mTriggeringStorageAccess(aTriggeringStorageAccess),
mInternalContentPolicyType(aContentPolicyType),
mTainting(aTainting),
mBlockAllMixedContent(aBlockAllMixedContent),
@ -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 &

Просмотреть файл

@ -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,
@ -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;

Просмотреть файл

@ -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;

Просмотреть файл

@ -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.
*/

Просмотреть файл

@ -160,6 +160,8 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext,
}
loadInfo->SetTriggeringSandboxFlags(aLoadState->TriggeringSandboxFlags());
loadInfo->SetTriggeringWindowId(aLoadState->TriggeringWindowId());
loadInfo->SetTriggeringStorageAccess(aLoadState->TriggeringStorageAccess());
loadInfo->SetHasValidUserGestureActivation(
aLoadState->HasValidUserGestureActivation());
loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh());
@ -187,6 +189,8 @@ static auto CreateObjectLoadInfo(nsDocShellLoadState* aLoadState,
loadInfo->SetHasValidUserGestureActivation(
aLoadState->HasValidUserGestureActivation());
loadInfo->SetTriggeringSandboxFlags(aLoadState->TriggeringSandboxFlags());
loadInfo->SetTriggeringWindowId(aLoadState->TriggeringWindowId());
loadInfo->SetTriggeringStorageAccess(aLoadState->TriggeringStorageAccess());
loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh());
return loadInfo.forget();

Просмотреть файл

@ -107,6 +107,8 @@ struct LoadInfoArgs
uint32_t securityFlags;
uint32_t sandboxFlags;
uint32_t triggeringSandboxFlags;
uint64_t triggeringWindowId;
bool triggeringStorageAccess;
nsContentPolicyType contentPolicyType;
uint32_t tainting;
bool blockAllMixedContent;
@ -238,6 +240,12 @@ struct ParentLoadInfoForwarderArgs
// Sandbox Flags of the Document that triggered the load
uint32_t triggeringSandboxFlags;
// Window ID and UsingStorageAccess of the Document that triggered the load.
// Used by the Storage Access API to determine if SubDocument loads should
// be partitioned or not.
uint64_t triggeringWindowId;
bool triggeringStorageAccess;
// We must also note that the tainting value was explicitly set
// by the service worker.
bool serviceWorkerTaintingSynthesized;

Просмотреть файл

@ -1279,6 +1279,12 @@ nsresult nsWindowWatcher::OpenWindowInternal(
loadState->SetTriggeringSandboxFlags(parentBC->GetSandboxFlags());
}
if (parentInnerWin) {
loadState->SetTriggeringWindowId(parentInnerWin->WindowID());
loadState->SetTriggeringStorageAccess(
parentInnerWin->HasStorageAccessPermissionGranted());
}
if (subjectPrincipal) {
loadState->SetTriggeringPrincipal(subjectPrincipal);
}