High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionSandbox escape in the DOM: Navigation component
ComponentDOM
Bug ClassLogic Error
Tracker2053240
Fix commit482ee76bf031 (firefox) +324/-154
CISA KEVNot listed
CreditedMozilla
Disclosed2026-10-27

Changed Functions

FunctionChangeNotes
if
docshell/base/BrowsingContext.cpp
modified

Files Changed

  • docshell/base/BrowsingContext.cpp
  • docshell/base/BrowsingContext.h
  • docshell/base/SyncedContext.h
  • docshell/base/SyncedContextInlines.h
  • dom/ipc/BrowserParent.cpp
  • dom/ipc/ContentParent.cpp
  • dom/ipc/WindowGlobalActor.cpp
  • dom/ipc/WindowGlobalActor.h
  • dom/ipc/WindowGlobalParent.cpp
  • dom/ipc/WindowGlobalParent.h
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…