Firefox · Graphics
CVE-2026-4685
Logic Error in Graphics
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
mPreserveAlphagfx/2d/FilterNodeSoftware.cpp |
modified | |
switchgfx/2d/FilterNodeSoftware.cpp |
modified |
Files Changed
gfx/2d/FilterNodeSoftware.cppgfx/2d/FilterNodeSoftware.hgfx/2d/Rect.h
Patch
diff --git a/gfx/2d/FilterNodeSoftware.cpp b/gfx/2d/FilterNodeSoftware.cpp
index 11f53d3a765..0130e7853b1 100644
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -2178,6 +2178,7 @@ FilterNodeConvolveMatrixSoftware::FilterNodeConvolveMatrixSoftware()
: mDivisor(0),
mBias(0),
mEdgeMode(EDGE_MODE_DUPLICATE),
+ mKernelUnitLength(1.0f, 1.0f),
mPreserveAlpha(false) {}
int32_t FilterNodeConvolveMatrixSoftware::InputIndex(uint32_t aInputEnumIndex) {
@@ -2223,7 +2224,21 @@ void FilterNodeConvolveMatrixSoftware::SetAttribute(
uint32_t aIndex, const Size& aKernelUnitLength) {
switch (aIndex) {
case ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH:
+ // Spec for feConvolveMatrix:
+ // If the attribute (kernelUnitLength) is not specified, the default value
+ // is one pixel in the offscreen bitmap. If a negative or zero value is
+ // specified the default value will be used instead. The first number is
+ // the x value. The second number is the y value. If the value is not
+ // specified, it defaults to the same value as x.
mKernelUnitLength = aKernelUnitLength;
+ if (mKernelUnitLength.width <= 0.0f ||
+ !std::isfinite(mKernelUnitLength.width)) {
+ mKernelUnitLength.width = 1.0f;
+ }
+ if (mKernelUnitLength.height <= 0.0f ||
+ !std::isfinite(mKernelUnitLength.height)) {
+ mKernelUnitLength.height = mKernelUnitLength.width;
+ }
break;
default:
MOZ_CRASH("GFX: FilterNodeConvolveMatrixSoftware::SetAttribute");
@@ -2433,11 +2448,15 @@ already_AddRefed<DataSourceSurface> FilterNodeConvolveMatrixSoftware::DoRender(
SurfaceFormat::B8G8R8A8, true);
}
- IntRect srcRect = InflatedSourceRect(aRect);
-
+ RectDouble srcRectD(aRect);
+ srcRectD.Inflate(GetInflateSourceMargin());
// Inflate the source rect by another pixel because the bilinear filtering in
// ColorComponentAtPoint may want to access the margins.
- srcRect.Inflate(1);
+ srcRectD.Inflate(1);
+ if (!RectIsInt32Safe(srcRectD)) {
+ return nullptr;
+ }
+ IntRect srcRect = TruncatedToInt(srcRectD);
RefPtr<DataSourceSurface> input =
GetInputDataSourceSurface(IN_CONVOLVE_MATRIX_IN, srcRect,
@@ -2516,23 +2535,26 @@ IntRect FilterNodeConvolveMatrixSoftware::MapRectToSource(
aMax, aSourceNode);
}
+MarginDouble FilterNodeConvolveMatrixSoftware::GetInflateSourceMargin() const {
+ double kulX = double(mKernelUnitLength.width);
+ double kulY = double(mKernelUnitLength.height);
+ MarginDouble margin;
+ margin.left = ceil(mTarget.x * kulX);
+ margin.top = ceil(mTarget.y * kulY);
+ margin.right = ceil((mKernelSize.width - mTarget.x - 1) * kulX);
+ margin.bottom = ceil((mKernelSize.height - mTarget.y - 1) * kulY);
+ return margin;
+}
+
IntRect FilterNodeConvolveMatrixSoftware::InflatedSourceRect(
const IntRect& aDestRect) {
if (aDestRect.IsEmpty()) {
return IntRect();
}
- IntMargin margin;
- margin.left = static_cast<int32_t>(ceil(mTarget.x * mKernelUnitLength.width));
- margin.top = static_cast<int32_t>(ceil(mTarget.y * mKernelUnitLength.height));
- margin.right = static_cast<int32_t>(
- ceil((mKernelSize.width - mTarget.x - 1) * mKernelUnitLength.width));
- margin.bottom = static_cast<int32_t>(
- ceil((mKernelSize.height - mTarget.y - 1) * mKernelUnitLength.height));
-
- IntRect srcRect = aDestRect;
- srcRect.Inflate(margin);
- return srcRect;
+ RectDouble srcRect(aDestRect);
+ srcRect.Inflate(GetInflateSourceMargin());
+ return RectIsInt32Safe(srcRect) ? TruncatedToInt(srcRect) : aDestRect;
}
IntRect FilterNodeConvolveMatrixSoftware::InflatedDestRect(
@@ -2541,19 +2563,12 @@ IntRect FilterNodeConvolveMatrixSoftware::InflatedDestRect(
return IntRect();
}
- IntMargin margin;
- margin.left = static_cast<int32_t>(
- ceil((mKernelSize.width - mTarget.x - 1) * mKernelUnitLength.width));
- margin.top = static_cast<int32_t>(
- ceil((mKernelSize.height - mTarget.y - 1) * mKernelUnitLength.height));
- margin.right =
- static_cast<int32_t>(ceil(mTarget.x * mKernelUnitLength.width));
- margin.bottom =
- static_cast<int32_t>(ceil(mTarget.y * mKernelUnitLength.height));
-
- IntRect destRect = aSourceRect;
+ RectDouble destRect(aSourceRect);
+ MarginDouble margin = GetInflateSourceMargin();
+ std::swap(margin.left, margin.right);
+ std::swap(margin.top, margin.bottom);
destRect.Inflate(margin);
- return destRect;
+ return RectIsInt32Safe(destRect) ? TruncatedToInt(destRect) : aSourceRect;
}
IntRect FilterNodeConvolveMatrixSoftware::GetOutputRectInRect(
diff --git a/gfx/2d/FilterNodeSoftware.h b/gfx/2d/FilterNodeSoftware.h
index 5dcc0a8c524..280320bd148 100644
--- a/gfx/2d/FilterNodeSoftware.h
+++ b/gfx/2d/FilterNodeSoftware.h
@@ -502,6 +502,7 @@ class FilterNodeConvolveMatrixSoftware : public FilterNodeSoftware {
CoordType aKernelUnitLengthX,
CoordType aKernelUnitLengthY);
+ MarginDouble GetInflateSourceMargin() const;
IntRect InflatedSourceRect(const IntRect& aDestRect);
IntRect InflatedDestRect(const IntRect& aSourceRect);
diff --git a/gfx/2d/Rect.h b/gfx/2d/Rect.h
index e272c5570b9..f9e0f7fe4ec 100644
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -174,6 +174,11 @@ struct MOZ_EMPTY_BASES IntRectTyped
aRect.Height());
}
+ static IntRectTyped<Units> Truncate(const RectTyped<Units, double>& aRect) {
+ return IntRectTyped(int32_t(aRect.X()), int32_t(aRect.Y()),
+ int32_t(aRect.Width()), int32_t(aRect.Height()));
+ }
+
// Rounding isn't meaningful on an integer rectangle.
void Round() {}
void RoundIn() {}
@@ -343,10 +348,10 @@ IntRectTyped<Units> RoundedToInt(const RectTyped<Units>& aRect) {
int32_t(copy.Width()), int32_t(copy.Height()));
}
-template <class Units>
-bool RectIsInt32Safe(const RectTyped<Units>& aRect) {
- float min = (float)std::numeric_limits<std::int32_t>::min();
- float max = (float)std::numeric_limits<std::int32_t>::max();
+template <class Units, class F>
+bool RectIsInt32Safe(const RectTyped<Units, F>& aRect) {
+ F min = (F)std::numeric_limits<int32_t>::min();
+ F max = (F)std::numeric_limits<int32_t>::max();
return aRect.x > min && aRect.y > min && aRect.width < max &&
aRect.height < max && aRect.XMost() < max && aRect.YMost() < max;
}
@@ -361,8 +366,8 @@ IntRectTyped<Units> RoundedOut(const RectTyped<Units>& aRect) {
return IntRectTyped<Units>::RoundOut(aRect);
}
-template <class Units>
-IntRectTyped<Units> TruncatedToInt(const RectTyped<Units>& aRect) {
+template <class Units, class F>
+IntRectTyped<Units> TruncatedToInt(const RectTyped<Units, F>& aRect) {
return IntRectTyped<Units>::Truncate(aRect);
}
Loading diff…
References
On This Page