Version in base suite: 2.0.6-1 Base version: libxfont_2.0.6-1 Target version: libxfont_2.0.6-1+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/libx/libxfont/libxfont_2.0.6-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/libx/libxfont/libxfont_2.0.6-1+deb13u1.dsc libxfont-2.0.6/debian/changelog | 12 +++++++ src/bitmap/bitscale.c | 62 +++++++++++++++++++++++++--------------- src/bitmap/pcfread.c | 59 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 108 insertions(+), 25 deletions(-) diff -u libxfont-2.0.6/debian/changelog libxfont-2.0.6/debian/changelog --- libxfont-2.0.6/debian/changelog +++ libxfont-2.0.6/debian/changelog @@ -1,3 +1,15 @@ +libxfont (1:2.0.6-1+deb13u1) trixie-security; urgency=high + + * Non-maintainer upload by the Security Team. + * bitscale: fix integer overflow in BitmapScaleBitmaps bytestoalloc + (CVE-2026-56001) (Closes: #1141702) + * pcfread: validate bitmap sizes and offsets against per-glyph metrics + (CVE-2026-56002) (Closes: #1141702) + * bitscale: add bounds check to computeProps for property buffer + (CVE-2026-56003) (Closes: #1141702) + + -- Salvatore Bonaccorso Fri, 10 Jul 2026 14:32:27 +0200 + libxfont (1:2.0.6-1) unstable; urgency=medium * New upstream release. only in patch2: unchanged: --- libxfont-2.0.6.orig/src/bitmap/bitscale.c +++ libxfont-2.0.6/src/bitmap/bitscale.c @@ -511,7 +511,8 @@ 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,14 +527,26 @@ 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++; @@ -543,18 +556,6 @@ 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; } @@ -671,7 +672,7 @@ n = NPROPS; n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp, fp, isStringProp, sourceFontInfo->nprops, dx, dy, - sdx, sdy); + sdx, sdy, nProps - NPROPS); return n; } @@ -1460,7 +1461,7 @@ 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 +1488,25 @@ 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 ? */ only in patch2: unchanged: --- libxfont-2.0.6.orig/src/bitmap/pcfread.c +++ libxfont-2.0.6/src/bitmap/pcfread.c @@ -531,25 +531,74 @@ 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 @@ 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)]=