Firefox · DOM
CVE-2026-100789
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
explicitLangdom/canvas/CanvasRenderingContext2D.cpp |
modified | |
ifdom/canvas/CanvasRenderingContext2D.cpp |
modified | |
fordom/canvas/CanvasRenderingContext2D.cpp |
modified | |
mActivelayout/svg/SVGObserverUtils.cpp |
modified | |
iflayout/svg/SVGObserverUtils.cpp |
modified |
Files Changed
dom/canvas/CanvasRenderingContext2D.cppdom/canvas/CanvasRenderingContext2D.hlayout/svg/SVGObserverUtils.cpplayout/svg/SVGObserverUtils.h
Patch
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index 25f10fb25d4..a20003c9110 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1036,12 +1036,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CanvasRenderingContext2D)
/*
* XXXjwatt: I don't think this is doing anything useful. All we do under
* this function is clear a raw C-style (i.e. not strong) pointer. That's
- * clearly not helping in breaking any cycles. The fact that we MOZ_CRASH
- * in OnRenderingChange if that pointer is null indicates that this isn't
- * even doing anything useful in terms of preventing further invalidation
- * from any observed filters.
+ * clearly not helping in breaking any cycles.
*/
- autoSVGFiltersObserver->Detach();
+ autoSVGFiltersObserver->SetIsActive(false);
}
ImplCycleCollectionUnlink(state.autoSVGFiltersObserver);
}
@@ -1131,12 +1128,21 @@ CanvasRenderingContext2D::ContextState::ContextState(const ContextState& aOther)
lineJoin(aOther.lineJoin),
filterString(aOther.filterString),
filterChain(aOther.filterChain),
- autoSVGFiltersObserver(aOther.autoSVGFiltersObserver),
filter(aOther.filter),
filterAdditionalImages(aOther.filterAdditionalImages.Clone()),
filterSourceGraphicTainted(aOther.filterSourceGraphicTainted),
imageSmoothingEnabled(aOther.imageSmoothingEnabled),
- explicitLang(aOther.explicitLang) {}
+ explicitLang(aOther.explicitLang) {
+ if (aOther.autoSVGFiltersObserver) {
+ autoSVGFiltersObserver = aOther.autoSVGFiltersObserver->Clone();
+ }
+}
+
+CanvasRenderingContext2D::ContextState::~ContextState() {
+ if (autoSVGFiltersObserver.get()) {
+ autoSVGFiltersObserver->SetIsActive(false);
+ }
+}
void CanvasRenderingContext2D::ContextState::SetColorStyle(Style aWhichStyle,
nscolor aColor) {
@@ -1234,12 +1240,6 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D() {
RemoveShutdownObserver();
ResetBitmap();
- for (ContextState& state : mStyleStack) {
- if (auto* obs = state.autoSVGFiltersObserver.get()) {
- obs->Detach();
- }
- }
-
sNumLivingContexts.set(sNumLivingContexts.get() - 1);
if (sNumLivingContexts.get() == 0 && sErrorTarget.get()) {
RefPtr<DrawTarget> target = dont_AddRef(sErrorTarget.get());
@@ -2389,9 +2389,13 @@ void CanvasRenderingContext2D::Save() {
SetErrorState();
return;
}
- mStyleStack[mStyleStack.Length() - 1].transform = GetCurrentTransform();
+ CurrentState().transform = GetCurrentTransform();
mStyleStack.SetCapacity(mStyleStack.Length() + 1);
mStyleStack.AppendElement(CurrentState());
+ if (auto* autoSVGFiltersObserver =
+ PreviousState().autoSVGFiltersObserver.get()) {
+ autoSVGFiltersObserver->SetIsActive(false);
+ }
if (mStyleStack.Length() > MAX_STYLE_STACK_SIZE) {
// This is not fast, but is better than OOMing and shouldn't be hit by
@@ -2417,6 +2421,10 @@ void CanvasRenderingContext2D::Restore() {
}
mStyleStack.RemoveLastElement();
+ if (auto* autoSVGFiltersObserver =
+ CurrentState().autoSVGFiltersObserver.get()) {
+ autoSVGFiltersObserver->SetIsActive(true);
+ }
mPathTransformDirty = true;
}
@@ -2985,7 +2993,7 @@ void CanvasRenderingContext2D::SetFilter(const nsACString& aFilter,
CurrentState().filterChain = std::move(filterChain);
if (mCanvasElement) {
if (CurrentState().autoSVGFiltersObserver) {
- CurrentState().autoSVGFiltersObserver->Detach();
+ CurrentState().autoSVGFiltersObserver->SetIsActive(false);
}
CurrentState().autoSVGFiltersObserver =
SVGObserverUtils::ObserveFiltersForCanvasContext(
diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h
index a73b7a35314..44260173ac9 100644
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -1083,7 +1083,7 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
ContextState() = default;
ContextState(const ContextState& aOther);
- ~ContextState() = default;
+ ~ContextState();
void SetColorStyle(Style aWhichStyle, nscolor aColor);
void SetPatternStyle(Style aWhichStyle, CanvasPattern* aPat);
@@ -1181,12 +1181,10 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
AutoTArray<ContextState, 3> mStyleStack;
- inline ContextState& CurrentState() {
- return mStyleStack[mStyleStack.Length() - 1];
- }
+ inline ContextState& CurrentState() { return mStyleStack.LastElement(); }
inline const ContextState& CurrentState() const {
- return mStyleStack[mStyleStack.Length() - 1];
+ return mStyleStack.LastElement();
}
inline const ContextState& PreviousState() const {
diff --git a/layout/svg/SVGObserverUtils.cpp b/layout/svg/SVGObserverUtils.cpp
index cab63a80839..190f5fc50e2 100644
--- a/layout/svg/SVGObserverUtils.cpp
+++ b/layout/svg/SVGObserverUtils.cpp
@@ -912,6 +912,8 @@ class SVGFilterObserverList : public ISVGFilterObserverList {
virtual void OnRenderingChange(Element* aObservingElement) = 0;
protected:
+ SVGFilterObserverList(const SVGFilterObserverList& aOther)
+ : mObservers(aOther.mObservers.Clone()) {}
virtual ~SVGFilterObserverList();
void DetachObservers() {
@@ -985,7 +987,14 @@ class SVGFilterObserverListForCSSProp final : public SVGFilterObserverList {
GetFrameContentAsElement(aFilteredFrame),
aFilteredFrame) {}
+ ISVGFilterObserverList* Clone() const override {
+ return new SVGFilterObserverListForCSSProp(*this);
+ }
+
protected:
+ SVGFilterObserverListForCSSProp(const SVGFilterObserverListForCSSProp& aOther)
+ : SVGFilterObserverList(aOther) {}
+
void OnRenderingChange(Element* aObservingElement) override;
};
@@ -1023,18 +1032,25 @@ class SVGFilterObserverListForCanvasContext final
: SVGFilterObserverList(aFilters, aCanvasElement), mContext(aContext) {}
void OnRenderingChange(Element* aObservingElement) override;
- void Detach() override { mContext = nullptr; }
+ void SetIsActive(bool aActive) override { mActive = aActive; }
+ ISVGFilterObserverList* Clone() const override {
+ return new SVGFilterObserverListForCanvasContext(*this);
+ }
private:
+ SVGFilterObserverListForCanvasContext(
+ const SVGFilterObserverListForCanvasContext& aOther)
+ : SVGFilterObserverList(aOther),
+ mContext(aOther.mContext),
+ mActive(aOther.mActive) {}
+
CanvasRenderingContext2D* mContext;
+ bool mActive = true;
};
void SVGFilterObserverListForCanvasContext::OnRenderingChange(
Element* aObservingElement) {
- if (!mContext) {
- NS_WARNING(
- "GFX: This should never be called without a context, except during "
- "cycle collection (when Detach has been called)");
+ if (!mActive) {
return;
}
// Refresh the cached FilterDescription in mContext->CurrentState().filter.
diff --git a/layout/svg/SVGObserverUtils.h b/layout/svg/SVGObserverUtils.h
index 9690998eba4..36e8fb6e0b1 100644
--- a/layout/svg/SVGObserverUtils.h
+++ b/layout/svg/SVGObserverUtils.h
@@ -54,7 +54,8 @@ class ISVGFilterObserverList : public nsISupports {
NS_DECL_CYCLE_COLLECTION_CLASS(ISVGFilterObserverList)
virtual const nsTArray<RefPtr<SVGFilterObserver>>& GetObservers() const = 0;
- virtual void Detach() {}
+ virtual void SetIsActive(bool aActive) {}
+ virtual ISVGFilterObserverList* Clone() const = 0;
protected:
virtual ~ISVGFilterObserverList() = default;
Loading diff…
References
On This Page