Firefox · DOM
CVE-2026-100791
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
dom/base/ContentList.cppdom/base/ContentList.hdom/base/nsContentUtils.h
Patch
diff --git a/dom/base/ContentList.cpp b/dom/base/ContentList.cpp
index 2e64eae77ad..e9898923ec1 100644
--- a/dom/base/ContentList.cpp
+++ b/dom/base/ContentList.cpp
@@ -606,7 +606,8 @@ void ContentList::ContentAppended(nsIContent* aFirstNewContent,
!nsContentUtils::IsInSameAnonymousTree(mRootNode, container) ||
!MayContainRelevantNodes(container) ||
(!aFirstNewContent->HasChildren() &&
- !aFirstNewContent->GetNextSibling() && !MatchSelf(aFirstNewContent))) {
+ !aFirstNewContent->GetNextSibling() &&
+ !MatchSelf<MatchSelfMode::Insertion>(aFirstNewContent))) {
MaybeMarkDirty();
return;
}
@@ -636,7 +637,7 @@ void ContentList::ContentAppended(nsIContent* aFirstNewContent,
// The new stuff is somewhere in the middle of our list; check
// whether we need to invalidate
for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
- if (MatchSelf(cur)) {
+ if (MatchSelf<MatchSelfMode::Insertion>(cur)) {
// Uh-oh. We're gonna have to add elements into the middle
// of our list. That's not worth the effort.
SetDirty();
@@ -690,7 +691,7 @@ void ContentList::ContentInserted(nsIContent* aChild,
if (mState != State::Dirty &&
MayContainRelevantNodes(aChild->GetParentNode()) &&
nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild) &&
- MatchSelf(aChild)) {
+ MatchSelf<MatchSelfMode::Insertion>(aChild)) {
SetDirty();
}
@@ -702,7 +703,7 @@ void ContentList::ContentWillBeRemoved(nsIContent* aChild,
if (mState != State::Dirty &&
MayContainRelevantNodes(aChild->GetParentNode()) &&
nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild) &&
- MatchSelf(aChild)) {
+ MatchSelf<MatchSelfMode::Removal>(aChild)) {
SetDirty();
}
@@ -741,6 +742,7 @@ bool ContentList::Match(Element* aElement) {
: ni->Equals(mXMLMatchAtom, mMatchNameSpaceId);
}
+template <ContentList::MatchSelfMode Mode>
bool ContentList::MatchSelf(nsIContent* aContent) {
MOZ_ASSERT(aContent, "Can't match null stuff, you know");
MOZ_ASSERT(mDeep || aContent->GetParentNode() == mRootNode,
@@ -750,13 +752,26 @@ bool ContentList::MatchSelf(nsIContent* aContent) {
return false;
}
- if (Match(aContent->AsElement())) return true;
+ auto matches = [&](Element* aElement) {
+ if (Match(aElement)) {
+ return true;
+ }
+ if constexpr (Mode == MatchSelfMode::Removal) {
+ return mFunc == nsContentUtils::MatchClassNames &&
+ aElement->IsSVGElement() && aElement->MayHaveClass();
+ }
+ return false;
+ };
+
+ if (matches(aContent->AsElement())) {
+ return true;
+ }
if (!mDeep) return false;
for (nsIContent* cur = aContent->GetFirstChild(); cur;
cur = cur->GetNextNode(aContent)) {
- if (cur->IsElement() && Match(cur->AsElement())) {
+ if (cur->IsElement() && matches(cur->AsElement())) {
return true;
}
}
diff --git a/dom/base/ContentList.h b/dom/base/ContentList.h
index 98dd407adc2..cc409aee8d7 100644
--- a/dom/base/ContentList.h
+++ b/dom/base/ContentList.h
@@ -381,6 +381,15 @@ class ContentList : public HTMLCollection, public nsStubMultiMutationObserver {
* @return whether we match
*/
bool Match(Element* aElement);
+
+ enum class MatchSelfMode : uint8_t {
+ Insertion,
+ // Also accept SVG elements that may have a class. SMIL can change their
+ // class without notification, so they can be in the list without
+ // matching now. Needed when aContent leaves the subtree.
+ Removal,
+ };
+
/**
* See if anything in the subtree rooted at aContent, including
* aContent itself, matches our criterion.
@@ -388,6 +397,7 @@ class ContentList : public HTMLCollection, public nsStubMultiMutationObserver {
* @param aContent the root of the subtree to match against
* @return whether we match something in the tree rooted at aContent
*/
+ template <MatchSelfMode Mode>
bool MatchSelf(nsIContent* aContent);
virtual nsINode* GetNextNode(nsINode* aCurrent);
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index d6635bbeb0e..90c81f9b28f 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2597,6 +2597,9 @@ class nsContentUtils {
static already_AddRefed<mozilla::dom::ContentList> GetElementsByClassName(
nsINode* aRootNode, const nsAString& aClasses);
+ static bool MatchClassNames(mozilla::dom::Element* aElement,
+ int32_t aNamespaceID, nsAtom* aAtom, void* aData);
+
/**
* Returns a presshell for this document, if there is one. This will be
* aDoc's direct presshell if there is one, otherwise we'll look at all
@@ -3769,8 +3772,6 @@ class nsContentUtils {
static void DropFragmentParsers();
- static bool MatchClassNames(mozilla::dom::Element* aElement,
- int32_t aNamespaceID, nsAtom* aAtom, void* aData);
static void DestroyClassNameArray(void* aData);
static void* AllocClassMatchingInfo(nsINode* aRootNode,
const nsString* aClasses);
Loading diff…
References
On This Page