Commit 4b493b6a authored by Andreas Farre's avatar Andreas Farre
Browse files

Bug 1595491 - Part 1: Make <embed> and <object> behave more like <iframe>. r=smaug,emilio

By making image loading in <embed> and <object> behave more like when
an <iframe> loads an image, we can make sure that the synthetic
document generated is process switched if the image is cross
origin. This is done by making image loading in nsObjectLoadingContent
follow the document loading path.

We also make sure that we pass the image size back to the embedder
element to not get stuck with the intrinsic size.

To avoid named targeting being able to target these synthetic
documents, as well as showing up in `Window.frames` and being counted
in `Window.length`, we keep a filtered list of non-synthetic browsing
contexts for that use-case.

This feature is controlled by two prefs:

* browser.opaqueResponseBlocking.syntheticBrowsingContext

  This triggers the creation of synthetic documents for images loaded
  in <object> or embed.

* browser.opaqueResponseBlocking.syntheticBrowsingContext.filter

  This turns on the filtering of synthetic browsing contexts in named
  targeting, `Window.length` and `Window.frames`.

Differential Revision: https://phabricator.services.mozilla.com/D148117
parent 9b0c492d
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -737,7 +737,18 @@ void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
      obs->NotifyWhenScriptSafe(ToSupports(this),
                                "browsing-context-did-set-embedder", nullptr);
    }

    if (IsEmbedderTypeObjectOrEmbed()) {
      Unused << SetSyntheticDocumentContainer(true);
    }
  }
}

bool BrowsingContext::IsEmbedderTypeObjectOrEmbed() {
  if (const Maybe<nsString>& type = GetEmbedderElementType()) {
    return nsGkAtoms::object->Equals(*type) || nsGkAtoms::embed->Equals(*type);
  }
  return false;
}

void BrowsingContext::Embed() {
@@ -1059,6 +1070,13 @@ void BrowsingContext::GetChildren(
  aChildren.AppendElements(Children());
}

Span<RefPtr<BrowsingContext>> BrowsingContext::NonSyntheticChildren() const {
  if (WindowContext* current = mCurrentWindowContext) {
    return current->NonSyntheticChildren();
  }
  return Span<RefPtr<BrowsingContext>>();
}

void BrowsingContext::GetWindowContexts(
    nsTArray<RefPtr<WindowContext>>& aWindows) {
  aWindows.AppendElements(mWindowContexts);
@@ -1209,7 +1227,7 @@ BrowsingContext* BrowsingContext::FindWithName(
        found = parent;
        break;
      } else {
        siblings = parent->Children();
        siblings = parent->NonSyntheticChildren();
      }

      for (BrowsingContext* sibling : siblings) {
@@ -1244,7 +1262,7 @@ BrowsingContext* BrowsingContext::FindChildWithName(
    return nullptr;
  }

  for (BrowsingContext* child : Children()) {
  for (BrowsingContext* child : NonSyntheticChildren()) {
    if (child->NameEquals(aName) && aRequestingContext.CanAccess(child) &&
        child->IsTargetable()) {
      return child;
@@ -1288,7 +1306,7 @@ BrowsingContext* BrowsingContext::FindWithNameInSubtree(
    return this;
  }

  for (BrowsingContext* child : Children()) {
  for (BrowsingContext* child : NonSyntheticChildren()) {
    if (BrowsingContext* found =
            child->FindWithNameInSubtree(aName, aRequestingContext)) {
      return found;
@@ -2966,6 +2984,13 @@ void BrowsingContext::DidSet(FieldIndex<IDX_IsInBFCache>) {
  }
}

void BrowsingContext::DidSet(FieldIndex<IDX_SyntheticDocumentContainer>) {
  if (WindowContext* parentWindowContext = GetParentWindowContext()) {
    parentWindowContext->UpdateChildSynthetic(this,
                                              GetSyntheticDocumentContainer());
  }
}

void BrowsingContext::SetCustomPlatform(const nsAString& aPlatform,
                                        ErrorResult& aRv) {
  Top()->SetPlatformOverride(aPlatform, aRv);
+12 −1
Original line number Diff line number Diff line
@@ -234,7 +234,10 @@ enum class ExplicitActiveStatus : uint8_t {
  /* This field only gets incrememented when we start navigations in the      \
   * parent process. This is used for keeping track of the racing navigations \
   * between the parent and content processes. */                             \
  FIELD(ParentInitiatedNavigationEpoch, uint64_t)
  FIELD(ParentInitiatedNavigationEpoch, uint64_t)                             \
  /* This browsing context is for a synthetic image document wrapping an      \
   * image embedded in <object> or <embed>. */                                \
  FIELD(SyntheticDocumentContainer, bool)

// BrowsingContext, in this context, is the cross process replicated
// environment in which information about documents is stored. In
@@ -366,6 +369,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
  Element* GetEmbedderElement() const { return mEmbedderElement; }
  void SetEmbedderElement(Element* aEmbedder);

  // Return true if the type of the embedder element is either object
  // or embed, false otherwise.
  bool IsEmbedderTypeObjectOrEmbed();

  // Called after the BrowingContext has been embedded in a FrameLoader. This
  // happens after `SetEmbedderElement` is called on the BrowsingContext and
  // after the BrowsingContext has been set on the FrameLoader.
@@ -488,6 +495,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
  Span<RefPtr<BrowsingContext>> Children() const;
  void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);

  Span<RefPtr<BrowsingContext>> NonSyntheticChildren() const;

  const nsTArray<RefPtr<WindowContext>>& GetWindowContexts() {
    return mWindowContexts;
  }
@@ -1194,6 +1203,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
  bool CanSet(FieldIndex<IDX_IsInBFCache>, bool, ContentParent* aSource);
  void DidSet(FieldIndex<IDX_IsInBFCache>);

  void DidSet(FieldIndex<IDX_SyntheticDocumentContainer>);

  // Allow if the process attemping to set field is the same as the owning
  // process. Deprecated. New code that might use this should generally be moved
  // to WindowContext or be settable only by the parent process.
+19 −0
Original line number Diff line number Diff line
@@ -122,6 +122,9 @@ void WindowContext::AppendChildBrowsingContext(
  MOZ_DIAGNOSTIC_ASSERT(!mChildren.Contains(aBrowsingContext));

  mChildren.AppendElement(aBrowsingContext);
  if (!aBrowsingContext->IsEmbedderTypeObjectOrEmbed()) {
    mNonSyntheticChildren.AppendElement(aBrowsingContext);
  }

  // If we're the current WindowContext in our BrowsingContext, make sure to
  // clear any cached `children` value.
@@ -136,6 +139,7 @@ void WindowContext::RemoveChildBrowsingContext(
                        "Mismatched groups?");

  mChildren.RemoveElement(aBrowsingContext);
  mNonSyntheticChildren.RemoveElement(aBrowsingContext);

  // If we're the current WindowContext in our BrowsingContext, make sure to
  // clear any cached `children` value.
@@ -144,6 +148,19 @@ void WindowContext::RemoveChildBrowsingContext(
  }
}

void WindowContext::UpdateChildSynthetic(BrowsingContext* aBrowsingContext,
                                         bool aIsSynthetic) {
  if (aIsSynthetic) {
    mNonSyntheticChildren.RemoveElement(aBrowsingContext);
  } else {
    // The same BrowsingContext will be reused for error pages, so it can be in
    // the list already.
    if (!mNonSyntheticChildren.Contains(aBrowsingContext)) {
      mNonSyntheticChildren.AppendElement(aBrowsingContext);
    }
  }
}

void WindowContext::SendCommitTransaction(ContentParent* aParent,
                                          const BaseTransaction& aTxn,
                                          uint64_t aEpoch) {
@@ -569,12 +586,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WindowContext)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildren)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonSyntheticChildren)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WindowContext)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonSyntheticChildren)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(WindowContext)
+21 −0
Original line number Diff line number Diff line
@@ -147,6 +147,12 @@ class WindowContext : public nsISupports, public nsWrapperCache {

  Span<RefPtr<BrowsingContext>> Children() { return mChildren; }

  // The filtered version of `Children()`, which contains no browsing contexts
  // for synthetic documents as created by object loading content.
  Span<RefPtr<BrowsingContext>> NonSyntheticChildren() {
    return mNonSyntheticChildren;
  }

  // Cast this object to it's parent-process canonical form.
  WindowGlobalParent* Canonical();

@@ -219,6 +225,12 @@ class WindowContext : public nsISupports, public nsWrapperCache {
  void AppendChildBrowsingContext(BrowsingContext* aBrowsingContext);
  void RemoveChildBrowsingContext(BrowsingContext* aBrowsingContext);

  // Update non-synthetic children based on whether `aBrowsingContext`
  // is synthetic or not. Regardless the synthetic of `aBrowsingContext`, it is
  // kept in this WindowContext's all children list.
  void UpdateChildSynthetic(BrowsingContext* aBrowsingContext,
                            bool aIsSynthetic);

  // Send a given `BaseTransaction` object to the correct remote.
  void SendCommitTransaction(ContentParent* aParent,
                             const BaseTransaction& aTxn, uint64_t aEpoch);
@@ -331,6 +343,15 @@ class WindowContext : public nsISupports, public nsWrapperCache {
  // `AppendChildBrowsingContext` and `RemoveChildBrowsingContext` methods.
  nsTArray<RefPtr<BrowsingContext>> mChildren;

  // --- NEVER CHANGE `mNonSyntheticChildren` DIRECTLY! ---
  // Same reason as for mChildren.
  // mNonSyntheticChildren contains the same browsing contexts except browsing
  // contexts created by the synthetic document for object loading contents
  // loading images. This is used to discern browsing contexts created when
  // loading images in <object> or <embed> elements, so that they can be hidden
  // from named targeting, `Window.frames` etc.
  nsTArray<RefPtr<BrowsingContext>> mNonSyntheticChildren;

  bool mIsDiscarded = false;
  bool mIsInProcess = false;

+10 −0
Original line number Diff line number Diff line
@@ -16520,6 +16520,16 @@ Selection* Document::GetSelection(ErrorResult& aRv) {
  return nsGlobalWindowInner::Cast(window)->GetSelection(aRv);
}
void Document::MakeBrowsingContextNonSynthetic() {
  if (nsContentUtils::ShouldHideObjectOrEmbedImageDocument()) {
    if (BrowsingContext* bc = GetBrowsingContext()) {
      if (bc->GetSyntheticDocumentContainer()) {
        Unused << bc->SetSyntheticDocumentContainer(false);
      }
    }
  }
}
nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
  // Step 1: check if cookie permissions are available or denied to this
  // document's principal
Loading