High firefox Memory Corruption 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionInternally found bugs present in Firefox ESR 153.0 and Firefox 153. Some of these bugs showed evidence of memory corruption or another security-relevant defect and we presume that with enough effort some of these could have been exploited.
ComponentGraphics
Bug ClassMemory Corruption
Tracker2045796
Fix commit2500ad5c8ac7 (firefox) +30/-2
CISA KEVNot listed
CreditedGabriele Svelto, Tom Ritter, Tom Schuster and the Mozilla Fuzzing Team
Disclosed2026-08-18

Background

`pixman`
the low-level pixel-manipulation library bundled under gfx/cairo/libpixman that Gecko uses for software rasterization of paths and trapezoids.
`RASTERIZE_EDGES`
the pixman macro/template in pixman-edge-imp.h that walks trapezoid left/right edges scanline-by-scanline and fills spans between them.
`pixman_fixed_t`
pixman’s 16.16 signed fixed-point number type, a 32-bit integer whose maximum representable value is INT32_MAX.
`X_FRAC_FIRST`
a macro producing the sub-pixel rounding offset added to an edge’s x-coordinate so that sample points on the line round north-west.

Root Cause Analysis

In the non-antialiased path of RASTERIZE_EDGES, the left and right edge coordinates lx and rx (both pixman_fixed_t) were adjusted with lx += X_FRAC_FIRST(1) - pixman_fixed_e and the analogous rx +=. Because lx/rx are 32-bit signed values, an edge coordinate near the top of the pixman_fixed_t range makes this addition overflow INT32_MAX, wrapping to a large negative value and violating the invariant that the rounded-up edge stays ordered and within the fixed-point range. The subsequent if (lx < 0) clip and the span computation then operate on a corrupted coordinate, so the fill can span the wrong range of pixels for the scanline.

The fix promotes the operands to int64_t, performs the add in 64-bit, and clamps the result to INT32_MAX with MIN before casting back to pixman_fixed_t, turning the overflowing add into a saturating one. This works because the coordinate can no longer wrap negative, keeping the edge within bounds so the clip and span logic behave correctly.

Key insight
The single mistake was rounding-up trapezoid edge coordinates with a plain 32-bit signed add that could overflow pixman_fixed_t and wrap to a negative value; the fix does the add in int64_t and saturates to INT32_MAX, guaranteeing the rounded edge stays in range and correctly ordered.

Attack Path

  1. Craft an extreme geometry Author web content (canvas, SVG, or CSS) that produces a trapezoid whose left or right edge x-coordinate is driven close to the pixman_fixed_t maximum.
  2. Reach the rasterizer Trigger software rasterization so the trapezoid is passed into RASTERIZE_EDGES for scanline filling.
  3. Overflow the edge add The lx += X_FRAC_FIRST(1) - pixman_fixed_e (or the rx variant) overflows 32 bits and wraps to a negative coordinate.
  4. Corrupt the span The clip and span computation use the wrapped coordinate, driving the fill outside the intended pixel range for the scanline and producing memory corruption in the pixel buffer.

Impact Assessment

An attacker who can render attacker-controlled graphics gains a memory-corruption primitive via out-of-range pixel writes during trapezoid rasterization, within the process that runs pixman rendering (the content/rendering context of the browser). The precondition is that the software (pixman) rasterization path is exercised with a trapezoid whose edge coordinate approaches the pixman_fixed_t limit; per the advisory this is a presumed-exploitable memory-corruption defect rather than a demonstrated exploit.

Files Changed

  • gfx/cairo/README
  • gfx/cairo/libpixman/src/pixman-edge-imp.h
  • gfx/cairo/pixman-edge-saturate.patch

Audit Directions

  • 32-bit fixed-point arithmetic
    Search pixman and cairo for pixman_fixed_t additions/subtractions that combine a coordinate with a rounding or fractional offset without range checks; they can overflow when inputs approach INT32_MAX.
  • Saturate-vs-wrap on geometry
    Audit rasterization inner loops (edge stepping, span clipping) for places where a computed coordinate is used before an ordering/bounds invariant is re-established, and confirm overflow is handled by widening or clamping.
  • Attacker-influenced extreme coordinates
    Trace how web-exposed graphics APIs (canvas, SVG, CSS transforms) can push path/trapezoid coordinates to fixed-point extremes and verify each downstream conversion to pixman_fixed_t is range-safe.
diff --git a/gfx/cairo/README b/gfx/cairo/README
index 0f733eebee9..16fba512702 100644
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -43,3 +43,5 @@ pixman-interp.patch: use lower quality interpolation by default on mobile
 pixman-rename.patch: include pixman-rename.h for renaming of external symbols
 
 pixman-translation-round-in-wide.patch: Round translation distances in 48/16 fixpoint.
+
+pixman-edge-saturate.patch: Saturate when rounding up trapezoid edges
diff --git a/gfx/cairo/libpixman/src/pixman-edge-imp.h b/gfx/cairo/libpixman/src/pixman-edge-imp.h
index a4698eddb28..39e8d71d256 100644
--- a/gfx/cairo/libpixman/src/pixman-edge-imp.h
+++ b/gfx/cairo/libpixman/src/pixman-edge-imp.h
@@ -53,10 +53,13 @@ RASTERIZE_EDGES (pixman_image_t  *image,
 	 * when the sample point lies exactly on the line, we round towards
 	 * north-west.
 	 *
+	 * Use 64 bits to get a saturating add, in case lx or rx are near
+	 * the limits of pixman_fixed_t.
+	 *
 	 * (The AA case does a similar  adjustment in RENDER_SAMPLES_X)
 	 */
-	lx += X_FRAC_FIRST(1) - pixman_fixed_e;
-	rx += X_FRAC_FIRST(1) - pixman_fixed_e;
+	lx = (pixman_fixed_t) MIN ((int64_t) lx + (X_FRAC_FIRST(1) - pixman_fixed_e), INT32_MAX);
+	rx = (pixman_fixed_t) MIN ((int64_t) rx + (X_FRAC_FIRST(1) - pixman_fixed_e), INT32_MAX);
 #endif
 	/* clip X */
 	if (lx < 0)
diff --git a/gfx/cairo/pixman-edge-saturate.patch b/gfx/cairo/pixman-edge-saturate.patch
new file mode 100644
index 00000000000..bb6fe0afa67
--- /dev/null
+++ b/gfx/cairo/pixman-edge-saturate.patch
@@ -0,0 +1,23 @@
+From: Jim Blandy <jimb@mozilla.com>
+Subject: Saturate when rounding up trapezoid edges
+
+diff --git a/gfx/cairo/libpixman/src/pixman-edge-imp.h b/gfx/cairo/libpixman/src/pixman-edge-imp.h
+index a4698eddb281..39e8d71d2568 100644
+--- a/gfx/cairo/libpixman/src/pixman-edge-imp.h
++++ b/gfx/cairo/libpixman/src/pixman-edge-imp.h
+@@ -53,10 +53,13 @@ RASTERIZE_EDGES (pixman_image_t  *image,
+ 	 * when the sample point lies exactly on the line, we round towards
+ 	 * north-west.
+ 	 *
++	 * Use 64 bits to get a saturating add, in case lx or rx are near
++	 * the limits of pixman_fixed_t.
++	 *
+ 	 * (The AA case does a similar  adjustment in RENDER_SAMPLES_X)
+ 	 */
+-	lx += X_FRAC_FIRST(1) - pixman_fixed_e;
+-	rx += X_FRAC_FIRST(1) - pixman_fixed_e;
++	lx = (pixman_fixed_t) MIN ((int64_t) lx + (X_FRAC_FIRST(1) - pixman_fixed_e), INT32_MAX);
++	rx = (pixman_fixed_t) MIN ((int64_t) rx + (X_FRAC_FIRST(1) - pixman_fixed_e), INT32_MAX);
+ #endif
+ 	/* clip X */
+ 	if (lx < 0)
Loading diff…