Firefox · Graphics
CVE-2026-109730
Logic Error in Graphics
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forgfx/2d/FilterNodeSoftware.cpp |
modified | |
TileTestInputgfx/tests/gtest/TestFilterNodeSoftware.cpp |
modified | |
ifgfx/tests/gtest/TestFilterNodeSoftware.cpp |
modified | |
TileTestNodegfx/tests/gtest/TestFilterNodeSoftware.cpp |
modified | |
forgfx/tests/gtest/TestFilterNodeSoftware.cpp |
modified |
Files Changed
gfx/2d/FilterNodeSoftware.cppgfx/tests/gtest/TestFilterNodeSoftware.cppgfx/tests/gtest/moz.build
Patch
diff --git a/gfx/2d/FilterNodeSoftware.cpp b/gfx/2d/FilterNodeSoftware.cpp
index 730fc34f8f0..38ec454dd6c 100644
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -1633,9 +1633,7 @@ int32_t FilterNodeTileSoftware::InputIndex(uint32_t aInputEnumIndex) {
void FilterNodeTileSoftware::SetAttribute(uint32_t aIndex,
const IntRect& aSourceRect) {
MOZ_ASSERT(aIndex == ATT_TILE_SOURCE_RECT);
- mSourceRect.SetRect(int32_t(aSourceRect.X()), int32_t(aSourceRect.Y()),
- int32_t(aSourceRect.Width()),
- int32_t(aSourceRect.Height()));
+ mSourceRect = aSourceRect;
Invalidate();
}
@@ -1673,14 +1671,24 @@ already_AddRefed<DataSourceSurface> FilterNodeTileSoftware::Render(
InputMap;
InputMap inputs;
+ auto IntRectToInt64Rect = [](const IntRect& aRect) {
+ return RectTyped<UnknownUnits, int64_t>(aRect.X(), aRect.Y(), aRect.Width(),
+ aRect.Height());
+ };
+
IntPoint startIndex = TileIndex(mSourceRect, aRect.TopLeft());
IntPoint endIndex = TileIndex(mSourceRect, aRect.BottomRight());
for (int32_t ix = startIndex.x; ix <= endIndex.x; ix++) {
for (int32_t iy = startIndex.y; iy <= endIndex.y; iy++) {
- IntPoint sourceToDestOffset(ix * mSourceRect.Width(),
- iy * mSourceRect.Height());
- IntRect destRect = aRect.Intersect(mSourceRect + sourceToDestOffset);
- IntRect srcRect = destRect - sourceToDestOffset;
+ auto sourceToDestOffset = PointTyped<UnknownUnits, int64_t>(
+ ix * mSourceRect.Width(), iy * mSourceRect.Height());
+ auto destRect64 = IntRectToInt64Rect(aRect).Intersect(
+ IntRectToInt64Rect(mSourceRect) + sourceToDestOffset);
+ auto srcRect64 = destRect64 - sourceToDestOffset;
+ IntRect destRect, srcRect;
+ if (!destRect64.ToIntRect(&destRect) || !srcRect64.ToIntRect(&srcRect)) {
+ return nullptr;
+ }
if (srcRect.IsEmpty()) {
continue;
}
diff --git a/gfx/tests/gtest/TestFilterNodeSoftware.cpp b/gfx/tests/gtest/TestFilterNodeSoftware.cpp
new file mode 100644
index 00000000000..ce336c43e6c
--- /dev/null
+++ b/gfx/tests/gtest/TestFilterNodeSoftware.cpp
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <vector>
+
+#include "2D.h"
+#include "FilterNodeSoftware.h"
+#include "gtest/gtest.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+
+namespace {
+
+class TileTestInput final : public FilterNodeSoftware {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TileTestInput, override)
+
+ std::vector<IntRect> mRects;
+
+ protected:
+ IntRect GetOutputRectInRect(const IntRect& aRect) override { return aRect; }
+
+ already_AddRefed<DataSourceSurface> GetOutput(const IntRect& aRect) override {
+ return Render(aRect);
+ }
+
+ already_AddRefed<DataSourceSurface> Render(const IntRect& aRect) override {
+ mRects.push_back(aRect);
+ RefPtr<DataSourceSurface> surface =
+ Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::A8, true);
+ if (!surface) {
+ return nullptr;
+ }
+ DataSourceSurface::ScopedMap map(surface, DataSourceSurface::WRITE);
+ if (!map.IsMapped()) {
+ return nullptr;
+ }
+ for (int32_t y = 0; y < aRect.Height(); ++y) {
+ std::memset(map.GetData() + y * map.GetStride(), 0x7f, aRect.Width());
+ }
+ return surface.forget();
+ }
+};
+
+class TileTestNode final : public FilterNodeTileSoftware {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TileTestNode, override)
+ using FilterNodeTileSoftware::Render;
+};
+
+} // namespace
+
+TEST(Moz2D, TileAcrossCoordinateLimits)
+{
+ constexpr int32_t extent = std::numeric_limits<int32_t>::max() - 1;
+ constexpr int32_t last = extent - 6;
+ RefPtr<TileTestInput> input = MakeRefPtr<TileTestInput>();
+ RefPtr<TileTestNode> tile = MakeRefPtr<TileTestNode>();
+ tile->SetInput(IN_TILE_IN, input.get());
+ tile->SetAttribute(ATT_TILE_SOURCE_RECT, IntRect(-4, -4, extent, extent));
+
+ RefPtr<DataSourceSurface> output = tile->Render(IntRect(-6, -6, 4, 4));
+ ASSERT_TRUE(output);
+ const IntRect expected[] = {IntRect(last, last, 2, 2),
+ IntRect(last, -4, 2, 2), IntRect(-4, last, 2, 2),
+ IntRect(-4, -4, 2, 2)};
+ ASSERT_EQ(input->mRects.size(), std::size(expected));
+ for (size_t i = 0; i < std::size(expected); ++i) {
+ EXPECT_EQ(input->mRects[i], expected[i]);
+ }
+
+ DataSourceSurface::ScopedMap map(output, DataSourceSurface::READ);
+ ASSERT_TRUE(map.IsMapped());
+ for (int32_t y = 0; y < 4; ++y) {
+ for (int32_t x = 0; x < 4; ++x) {
+ EXPECT_EQ(map.GetData()[y * map.GetStride() + x], 0x7f);
+ }
+ }
+}
diff --git a/gfx/tests/gtest/moz.build b/gfx/tests/gtest/moz.build
index f5dac2b29b3..458b9eed04f 100644
--- a/gfx/tests/gtest/moz.build
+++ b/gfx/tests/gtest/moz.build
@@ -14,6 +14,7 @@ UNIFIED_SOURCES += [
"TestConvolutionFilter.cpp",
"TestCoord.cpp",
"TestCopyPlane.cpp",
+ "TestFilterNodeSoftware.cpp",
"TestFontFallback.cpp",
"TestFontOverlapPrevention.cpp",
"TestGfxWidgets.cpp",
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/gfx/tests/gtest/TestFilterNodeSoftware.cpp b/gfx/tests/gtest/TestFilterNodeSoftware.cpp
new file mode 100644
index 00000000000..ce336c43e6c
--- /dev/null
+++ b/gfx/tests/gtest/TestFilterNodeSoftware.cpp
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <vector>
+
+#include "2D.h"
+#include "FilterNodeSoftware.h"
+#include "gtest/gtest.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+
+namespace {
+
+class TileTestInput final : public FilterNodeSoftware {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TileTestInput, override)
+
+ std::vector<IntRect> mRects;
+
+ protected:
+ IntRect GetOutputRectInRect(const IntRect& aRect) override { return aRect; }
+
+ already_AddRefed<DataSourceSurface> GetOutput(const IntRect& aRect) override {
+ return Render(aRect);
+ }
+
+ already_AddRefed<DataSourceSurface> Render(const IntRect& aRect) override {
+ mRects.push_back(aRect);
+ RefPtr<DataSourceSurface> surface =
+ Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::A8, true);
+ if (!surface) {
+ return nullptr;
+ }
+ DataSourceSurface::ScopedMap map(surface, DataSourceSurface::WRITE);
+ if (!map.IsMapped()) {
+ return nullptr;
+ }
+ for (int32_t y = 0; y < aRect.Height(); ++y) {
+ std::memset(map.GetData() + y * map.GetStride(), 0x7f, aRect.Width());
+ }
+ return surface.forget();
+ }
+};
+
+class TileTestNode final : public FilterNodeTileSoftware {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TileTestNode, override)
+ using FilterNodeTileSoftware::Render;
+};
+
+} // namespace
+
+TEST(Moz2D, TileAcrossCoordinateLimits)
+{
+ constexpr int32_t extent = std::numeric_limits<int32_t>::max() - 1;
+ constexpr int32_t last = extent - 6;
+ RefPtr<TileTestInput> input = MakeRefPtr<TileTestInput>();
+ RefPtr<TileTestNode> tile = MakeRefPtr<TileTestNode>();
+ tile->SetInput(IN_TILE_IN, input.get());
+ tile->SetAttribute(ATT_TILE_SOURCE_RECT, IntRect(-4, -4, extent, extent));
+
+ RefPtr<DataSourceSurface> output = tile->Render(IntRect(-6, -6, 4, 4));
+ ASSERT_TRUE(output);
+ const IntRect expected[] = {IntRect(last, last, 2, 2),
+ IntRect(last, -4, 2, 2), IntRect(-4, last, 2, 2),
+ IntRect(-4, -4, 2, 2)};
+ ASSERT_EQ(input->mRects.size(), std::size(expected));
+ for (size_t i = 0; i < std::size(expected); ++i) {
+ EXPECT_EQ(input->mRects[i], expected[i]);
+ }
+
+ DataSourceSurface::ScopedMap map(output, DataSourceSurface::READ);
+ ASSERT_TRUE(map.IsMapped());
+ for (int32_t y = 0; y < 4; ++y) {
+ for (int32_t x = 0; x < 4; ++x) {
+ EXPECT_EQ(map.GetData()[y * map.GetStride() + x], 0x7f);
+ }
+ }
+}
diff --git a/gfx/tests/gtest/moz.build b/gfx/tests/gtest/moz.build
index f5dac2b29b3..458b9eed04f 100644
--- a/gfx/tests/gtest/moz.build
+++ b/gfx/tests/gtest/moz.build
@@ -14,6 +14,7 @@ UNIFIED_SOURCES += [
"TestConvolutionFilter.cpp",
"TestCoord.cpp",
"TestCopyPlane.cpp",
+ "TestFilterNodeSoftware.cpp",
"TestFontFallback.cpp",
"TestFontOverlapPrevention.cpp",
"TestGfxWidgets.cpp",
Loading diff…
References
On This Page