Firefox · DOM
CVE-2026-117861
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdocshell/base/BrowsingContext.cpp |
modified |
Files Changed
docshell/base/BrowsingContext.cppdocshell/base/BrowsingContext.hdocshell/base/SyncedContext.hdocshell/base/SyncedContextInlines.hdom/ipc/BrowserParent.cppdom/ipc/ContentParent.cppdom/ipc/WindowGlobalActor.cppdom/ipc/WindowGlobalActor.hdom/ipc/WindowGlobalParent.cppdom/ipc/WindowGlobalParent.h
Patch
diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp
index a6155fa2eeb..b3ff062350e 100644
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -350,6 +350,84 @@ bool BrowsingContext::SameOriginWithTop() {
return principal->Equals(topPrincipal);
}
+/* static */
+BrowsingContext::FieldValues BrowsingContext::ComputeInitialFields(
+ WindowContext* aParentWindow, BrowsingContext* aOpener,
+ BrowsingContextGroup* aGroup, Type aType) {
+ BrowsingContext* const parentBC =
+ aParentWindow ? aParentWindow->GetBrowsingContext() : nullptr;
+
+ BrowsingContext* const inherit = parentBC ? parentBC : aOpener;
+
+ FieldValues fields;
+ if (inherit) {
+ fields.Get<IDX_AllowContentRetargeting>() =
+ inherit->GetAllowContentRetargetingOnChildren();
+ fields.Get<IDX_AllowContentRetargetingOnChildren>() =
+ inherit->GetAllowContentRetargetingOnChildren();
+ fields.Get<IDX_DefaultLoadFlags>() = inherit->GetDefaultLoadFlags();
+ fields.Get<IDX_UseGlobalHistory>() = inherit->GetUseGlobalHistory();
+ fields.Get<IDX_AllowJavascript>() = inherit->GetAllowJavascript();
+ fields.Get<IDX_IPAddressSpace>() = inherit->GetIPAddressSpace();
+ fields.Get<IDX_ParentalControlsEnabled>() =
+ inherit->GetParentalControlsEnabled();
+ }
+
+ if (aOpener) {
+ fields.Get<IDX_OpenerId>() = aOpener->Id();
+ fields.Get<IDX_HadOriginalOpener>() = true;
+ fields.Get<IDX_MessageManagerGroup>() =
+ aOpener->Top()->GetMessageManagerGroup();
+
+ if (aType == Type::Chrome && !aParentWindow) {
+ // See SetOpener for why we do this inheritance.
+ fields.Get<IDX_PrefersColorSchemeOverride>() =
+ aOpener->Top()->GetPrefersColorSchemeOverride();
+ }
+ }
+
+ if (aParentWindow) {
+ fields.Get<IDX_EmbedderInnerWindowId>() = aParentWindow->Id();
+ // Non-toplevel content documents are always embedded within content.
+ fields.Get<IDX_EmbeddedInContentDocument>() = parentBC->IsContent();
+ fields.Get<IDX_BrowserId>() = parentBC->GetBrowserId();
+ fields.Get<IDX_AncestorLoading>() = parentBC->GetAncestorLoading();
+ fields.Get<IDX_FullZoom>() = parentBC->FullZoom();
+ fields.Get<IDX_TextZoom>() = parentBC->TextZoom();
+ } else if (aGroup->IsPotentiallyCrossOriginIsolated()) {
+ // A brand-new toplevel BC in a potentially cross-origin isolated group
+ // starts out with a strict opener policy.
+ fields.Get<IDX_OpenerPolicy>() =
+ nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
+ }
+
+ fields.Get<IDX_ExplicitActive>() = [&] {
+ if (parentBC || aType == Type::Content) {
+ // Non-root browsing-contexts inherit their status from its parent.
+ // Top-content either gets managed by the top chrome, or gets manually
+ // managed by the front-end (see ManuallyManagesActiveness). In any case
+ // we want to start off as inactive.
+ return ExplicitActiveStatus::None;
+ }
+ // Chrome starts as active.
+ return ExplicitActiveStatus::Active;
+ }();
+
+ // Assume top allows fullscreen for its children unless otherwise stated.
+ // Subframes start with it false unless otherwise noted in SetEmbedderElement.
+ fields.Get<IDX_FullscreenAllowedByOwner>() = !aParentWindow;
+
+ if (!inherit && XRE_IsParentProcess()) {
+ fields.Get<IDX_ParentalControlsEnabled>() =
+ CanonicalBrowsingContext::ShouldEnforceParentalControls();
+ }
+
+ fields.Get<IDX_ShouldDelayMediaFromStart>() =
+ !parentBC && StaticPrefs::media_block_autoplay_until_in_foreground();
+
+ return fields;
+}
+
/* static */
already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
@@ -373,8 +451,6 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
aParent ? aParent->GetBrowsingContext() : nullptr;
RefPtr<WindowContext> parentWC =
aParent ? aParent->GetWindowContext() : nullptr;
- BrowsingContext* inherit = parentBC ? parentBC.get() : aOpener;
-
// Determine which BrowsingContextGroup this context should be created in.
RefPtr<BrowsingContextGroup> group = aSpecificGroup;
if (aType == Type::Chrome) {
@@ -384,47 +460,31 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
group = BrowsingContextGroup::Select(parentWC, aOpener);
}
- // Configure initial values for synced fields.
- FieldValues fields;
- fields.Get<IDX_Name>() = aName;
+ MOZ_DIAGNOSTIC_ASSERT_IF(aOpener, !aParent);
+ MOZ_DIAGNOSTIC_ASSERT_IF(aOpener, aOpener->Group() == group);
+ MOZ_DIAGNOSTIC_ASSERT_IF(aOpener, aOpener->mType == aType);
+ MOZ_DIAGNOSTIC_ASSERT_IF(aParent, parentBC->Group() == group);
+ MOZ_DIAGNOSTIC_ASSERT_IF(aParent, parentBC->mType == aType);
- if (aOpener) {
- MOZ_DIAGNOSTIC_ASSERT(!aParent,
- "new BC with both initial opener and parent");
- MOZ_DIAGNOSTIC_ASSERT(aOpener->Group() == group);
- MOZ_DIAGNOSTIC_ASSERT(aOpener->mType == aType);
- fields.Get<IDX_OpenerId>() = aOpener->Id();
- fields.Get<IDX_HadOriginalOpener>() = true;
- fields.Get<IDX_MessageManagerGroup>() =
- aOpener->Top()->GetMessageManagerGroup();
-
- if (aType == Type::Chrome && !aParent) {
- // See SetOpener for why we do this inheritance.
- fields.Get<IDX_PrefersColorSchemeOverride>() =
- aOpener->Top()->GetPrefersColorSchemeOverride();
- }
- }
-
- if (aParent) {
- MOZ_DIAGNOSTIC_ASSERT(parentBC->Group() == group);
- MOZ_DIAGNOSTIC_ASSERT(parentBC->mType == aType);
- // Non-toplevel content documents are always embededed within content.
- fields.Get<IDX_EmbeddedInContentDocument>() =
- parentBC->mType == Type::Content;
+ FieldValues fields = ComputeInitialFields(parentWC, aOpener, group, aType);
+ fields.Get<IDX_Name>() = aName;
+ fields.Get<IDX_HistoryID>() = nsID::GenerateUUID();
+ fields.Get<IDX_IsPopupRequested>() = aOptions.isPopupRequested;
+ fields.Get<IDX_TopLevelCreatedByWebContent>() =
+ aOptions.topLevelCreatedByWebContent;
+ if (parentWC) {
// XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug
// 1608448) Check if the parent was itself loading already
- auto readystate = aParent->GetDocument()->GetReadyStateEnum();
+ const auto readystate = aParent->GetDocument()->GetReadyStateEnum();
fields.Get<IDX_AncestorLoading>() =
- parentBC->GetAncestorLoading() ||
+ fields.Get<IDX_AncestorLoading>() ||
readystate == Document::ReadyState::READYSTATE_LOADING ||
readystate == Document::ReadyState::READYSTATE_INTERACTIVE;
+ } else {
+ fields.Get<IDX_BrowserId>() = nsContentUtils::GenerateBrowserId();
}
- fields.Get<IDX_BrowserId>() =
- parentBC ? parentBC->GetBrowserId() : nsContentUtils::GenerateBrowserId();
-
- fields.Get<IDX_OpenerPolicy>() = nsILoadInfo::OPENER_POLICY_UNSAFE_NONE;
if (aOpener && aOpener->SameOriginWithTop()) {
// We inherit the opener policy if there is a creator and if the creator's
// origin is same origin with the creator's top-level origin.
@@ -433,14 +493,14 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
// If we inherit a policy which is potentially cross-origin isolated, we
// must be in a potentially cross-origin isolated BCG.
- bool isPotentiallyCrossOriginIsolated =
+ const bool isPotentiallyCrossOriginIsolated =
fields.Get<IDX_OpenerPolicy>() ==
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
MOZ_RELEASE_ASSERT(isPotentiallyCrossOriginIsolated ==
group->IsPotentiallyCrossOriginIsolated());
} else if (aOpener) {
// They are not same origin
- auto topPolicy = aOpener->Top()->GetOpenerPolicy();
+ const auto topPolicy = aOpener->Top()->GetOpenerPolicy();
MOZ_RELEASE_ASSERT(
topPolicy == nsILoadInfo::OPENER_POLICY_UNSAFE_NONE ||
topPolicy == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS ||
@@ -449,77 +509,12 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
// Ensure our opener policy is consistent for printing for our top.
fields.Get<IDX_OpenerPolicy>() = topPolicy;
}
- } else if (!aParent && group->IsPotentiallyCrossOriginIsolated()) {
- // If we're creating a brand-new toplevel BC in a potentially cross-origin
- // isolated group, it should start out with a strict opener policy.
- fields.Get<IDX_OpenerPolicy>() =
- nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
}
- fields.Get<IDX_HistoryID>() = nsID::GenerateUUID();
- fields.Get<IDX_ExplicitActive>() = [&] {
- if (parentBC || aType == Type::Content) {
- // Non-root browsing-contexts inherit their status from its parent.
- // Top-content either gets managed by the top chrome, or gets manually
- // managed by the front-end (see ManuallyManagesActiveness). In any case
- // we want to start off as inactive.
- return ExplicitActiveStatus::None;
- }
- // Chrome starts as active.
- return ExplicitActiveStatus::Active;
- }();
-
- fields.Get<IDX_FullZoom>() = parentBC ? parentBC->FullZoom() : 1.0f;
- fields.Get<IDX_TextZoom>() = parentBC ? parentBC->TextZoom() : 1.0f;
-
- bool allowContentRetargeting =
- inherit ? inherit->GetAllowContentRetargetingOnChildren() : true;
- fields.Get<IDX_AllowContentRetargeting>() = allowContentRetargeting;
- fields.Get<IDX_AllowContentRetargetingOnChildren>() = allowContentRetargeting;
-
- // Assume top allows fullscreen for its children unless otherwise stated.
- // Subframes start with it false unless otherwise noted in SetEmbedderElement.
- fields.Get<IDX_FullscreenAllowedByOwner>() = !aParent;
-
- fields.Get<IDX_DefaultLoadFlags>() =
- inherit ? inherit->GetDefaultLoadFlags() : nsIRequest::LOAD_NORMAL;
-
- fields.Get<IDX_UseGlobalHistory>() =
- inherit ? inherit->GetUseGlobalHistory() : false;
-
- fields.Get<IDX_AllowJavascript>() =
- inherit ? inherit->GetAllowJavascript() : true;
-
- fields.Get<IDX_IPAddressSpace>() = inherit
- ? inherit->GetIPAddressSpace()
- : nsILoadInfo::IPAddressSpace::Unknown;
-
- bool parentalControlsEnabled;
- if (inherit) {
- parentalControlsEnabled = inherit->GetParentalControlsEnabled();
- } else if (XRE_IsParentProcess()) {
- parentalControlsEnabled =
- CanonicalBrowsingContext::ShouldEnforceParentalControls();
- } else {
- parentalControlsEnabled = false;
- }
-
- fields.Get<IDX_ParentalControlsEnabled>() = parentalControlsEnabled;
-
- fields.Get<IDX_IsPopupRequested>() = aOptions.isPopupRequested;
-
- fields.Get<IDX_TopLevelCreatedByWebContent>() =
- aOptions.topLevelCreatedByWebContent;
-
if (aOptions.isForPrinting && !parentBC) {
fields.Get<IDX_IsPrinting>() = true;
}
- if (!parentBC) {
- fields.Get<IDX_ShouldDelayMediaFromStart>() =
- StaticPrefs::media_block_autoplay_until_in_foreground();
- }
-
RefPtr<BrowsingContext> context;
if (XRE_IsParentProcess()) {
context = new CanonicalBrowsingContext(parentWC, group, id,
@@ -534,7 +529,7 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
context->mWindowless = aOptions.windowless;
context->mEmbeddedByThisProcess = XRE_IsParentProcess() || aParent;
context->mCreatedDynamically = aOptions.createdDynamically;
- if (inherit) {
+ if (BrowsingContext* inherit = parentBC ? parentBC.get() : aOpener) {
context->mPrivateBrowsingId = inherit->mPrivateBrowsingId;
context->mUseRemoteTabs = inherit->mUseRemoteTabs;
context->mUseRemoteSubframes = inherit->mUseRemoteSubframes;
@@ -595,6 +590,28 @@ mozilla::ipc::IPCResult BrowsingContext::CreateFromIPC(
RefPtr<WindowContext> parent = aInit.GetParent();
+ // In the parent process the initializer was authored by a content process.
+ // Start from the values this process derives for itself and reconcile the
+ // initializer's values against them below.
+ FieldValues fields;
+ if (XRE_IsContentProcess()) {
+ fields = std::move(aInit.mFields);
+ } else {
+ RefPtr<BrowsingContext> opener;
+ if (aInit.GetOpenerId() != 0) {
+ opener = BrowsingContext::Get(aInit.GetOpenerId());
+ MOZ_DIAGNOSTIC_ASSERT(opener && opener->Group() == aGroup,
+ "validated by RecvCreateBrowsingContext");
+ }
+ fields = ComputeInitialFields(parent, opener, aGroup, Type::Content);
+ if (!parent) {
+ // The only content process path creating a toplevel context is
+ // ContentChild::ProvideWindowCommon.
+ fields.Get<IDX_TopLevelCreatedByWebContent>() = true;
+ fields.Get<IDX_PendingInitialization>() = true;
+ }
+ }
+
RefPtr<BrowsingContext> context;
if (XRE_IsParentProcess()) {
// If the new BrowsingContext has a parent, it is a sub-frame embedded in
@@ -603,10 +620,22 @@ mozilla::ipc::IPCResult BrowsingContext::CreateFromIPC(
uint64_t embedderProcessId = (aInit.mWindowless || parent) ? originId : 0;
context = new CanonicalBrowsingContext(parent, aGroup, aInit.mId, originId,
embedderProcessId, Type::Content,
- std::move(aInit.mFields));
+ std::move(fields));
} else {
context = new BrowsingContext(parent, aGroup, aInit.mId, Type::Content,
- std::move(aInit.mFields));
+ std::move(fields));
+ }
+
+ Transaction correction;
+ if (XRE_IsParentProcess()) {
+ MOZ_DIAGNOSTIC_ASSERT(!context->EverAttached());
+ Transaction::ReconcileInitialFields(context, std::move(aInit.mFields),
+ aOriginProcess, correction);
+ // A toplevel's BrowserId is generated by the creating process; there is no
+ // derived value to fall back to if it was refused.
+ if (!parent && context->GetBrowserId() == 0) {
+ return IPC_FAIL(aOriginProcess, "Invalid BrowserId for new toplevel");
+ }
}
context->mWindowless = aInit.mWindowless;
@@ -639,6 +668,10 @@ mozilla::ipc::IPCResult BrowsingContext::CreateFromIPC(
Register(context);
context->Attach(/* aFromIPC */ true, aOriginProcess);
+
+ if (XRE_IsParentProcess()) {
+ correction.SendCorrection(context, aOriginProcess);
+ }
return IPC_OK();
}
@@ -3153,15 +3186,6 @@ already_AddRefed<WindowContext> BrowsingContext::IPCInitializer::GetParent() {
return parent.forget();
}
-already_AddRefed<BrowsingContext> BrowsingContext::IPCInitializer::GetOpener() {
- RefPtr<BrowsingContext> opener;
- if (GetOpenerId() != 0) {
- opener = BrowsingContext::Get(GetOpenerId());
- MOZ_RELEASE_ASSERT(opener);
- }
- return opener.forget();
-}
-
void BrowsingContext::StartDelayedAutoplayMediaComponents() {
if (!mDocShell) {
return;
@@ -4222,7 +4246,11 @@ bool BrowsingContext::CanSet(FieldIndex<IDX_BrowserId>, const uint64_t& aValue,
return false;
}
- return GetBrowserId() == 0 && Children().IsEmpty();
+ if (GetBrowserId() != 0 || !Children().IsEmpty()) {
+ return false;
+ }
+ RefPtr<BrowsingContext> existing = GetCurrentTopByBrowserId(aValue);
+ return !existing;
}
bool BrowsingContext::CanSet(FieldIndex<IDX_PendingInitialization>,
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h
index 67be3b7c422..0d669468347 100644
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -110,6 +110,8 @@ struct EmbedderColorSchemes {
//
// * If custom behaviour is needed, `CanSet::Custom` can be specified, which
// will invoke a `CanSet` overload on `BrowsingContext`.
+//
+// Initial values are configured with `.mDefault` and `ComputeInitialFields`.
#define MOZ_EACH_BC_FIELD(FIELD) \
FIELD(Name, nsString, {.mCanSet = CanSet::Unrestricted}) \
FIELD(Closed, bool, {.mCanSet = CanSet::Unrestricted}) \
@@ -187,8 +189,10 @@ struct EmbedderColorSchemes {
* We use it exclusively to block navigation for both of these cases. */ \
FIELD(IsPrinting, bool, {.mCanSet = CanSet::Unrestricted}) \
FIELD(AncestorLoading, bool, {.mCanSet = CanSet::Unrestricted}) \
- FIELD(AllowContentRetargeting, bool, {.mCanSet = CanSet::Custom}) \
- FIELD(AllowContentRetargetingOnChildren, bool, {.mCanSet = CanSet::Custom}) \
+ FIELD(AllowContentRetargeting, bool, \
+ {.mCanSet = CanSet::Custom, .mDefault = [] { return true; }}) \
+ FIELD(AllowContentRetargetingOnChildren, bool, \
+ {.mCanSet = CanSet::Custom, .mDefault = [] { return true; }}) \
FIELD(ForceEnableTrackingProtection, bool, \
{.mCanSet = CanSet::Unrestricted}) \
FIELD(UseGlobalHistory, bool, {.mCanSet = CanSet::Unrestricted}) \
@@ -234,10 +238,12 @@ struct EmbedderColorSchemes {
FIELD(MessageManagerGroup, nsString, \
{.mTopOnly = true, .mCanSet = CanSet::ParentOnly}) \
FIELD(MaxTouchPointsOverride, uint8_t, {.mCanSet = CanSet::Unrestricted}) \
- FIELD(FullZoom, float, {.mCanSet = CanSet::Unrestricted}) \
+ FIELD(FullZoom, float, \
+ {.mCanSet = CanSet::Unrestricted, .mDefault = [] { return 1.0f; }}) \
FIELD(WatchedByDevToolsInternal, bool, \
{.mTopOnly = true, .mCanSet = CanSet::Custom}) \
- FIELD(TextZoom, float, {.mCanSet = CanSet::Unrestricted}) \
+ FIELD(TextZoom, float, \
+ {.mCanSet = CanSet::Unrestricted, .mDefault = [] { return 1.0f; }}) \
FIELD(OverrideDPPX, float, \
{.mTopOnly = true, .mCanSet = CanSet::ParentOnly}) \
... (file diff truncated)
Loading diff…
References
On This Page