Hello,

On Sun, 12 Jul 2026 17:30:32 +0200 Andrej Shadura <[email protected]> wrote:
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected], Timo Aaltonen <[email protected]>
Control: affects -1 + src:libxfont
User: [email protected]
Usertags: pu

[ Reason ]
This upload fixes three recent CVEs, see https://bugs.debian.org/1141702
for more context. We’re fixing these in bookworm and bullseye as part of
the Debian LTS project.

[ Impact ]
Users of trixie would be impacted by these security issues. Users
upgrading from LTS would find themselves facing them again.

[ Tests ]
No automated tests. Only build testing was done.
(What automated or manual tests cover the affected code?)

[ Risks ]
(Discussion of the risks involved. E.g. code is trivial or
complex, alternatives available.)

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
The changes are only clean cherry-picks of the upstream commits.

As it happens, I didn’t attach the debdiff initially.

--
Cheers,
  Andrej
diff --git a/debian/changelog b/debian/changelog
index 60002827f386..274f848559f5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+libxfont (1:2.0.6-2+deb13u1) trixie; urgency=medium
+
+  * Add upstream patches for security issues:
+    - CVE-2026-56001: integer overflow in BitmapScaleBitmaps bytestoalloc
+    - CVE-2026-56002: validate bitmap sizes and offsets in pcfread
+    - CVE-2026-56003: bounds check to computeProps for property buffer
+
+ -- Andrej Shadura <[email protected]>  Sun, 12 Jul 2026 16:45:15 +0200
+
 libxfont (1:2.0.6-2) unstable; urgency=medium
 
   * Team upload
diff --git a/debian/patches/CVE-2026-56001.patch 
b/debian/patches/CVE-2026-56001.patch
new file mode 100644
index 000000000000..6a2df72474de
--- /dev/null
+++ b/debian/patches/CVE-2026-56001.patch
@@ -0,0 +1,68 @@
+From: Peter Hutterer <[email protected]>
+Date: Mon, 1 Jun 2026 16:46:10 +1000
+Subject: bitscale: fix integer overflow in BitmapScaleBitmaps bytestoalloc
+
+bytestoalloc is declared as unsigned int (32-bit). When the sum of
+per-glyph byte counts exceeds 2^32, the value wraps around and calloc()
+allocates a buffer that is too small. The subsequent ScaleBitmap loop
+then writes past the end of the allocated buffer.
+
+Change bytestoalloc from unsigned int to size_t to match the actual
+allocation size type, and add an explicit overflow check in the
+accumulation loop to bail out if the total would exceed SIZE_MAX.
+
+This vulnerability was discovered by:
+Anonymous working with TrendAI Zero Day Initiative
+
+CVE-2026-56001/ZDI-CAN-30558
+
+Assisted-by: Claude:claude-opus-4-6
+Signed-off-by: Peter Hutterer <[email protected]>
+Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxfont/-/merge_requests/34>
+
+Origin: upstream, 
https://gitlab.freedesktop.org/xorg/lib/libxfont/-/commit/be0b08e2d354138d3222b4490e2a77c6ee42f778
+---
+ src/bitmap/bitscale.c | 23 ++++++++++++++++++++---
+ 1 file changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/src/bitmap/bitscale.c b/src/bitmap/bitscale.c
+index e29ba96..7100138 100644
+--- a/src/bitmap/bitscale.c
++++ b/src/bitmap/bitscale.c
+@@ -1460,7 +1460,7 @@ BitmapScaleBitmaps(FontPtr pf,          /* scaled font */
+               opci;
+     FontInfoPtr pfi;
+     int         glyph;
+-    unsigned    bytestoalloc = 0;
++    size_t      bytestoalloc = 0;
+     int               firstCol, lastCol, firstRow, lastRow;
+ 
+     double    xform[4], inv_xform[4];
+@@ -1487,8 +1487,25 @@ BitmapScaleBitmaps(FontPtr pf,          /* scaled font 
*/
+     glyph = pf->glyph;
+     for (i = 0; i < nchars; i++)
+     {
+-      if ((pci = ACCESSENCODING(bitmapFont->encoding, i)))
+-          bytestoalloc += BYTES_FOR_GLYPH(pci, glyph);
++      if ((pci = ACCESSENCODING(bitmapFont->encoding, i))) {
++          size_t glyphsize = BYTES_FOR_GLYPH(pci, glyph);
++          if (bytestoalloc > SIZE_MAX - glyphsize) {
++              fprintf(stderr,
++                      "Error: bitmap allocation overflow for scaled font\n");
++              goto bail;
++          }
++          bytestoalloc += glyphsize;
++      }
++    }
++
++    /* Reject unreasonably large bitmap allocations that could result
++     * from malicious fonts with extreme scale factors.  256 MiB is
++     * far beyond any legitimate scaled bitmap font. */
++#define BITMAP_SCALE_MAX_ALLOC        (256 * 1024 * 1024)
++    if (bytestoalloc > BITMAP_SCALE_MAX_ALLOC) {
++      fprintf(stderr,
++              "Error: scaled bitmap size %zu exceeds limit\n", bytestoalloc);
++      goto bail;
+     }
+ 
+     /* Do we add the font malloc stuff for VALUE ADDED ? */
diff --git a/debian/patches/CVE-2026-56002.patch 
b/debian/patches/CVE-2026-56002.patch
new file mode 100644
index 000000000000..d3bd18042d25
--- /dev/null
+++ b/debian/patches/CVE-2026-56002.patch
@@ -0,0 +1,131 @@
+From: Peter Hutterer <[email protected]>
+Date: Mon, 1 Jun 2026 16:48:40 +1000
+Subject: pcfread: validate bitmap sizes and offsets against per-glyph metrics
+
+pcfReadFont() uses bitmapSizes[] read directly from the PCF file to
+allocate the repadded bitmap buffer. However, per-glyph metrics (also
+from the file) control how much data RepadBitmap() writes. A malicious
+PCF font can declare a small bitmapSizes[] value while having per-glyph
+metrics that require more space, causing a heap buffer overflow.
+
+A similar issue happens with the encoding offsets: pcfReadFont reads
+encoding offsets from the PCF file and uses them to index into the
+metrics array without bounds checking.  A crafted font can set an
+encoding offset larger than nmetrics, causing an out-of-bounds pointer
+that is later dereferenced when glyphs are accessed through the encoding
+table.
+
+And the no-repad bitmap path (when PCF_GLYPH_PAD matches the requested
+glyph pad) only validated that each glyph's offset was within the bitmap
+buffer, but did not check that the full glyph extent (offset +
+BYTES_PER_ROW * height) fits within the buffer.  A crafted font with a
+glyph offset near the end of a small bitmap buffer but large glyph
+metrics causes a heap buffer over-read when the glyph is later rendered.
+
+This vulnerability was discovered by:
+  Anonymous working with TrendAI Zero Day Initiative
+
+CVE-2026-56002/ZDI-CAN-30559
+
+Assisted-by: Claude:claude-opus-4-6
+Signed-off-by: Peter Hutterer <[email protected]>
+Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxfont/-/merge_requests/34>
+
+Origin: upstream, 
https://gitlab.freedesktop.org/xorg/lib/libxfont/-/commit/b4389e0b1d84a690b819bb27b1439968811a3674
+---
+ src/bitmap/pcfread.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 56 insertions(+), 3 deletions(-)
+
+diff --git a/src/bitmap/pcfread.c b/src/bitmap/pcfread.c
+index 882318b..bcb82b8 100644
+--- a/src/bitmap/pcfread.c
++++ b/src/bitmap/pcfread.c
+@@ -531,25 +531,74 @@ pcfReadFont(FontPtr pFont, FontFilePtr file,
+       int         old,
+                   new;
+       xCharInfo  *metric;
++      int         srcPad = PCF_GLYPH_PAD(format);
+ 
+-      sizepadbitmaps = bitmapSizes[PCF_SIZE_TO_INDEX(glyph)];
+-      padbitmaps = malloc(sizepadbitmaps);
++      /* Compute the actual required size from per-glyph metrics instead
++       * of trusting the file's bitmapSizes[] value, which may be smaller
++       * than the actual data written by RepadBitmap. */
++      sizepadbitmaps = 0;
++      for (i = 0; i < nbitmaps; i++) {
++          int w, h, glyphBytes;
++          metric = &metrics[i].metrics;
++          w = metric->rightSideBearing - metric->leftSideBearing;
++          h = metric->ascent + metric->descent;
++          glyphBytes = BYTES_PER_ROW(w, glyph) * h;
++          if (glyphBytes < 0 || (glyphBytes > 0 && sizepadbitmaps > INT_MAX - 
glyphBytes)) {
++              pcfError("pcfReadFont(): bitmap size overflow\n");
++              goto Bail;
++          }
++          sizepadbitmaps += glyphBytes;
++      }
++      padbitmaps = malloc(sizepadbitmaps ? sizepadbitmaps : 1);
+       if (!padbitmaps) {
+           pcfError("pcfReadFont(): Couldn't allocate padbitmaps (%d)\n", 
sizepadbitmaps);
+           goto Bail;
+       }
+       new = 0;
+       for (i = 0; i < nbitmaps; i++) {
++          int srcGlyphBytes;
++
+           old = offsets[i];
+           metric = &metrics[i].metrics;
++
++          /* Validate source offset and source glyph size against the
++           * source bitmap buffer to prevent out-of-bounds reads. */
++          srcGlyphBytes = BYTES_PER_ROW(
++              metric->rightSideBearing - metric->leftSideBearing,
++              srcPad) * (metric->ascent + metric->descent);
++          if (old < 0 || old > sizebitmaps ||
++              srcGlyphBytes < 0 || srcGlyphBytes > sizebitmaps - old) {
++              pcfError("pcfReadFont(): bitmap offset/size out of bounds\n");
++              free(padbitmaps);
++              goto Bail;
++          }
++
+           offsets[i] = new;
+           new += RepadBitmap(bitmaps + old, padbitmaps + new,
+-                             PCF_GLYPH_PAD(format), glyph,
++                             srcPad, glyph,
+                         metric->rightSideBearing - metric->leftSideBearing,
+                              metric->ascent + metric->descent);
+       }
+       free(bitmaps);
+       bitmaps = padbitmaps;
++    } else {
++      /* Validate offsets and full glyph extents against bitmap buffer */
++      for (i = 0; i < nbitmaps; i++) {
++          int glyphBytes;
++          xCharInfo *metric = &metrics[i].metrics;
++
++          glyphBytes = BYTES_PER_ROW(
++              metric->rightSideBearing - metric->leftSideBearing,
++              glyph) * (metric->ascent + metric->descent);
++          if (offsets[i] >= (CARD32)sizebitmaps ||
++              glyphBytes < 0 ||
++              glyphBytes > sizebitmaps - (int)offsets[i]) {
++              pcfError("pcfReadFont(): bitmap offset/size out of bounds "
++                       "(offset %u, size %d, total %d)\n",
++                       offsets[i], glyphBytes, sizebitmaps);
++              goto Bail;
++          }
++      }
+     }
+     for (i = 0; i < nbitmaps; i++)
+       metrics[i].bits = bitmaps + offsets[i];
+@@ -624,6 +673,10 @@ pcfReadFont(FontPtr pFont, FontFilePtr file,
+       if (IS_EOF(file)) goto Bail;
+       if (encodingOffset == 0xFFFF) {
+           pFont->info.allExist = FALSE;
++      } else if (encodingOffset >= nmetrics) {
++          pcfError("pcfReadFont(): encoding offset %d out of range 
(nmetrics=%d)\n",
++                   encodingOffset, nmetrics);
++          goto Bail;
+       } else {
+             if(!encoding[SEGMENT_MAJOR(i)]) {
+                 encoding[SEGMENT_MAJOR(i)]=
diff --git a/debian/patches/CVE-2026-56003.patch 
b/debian/patches/CVE-2026-56003.patch
new file mode 100644
index 000000000000..6bd5f07b0848
--- /dev/null
+++ b/debian/patches/CVE-2026-56003.patch
@@ -0,0 +1,107 @@
+From: Peter Hutterer <[email protected]>
+Date: Mon, 1 Jun 2026 16:49:55 +1000
+Subject: bitscale: add bounds check to computeProps for property buffer
+
+ComputeScaledProperties allocates a fixed-size property buffer of 70
+slots. computeProps iterates the source font's properties and writes 1
+slot for unscaled properties or 2 slots for scaledX/scaledY properties,
+with no bounds check. A malicious font with many duplicate properties
+matching fontPropTable entries can overflow the allocated buffer.
+
+Fix this by passing the remaining buffer capacity to computeProps and
+checking it before each write. Properties that would exceed the buffer
+are silently skipped.
+
+The function is also restructured to handle the buffer writes for
+scaledX/scaledY inside the switch cases directly, rather than in a
+separate block after the switch. This makes the control flow clearer and
+ensures the bounds check covers all writes.
+
+This vulnerability was discovered by:
+Anonymous working with TrendAI Zero Day Initiative
+
+CVE-2026-56003/ZDI-CAN-30560
+
+Assisted-by: Claude:claude-opus-4-6
+Signed-off-by: Peter Hutterer <[email protected]>
+Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxfont/-/merge_requests/34>
+
+Origin: upstream, 
https://gitlab.freedesktop.org/xorg/lib/libxfont/-/commit/dff957a5158da038a282a59a31fe736702732939
+---
+ src/bitmap/bitscale.c | 41 +++++++++++++++++++++--------------------
+ 1 file changed, 21 insertions(+), 20 deletions(-)
+
+diff --git a/src/bitmap/bitscale.c b/src/bitmap/bitscale.c
+index 7100138..1fd15be 100644
+--- a/src/bitmap/bitscale.c
++++ b/src/bitmap/bitscale.c
+@@ -511,7 +511,8 @@ static int
+ computeProps(FontPropPtr pf, char *wasStringProp,
+            FontPropPtr npf, char *isStringProp,
+            unsigned int nprops, double xfactor, double yfactor,
+-           double sXfactor, double sYfactor)
++           double sXfactor, double sYfactor,
++           int maxprops)
+ {
+     int         n;
+     int         count;
+@@ -526,25 +527,13 @@ computeProps(FontPropPtr pf, char *wasStringProp,
+ 
+       switch (t->type) {
+       case scaledX:
+-          npf->value = doround(xfactor * (double)pf->value);
+-          rawfactor = sXfactor;
+-          break;
+       case scaledY:
+-          npf->value = doround(yfactor * (double)pf->value);
+-          rawfactor = sYfactor;
+-          break;
+-      case unscaled:
+-          npf->value = pf->value;
+-          npf->name = pf->name;
+-          npf++;
+-          count++;
+-          *isStringProp++ = *wasStringProp;
+-          break;
+-      default:
+-          break;
+-      }
+-      if (t->type != unscaled)
+-      {
++          if (count + 2 > maxprops)
++              continue;
++          npf->value = (t->type == scaledX)
++              ? doround(xfactor * (double)pf->value)
++              : doround(yfactor * (double)pf->value);
++          rawfactor = (t->type == scaledX) ? sXfactor : sYfactor;
+           npf->name = pf->name;
+           npf++;
+           count++;
+@@ -554,6 +543,18 @@ computeProps(FontPropPtr pf, char *wasStringProp,
+           count++;
+           *isStringProp++ = *wasStringProp;
+           *isStringProp++ = *wasStringProp;
++          break;
++      case unscaled:
++          if (count + 1 > maxprops)
++              continue;
++          npf->value = pf->value;
++          npf->name = pf->name;
++          npf++;
++          count++;
++          *isStringProp++ = *wasStringProp;
++          break;
++      default:
++          break;
+       }
+     }
+     return count;
+@@ -671,7 +672,7 @@ ComputeScaledProperties(FontInfoPtr sourceFontInfo, /* the 
font to be scaled */
+     n = NPROPS;
+     n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp,
+                     fp, isStringProp, sourceFontInfo->nprops, dx, dy,
+-                    sdx, sdy);
++                    sdx, sdy, nProps - NPROPS);
+     return n;
+ }
+ 
diff --git a/debian/patches/series b/debian/patches/series
index fdffa2a0fd7b..7d05b9a86497 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,3 @@
-# placeholder
+CVE-2026-56001.patch
+CVE-2026-56002.patch
+CVE-2026-56003.patch

Reply via email to