diff --git a/0001-bitscale-fix-integer-overflow-in-BitmapScaleBitmaps-.patch b/0001-bitscale-fix-integer-overflow-in-BitmapScaleBitmaps-.patch new file mode 100644 index 0000000..0e5e71d --- /dev/null +++ b/0001-bitscale-fix-integer-overflow-in-BitmapScaleBitmaps-.patch @@ -0,0 +1,71 @@ +From be0b08e2d354138d3222b4490e2a77c6ee42f778 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Mon, 1 Jun 2026 16:46:10 +1000 +Subject: [PATCH libXfont 1/3] 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 +Part-of: +--- + 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 3f3c10e..5f465d1 100644 +--- a/src/bitmap/bitscale.c ++++ b/src/bitmap/bitscale.c +@@ -1456,7 +1456,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]; +@@ -1483,8 +1483,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 ? */ +-- +2.55.0 + diff --git a/0002-pcfread-validate-bitmap-sizes-and-offsets-against-pe.patch b/0002-pcfread-validate-bitmap-sizes-and-offsets-against-pe.patch new file mode 100644 index 0000000..be5bf1d --- /dev/null +++ b/0002-pcfread-validate-bitmap-sizes-and-offsets-against-pe.patch @@ -0,0 +1,134 @@ +From b4389e0b1d84a690b819bb27b1439968811a3674 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Mon, 1 Jun 2026 16:48:40 +1000 +Subject: [PATCH libXfont 2/3] 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 +Part-of: +--- + 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 7c2e7e1..a385331 100644 +--- a/src/bitmap/pcfread.c ++++ b/src/bitmap/pcfread.c +@@ -532,25 +532,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]; +@@ -625,6 +674,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)]= +-- +2.55.0 + diff --git a/0003-bitscale-add-bounds-check-to-computeProps-for-proper.patch b/0003-bitscale-add-bounds-check-to-computeProps-for-proper.patch new file mode 100644 index 0000000..f23f02f --- /dev/null +++ b/0003-bitscale-add-bounds-check-to-computeProps-for-proper.patch @@ -0,0 +1,110 @@ +From dff957a5158da038a282a59a31fe736702732939 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Mon, 1 Jun 2026 16:49:55 +1000 +Subject: [PATCH libXfont 3/3] 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 +Part-of: +--- + src/bitmap/bitscale.c | 39 ++++++++++++++++++++------------------- + 1 file changed, 20 insertions(+), 19 deletions(-) + +diff --git a/src/bitmap/bitscale.c b/src/bitmap/bitscale.c +index 5f465d1..ec57f55 100644 +--- a/src/bitmap/bitscale.c ++++ b/src/bitmap/bitscale.c +@@ -507,7 +507,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; +@@ -522,14 +523,26 @@ 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; ++ 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++; ++ npf->value = doround(rawfactor * (double)pf->value); ++ npf->name = rawFontPropTable[t - fontPropTable].atom; ++ npf++; ++ count++; ++ *isStringProp++ = *wasStringProp; ++ *isStringProp++ = *wasStringProp; + break; + case unscaled: ++ if (count + 1 > maxprops) ++ continue; + npf->value = pf->value; + npf->name = pf->name; + npf++; +@@ -539,18 +552,6 @@ computeProps(FontPropPtr pf, char *wasStringProp, + default: + break; + } +- if (t->type != unscaled) +- { +- npf->name = pf->name; +- npf++; +- count++; +- npf->value = doround(rawfactor * (double)pf->value); +- npf->name = rawFontPropTable[t - fontPropTable].atom; +- npf++; +- count++; +- *isStringProp++ = *wasStringProp; +- *isStringProp++ = *wasStringProp; +- } + } + return count; + } +@@ -667,7 +668,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; + } + +-- +2.55.0 + diff --git a/libXfont2.spec b/libXfont2.spec index 5f03dac..87e5b82 100644 --- a/libXfont2.spec +++ b/libXfont2.spec @@ -1,7 +1,7 @@ Summary: X.Org X11 libXfont2 runtime library Name: libXfont2 Version: 2.0.3 -Release: 2%{?dist} +Release: 2%{?dist}.1 License: MIT Group: System Environment/Libraries URL: http://www.x.org @@ -15,6 +15,10 @@ BuildRequires: xorg-x11-xtrans-devel >= 1.0.3-3 BuildRequires: libfontenc-devel BuildRequires: freetype-devel +Patch1: 0001-bitscale-fix-integer-overflow-in-BitmapScaleBitmaps-.patch +Patch2: 0002-pcfread-validate-bitmap-sizes-and-offsets-against-pe.patch +Patch3: 0003-bitscale-add-bounds-check-to-computeProps-for-proper.patch + %description X.Org X11 libXfont2 runtime library @@ -28,7 +32,7 @@ Requires: libfontenc-devel%{?_isa} X.Org X11 libXfont development package %prep -%autosetup +%autosetup -p1 %build autoreconf -v --install --force @@ -56,6 +60,12 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.la %{_libdir}/pkgconfig/xfont2.pc %changelog +* Wed Jul 08 2026 Olivier Fourdan - 2.0.3-2.1 +- CVE fix for: CVE-2026-56001, CVE-2026-56002, CVE-2026-56003 + Resolves: https://redhat.atlassian.net/browse/RHEL-191877 + Resolves: https://redhat.atlassian.net/browse/RHEL-191928 + Resolves: https://redhat.atlassian.net/browse/RHEL-191948 + * Fri Jun 29 2018 Adam Jackson - 2.0.3-2 - Use ldconfig scriptlet macros