Firefox · DOM
CVE-2024-10458
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/base/nsObjectLoadingContent.cpp |
modified | |
GetFeaturePolicyDefaultOrigindom/base/nsObjectLoadingContent.cpp |
modified | |
FeaturePolicydom/base/nsObjectLoadingContent.h |
modified | |
Sequencedom/base/nsObjectLoadingContent.h |
modified | |
HTMLIFrameElementdom/base/nsObjectLoadingContent.h |
modified | |
ifdom/html/HTMLEmbedElement.cpp |
modified | |
ifdom/html/HTMLObjectElement.cpp |
modified |
Files Changed
dom/base/nsObjectLoadingContent.cppdom/base/nsObjectLoadingContent.hdom/html/HTMLEmbedElement.cppdom/html/HTMLObjectElement.cppnetwerk/ipc/DocumentLoadListener.cpp
Patch
diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp
index 866bcb9abcb..98c1272f8a6 100644
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -218,8 +218,6 @@ already_AddRefed<nsIDocShell> nsObjectLoadingContent::SetupDocShell(
return nullptr;
}
- MaybeStoreCrossOriginFeaturePolicy();
-
return docShell.forget();
}
@@ -1554,6 +1552,7 @@ void nsObjectLoadingContent::Destroy() {
void nsObjectLoadingContent::Traverse(nsObjectLoadingContent* tmp,
nsCycleCollectionTraversalCallback& cb) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader);
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy);
}
/* static */
@@ -1562,6 +1561,7 @@ void nsObjectLoadingContent::Unlink(nsObjectLoadingContent* tmp) {
tmp->mFrameLoader->Destroy();
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader);
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mFeaturePolicy);
}
void nsObjectLoadingContent::UnloadObject(bool aResetState) {
@@ -1720,6 +1720,13 @@ nsObjectLoadingContent::UpgradeLoadToDocument(
return NS_ERROR_FAILURE;
}
+ // At this point we know that we have a browsing context, so it's time to make
+ // sure that that browsing context gets the correct container feature policy.
+ // This is needed for `DocumentLoadListener::MaybeTriggerProcessSwitch` to be
+ // able to start loading the document with the correct container feature
+ // policy in the load info.
+ RefreshFeaturePolicy();
+
bc.forget(aBrowsingContext);
return NS_OK;
}
@@ -1818,6 +1825,9 @@ void nsObjectLoadingContent::SubdocumentImageLoadComplete(nsresult aResult) {
void nsObjectLoadingContent::MaybeStoreCrossOriginFeaturePolicy() {
MOZ_DIAGNOSTIC_ASSERT(mFrameLoader);
+ if (!mFrameLoader) {
+ return;
+ }
// If the browsingContext is not ready (because docshell is dead), don't try
// to create one.
@@ -1831,15 +1841,54 @@ void nsObjectLoadingContent::MaybeStoreCrossOriginFeaturePolicy() {
return;
}
- Element* el = AsElement();
+ auto* el = nsGenericHTMLElement::FromNode(AsElement());
if (!el->IsInComposedDoc()) {
return;
}
- FeaturePolicy* featurePolicy = el->OwnerDoc()->FeaturePolicy();
-
- if (ContentChild* cc = ContentChild::GetSingleton(); cc && featurePolicy) {
+ if (ContentChild* cc = ContentChild::GetSingleton()) {
Unused << cc->SendSetContainerFeaturePolicy(
- browsingContext, Some(featurePolicy->ToFeaturePolicyInfo()));
+ browsingContext, Some(mFeaturePolicy->ToFeaturePolicyInfo()));
+ }
+}
+
+/* static */ already_AddRefed<nsIPrincipal>
+nsObjectLoadingContent::GetFeaturePolicyDefaultOrigin(nsINode* aNode) {
+ auto* el = nsGenericHTMLElement::FromNode(aNode);
+ nsCOMPtr<nsIURI> nodeURI;
+ // Different elements keep this in various locations
+ if (el->NodeInfo()->Equals(nsGkAtoms::object)) {
+ el->GetURIAttr(nsGkAtoms::data, nullptr, getter_AddRefs(nodeURI));
+ } else if (el->NodeInfo()->Equals(nsGkAtoms::embed)) {
+ el->GetURIAttr(nsGkAtoms::src, nullptr, getter_AddRefs(nodeURI));
}
+
+ nsCOMPtr<nsIPrincipal> principal;
+ if (nodeURI) {
+ principal = BasePrincipal::CreateContentPrincipal(
+ nodeURI,
+ BasePrincipal::Cast(el->NodePrincipal())->OriginAttributesRef());
+ } else {
+ principal = el->NodePrincipal();
+ }
+
+ return principal.forget();
+}
+
+void nsObjectLoadingContent::RefreshFeaturePolicy() {
+ if (mType != ObjectType::Document) {
+ return;
+ }
+
+ if (!mFeaturePolicy) {
+ mFeaturePolicy = MakeAndAddRef<FeaturePolicy>(AsElement());
+ }
+
+ // The origin can change if 'src' or 'data' attributes change.
+ nsCOMPtr<nsIPrincipal> origin = GetFeaturePolicyDefaultOrigin(AsElement());
+ MOZ_ASSERT(origin);
+ mFeaturePolicy->SetDefaultOrigin(origin);
+
+ mFeaturePolicy->InheritPolicy(AsElement()->OwnerDoc()->FeaturePolicy());
+ MaybeStoreCrossOriginFeaturePolicy();
}
diff --git a/dom/base/nsObjectLoadingContent.h b/dom/base/nsObjectLoadingContent.h
index 51973a8d7c5..f13f8fa3eb5 100644
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -27,6 +27,7 @@ class nsFrameLoader;
namespace mozilla::dom {
struct BindContext;
+class FeaturePolicy;
template <typename T>
class Sequence;
class HTMLIFrameElement;
@@ -213,6 +214,14 @@ class nsObjectLoadingContent : public nsIStreamListener,
*/
bool BlockEmbedOrObjectContentLoading();
+ /**
+ * Updates and stores the container's feature policy in its canonical browsing
+ * context. This gets called whenever the feature policy has changed, which
+ * can happen when this element is upgraded to a container or when the URI of
+ * the element has changed.
+ */
+ void RefreshFeaturePolicy();
+
private:
// Object parameter changes returned by UpdateObjectParameters
enum ParameterUpdateFlags {
@@ -393,6 +402,14 @@ class nsObjectLoadingContent : public nsIStreamListener,
*/
void MaybeStoreCrossOriginFeaturePolicy();
+ /**
+ * Return the value of either `data` or `src`, depending on element type,
+ * parsed as a URL. If URL is invalid or the attribute is missing this returns
+ * the document's origin.
+ */
+ static already_AddRefed<nsIPrincipal> GetFeaturePolicyDefaultOrigin(
+ nsINode* aNode);
+
// The final listener for mChannel (uriloader, pluginstreamlistener, etc.)
nsCOMPtr<nsIStreamListener> mFinalListener;
@@ -464,6 +481,14 @@ class nsObjectLoadingContent : public nsIStreamListener,
// our own frame.
mozilla::Maybe<mozilla::IntrinsicSize> mSubdocumentIntrinsicSize;
mozilla::Maybe<mozilla::AspectRatio> mSubdocumentIntrinsicRatio;
+
+ // This gets created on the first call of `RefreshFeaturePolicy`, and will be
+ // kept after that. Navigations of this element will use this if they're
+ // targetting documents, which is how iframe element works. If it's a
+ // non-document the feature policy isn't used, but it doesn't hurt to keep it
+ // around, and a subsequent document load will continue using it after
+ // refreshing it.
+ RefPtr<mozilla::dom::FeaturePolicy> mFeaturePolicy;
};
#endif
diff --git a/dom/html/HTMLEmbedElement.cpp b/dom/html/HTMLEmbedElement.cpp
index 7cd9fd916c4..c307838b33b 100644
--- a/dom/html/HTMLEmbedElement.cpp
+++ b/dom/html/HTMLEmbedElement.cpp
@@ -79,6 +79,10 @@ void HTMLEmbedElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
}
+ if (aName == nsGkAtoms::src) {
+ RefreshFeaturePolicy();
+ }
+
if (aNamespaceID == kNameSpaceID_None &&
aName == nsGkAtoms::allowfullscreen && mFrameLoader) {
if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) {
diff --git a/dom/html/HTMLObjectElement.cpp b/dom/html/HTMLObjectElement.cpp
index d449e484074..7f7eca1e15d 100644
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -100,6 +100,11 @@ void HTMLObjectElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) {
AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
+
+ if (aName == nsGkAtoms::data) {
+ RefreshFeaturePolicy();
+ }
+
return nsGenericHTMLFormControlElement::AfterSetAttr(
aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
Loading diff…
References
On This Page