Compare commits
No commits in common. "c8s" and "c9-beta" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1 @@
|
|||||||
SOURCES/libXfont2-2.0.3.tar.bz2
|
SOURCES/libXfont2-2.0.3.tar.bz2
|
||||||
/libXfont2-2.0.3.tar.bz2
|
|
||||||
|
|||||||
1
.libXfont2.metadata
Normal file
1
.libXfont2.metadata
Normal file
@ -0,0 +1 @@
|
|||||||
|
1110f1ad4061d9e8131ecb941757480e3e32bca0 SOURCES/libXfont2-2.0.3.tar.bz2
|
||||||
@ -1,71 +0,0 @@
|
|||||||
From be0b08e2d354138d3222b4490e2a77c6ee42f778 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
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 <peter.hutterer@who-t.net>
|
|
||||||
Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxfont/-/merge_requests/34>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
From b4389e0b1d84a690b819bb27b1439968811a3674 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
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 <peter.hutterer@who-t.net>
|
|
||||||
Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxfont/-/merge_requests/34>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,110 +0,0 @@
|
|||||||
From dff957a5158da038a282a59a31fe736702732939 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
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 <peter.hutterer@who-t.net>
|
|
||||||
Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxfont/-/merge_requests/34>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,117 +0,0 @@
|
|||||||
From 76a453c43a7fb74f1e6258d452b3d3df51b97af4 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
Date: Mon, 13 Jul 2026 15:48:06 +1000
|
|
||||||
Subject: [PATCH] fserve: validate num_chars against encoding array size in
|
|
||||||
fs_read_glyphs
|
|
||||||
|
|
||||||
FS_QueryXExtents16 causes us to allocate the encoding[] array, later
|
|
||||||
during the FS_QueryXBitmaps16 reply handling we fill in that array.
|
|
||||||
There is no verification that the allocation is large enough, a
|
|
||||||
malicious font server could send us a small numExtents and a
|
|
||||||
large num_chars to force underallocation and OOB read/rwrite.
|
|
||||||
|
|
||||||
A regression test is included that constructs a crafted
|
|
||||||
FS_QueryXBitmaps16 reply with num_chars > num_encoding and verifies
|
|
||||||
the library rejects it.
|
|
||||||
|
|
||||||
CVE-2026-59679
|
|
||||||
|
|
||||||
Found-by: Zhixi "Jace" Sun, independent security researcher
|
|
||||||
Assisted-by: Claude:claude-opus-4-6
|
|
||||||
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxfont/-/merge_requests/36>
|
|
||||||
---
|
|
||||||
Makefile.am | 16 ++++++++++++++++
|
|
||||||
src/fc/fserve.c | 22 ++++++++++++++++++++++
|
|
||||||
src/fc/fservestr.h | 1 +
|
|
||||||
3 files changed, 39 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/Makefile.am b/Makefile.am
|
|
||||||
index c1a3db2..ef9bc40 100644
|
|
||||||
--- a/Makefile.am
|
|
||||||
+++ b/Makefile.am
|
|
||||||
@@ -157,6 +157,22 @@ endif
|
|
||||||
|
|
||||||
EXTRA_DIST = src/builtins/buildfont
|
|
||||||
|
|
||||||
+# Security regression tests
|
|
||||||
+TESTS =
|
|
||||||
+check_PROGRAMS =
|
|
||||||
+
|
|
||||||
+if XFONT_FC
|
|
||||||
+TESTS += test-fserve-read-glyphs
|
|
||||||
+check_PROGRAMS += test-fserve-read-glyphs
|
|
||||||
+
|
|
||||||
+# The test #includes fserve.c directly to access static functions so
|
|
||||||
+# we statically link against libXfont2.a.
|
|
||||||
+test_fserve_read_glyphs_SOURCES = test/test-fserve-read-glyphs.c
|
|
||||||
+test_fserve_read_glyphs_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/src/fc
|
|
||||||
+test_fserve_read_glyphs_LDFLAGS = -static
|
|
||||||
+test_fserve_read_glyphs_LDADD = libXfont2.la $(LTLIBOBJS)
|
|
||||||
+endif XFONT_FC
|
|
||||||
+
|
|
||||||
MAINTAINERCLEANFILES = ChangeLog INSTALL
|
|
||||||
|
|
||||||
.PHONY: ChangeLog INSTALL
|
|
||||||
diff --git a/src/fc/fserve.c b/src/fc/fserve.c
|
|
||||||
index 708fc35..4141c3c 100644
|
|
||||||
--- a/src/fc/fserve.c
|
|
||||||
+++ b/src/fc/fserve.c
|
|
||||||
@@ -1097,6 +1097,7 @@ fs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
|
|
||||||
return AllocError;
|
|
||||||
}
|
|
||||||
fsfont->encoding = pCI;
|
|
||||||
+ fsfont->num_encoding = numExtents;
|
|
||||||
if (haveInk)
|
|
||||||
fsfont->inkMetrics = pCI + numExtents;
|
|
||||||
else
|
|
||||||
@@ -2004,6 +2005,17 @@ fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
|
|
||||||
{
|
|
||||||
minchar = 0;
|
|
||||||
maxchar = rep->num_chars;
|
|
||||||
+
|
|
||||||
+ /* Reject replies where num_chars exceeds the encoding array
|
|
||||||
+ size allocated in fs_read_extent_info() to prevent
|
|
||||||
+ out-of-bounds access on encoding[]. */
|
|
||||||
+ if (rep->num_chars > (CARD32)fsdata->num_encoding)
|
|
||||||
+ {
|
|
||||||
+ ErrorF("fserve: num_chars (%u) > num_encoding (%d)\n",
|
|
||||||
+ (unsigned) rep->num_chars, fsdata->num_encoding);
|
|
||||||
+ err = AllocError;
|
|
||||||
+ goto bail;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
off_adr = (char *)ppbits;
|
|
||||||
@@ -2025,6 +2037,16 @@ fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
|
|
||||||
for (i = 0; i < rep->num_chars; i++)
|
|
||||||
{
|
|
||||||
memcpy(&local_off, off_adr, SIZEOF(fsOffset32)); /* align it */
|
|
||||||
+ /* Bounds-check minchar against the encoding array size to
|
|
||||||
+ prevent out-of-bounds access from a malicious font server
|
|
||||||
+ reply with more num_chars than num_extents. */
|
|
||||||
+ if (minchar >= (unsigned long)fsdata->num_encoding)
|
|
||||||
+ {
|
|
||||||
+ ErrorF("fserve: glyph index %lu >= num_encoding (%d)\n",
|
|
||||||
+ minchar, fsdata->num_encoding);
|
|
||||||
+ err = AllocError;
|
|
||||||
+ goto bail;
|
|
||||||
+ }
|
|
||||||
if (blockrec->type == FS_OPEN_FONT ||
|
|
||||||
fsdata->encoding[minchar].bits == &_fs_glyph_requested)
|
|
||||||
{
|
|
||||||
diff --git a/src/fc/fservestr.h b/src/fc/fservestr.h
|
|
||||||
index 29ae46e..da95e41 100644
|
|
||||||
--- a/src/fc/fservestr.h
|
|
||||||
+++ b/src/fc/fservestr.h
|
|
||||||
@@ -43,6 +43,7 @@ typedef struct _fs_glyph {
|
|
||||||
typedef struct _fs_font {
|
|
||||||
CharInfoPtr pDefault;
|
|
||||||
CharInfoPtr encoding;
|
|
||||||
+ int num_encoding;
|
|
||||||
CharInfoPtr inkMetrics;
|
|
||||||
FSGlyphPtr glyphs;
|
|
||||||
} FSFontRec, *FSFontPtr;
|
|
||||||
--
|
|
||||||
2.39.5
|
|
||||||
|
|
||||||
@ -1,13 +1,13 @@
|
|||||||
Summary: X.Org X11 libXfont2 runtime library
|
Summary: X.Org X11 libXfont2 runtime library
|
||||||
Name: libXfont2
|
Name: libXfont2
|
||||||
Version: 2.0.3
|
Version: 2.0.3
|
||||||
Release: 2%{?dist}.3
|
Release: 12%{?dist}
|
||||||
License: MIT
|
License: MIT
|
||||||
Group: System Environment/Libraries
|
|
||||||
URL: http://www.x.org
|
URL: http://www.x.org
|
||||||
|
|
||||||
Source0: http://www.x.org/pub/individual/lib/%{name}-%{version}.tar.bz2
|
Source0: http://www.x.org/pub/individual/lib/%{name}-%{version}.tar.bz2
|
||||||
|
|
||||||
|
BuildRequires: make
|
||||||
BuildRequires: autoconf automake libtool
|
BuildRequires: autoconf automake libtool
|
||||||
BuildRequires: pkgconfig(fontsproto)
|
BuildRequires: pkgconfig(fontsproto)
|
||||||
BuildRequires: xorg-x11-util-macros
|
BuildRequires: xorg-x11-util-macros
|
||||||
@ -15,21 +15,11 @@ BuildRequires: xorg-x11-xtrans-devel >= 1.0.3-3
|
|||||||
BuildRequires: libfontenc-devel
|
BuildRequires: libfontenc-devel
|
||||||
BuildRequires: freetype-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
|
|
||||||
|
|
||||||
# https://gitlab.freedesktop.org/xorg/lib/libxfont/-/commit/c2d222bb22c623d8a40f3275077fc7e6617f2c8a
|
|
||||||
Patch4: libXfont2-2.0.3-CVE-2026-44950.patch
|
|
||||||
# https://gitlab.freedesktop.org/xorg/lib/libxfont/-/commit/668fea81f40bcb48ec67fb55d0b851049d265290
|
|
||||||
Patch5: 0004-fserve-validate-num_chars-against-encoding-array-siz.patch
|
|
||||||
|
|
||||||
%description
|
%description
|
||||||
X.Org X11 libXfont2 runtime library
|
X.Org X11 libXfont2 runtime library
|
||||||
|
|
||||||
%package devel
|
%package devel
|
||||||
Summary: X.Org X11 libXfont2 development package
|
Summary: X.Org X11 libXfont2 development package
|
||||||
Group: Development/Libraries
|
|
||||||
Requires: %{name}%{?_isa} = %{version}-%{release}
|
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||||
Requires: libfontenc-devel%{?_isa}
|
Requires: libfontenc-devel%{?_isa}
|
||||||
|
|
||||||
@ -37,7 +27,7 @@ Requires: libfontenc-devel%{?_isa}
|
|||||||
X.Org X11 libXfont development package
|
X.Org X11 libXfont development package
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%autosetup -p1
|
%autosetup
|
||||||
|
|
||||||
%build
|
%build
|
||||||
autoreconf -v --install --force
|
autoreconf -v --install --force
|
||||||
@ -65,19 +55,36 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
|
|||||||
%{_libdir}/pkgconfig/xfont2.pc
|
%{_libdir}/pkgconfig/xfont2.pc
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Thu Aug 06 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.0.3-2.3
|
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.0.3-12
|
||||||
- CVE fix for: CVE-2026-59679
|
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
|
||||||
Resolves: https://redhat.atlassian.net/browse/RHEL-221956
|
Related: rhbz#1991688
|
||||||
|
|
||||||
* Thu Aug 06 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.0.3-2.2
|
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 2.0.3-11
|
||||||
- CVE fix for: CVE-2026-44950
|
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
|
||||||
Resolves: https://redhat.atlassian.net/browse/RHEL-222015
|
|
||||||
|
|
||||||
* Wed Jul 08 2026 Olivier Fourdan <ofourdan@redhat.com> - 2.0.3-2.1
|
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.3-10
|
||||||
- CVE fix for: CVE-2026-56001, CVE-2026-56002, CVE-2026-56003
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||||
Resolves: https://redhat.atlassian.net/browse/RHEL-191877
|
|
||||||
Resolves: https://redhat.atlassian.net/browse/RHEL-191928
|
* Thu Nov 5 11:25:30 AEST 2020 Peter Hutterer <peter.hutterer@redhat.com> - 2.0.3-9
|
||||||
Resolves: https://redhat.atlassian.net/browse/RHEL-191948
|
- Add BuildRequires for make
|
||||||
|
|
||||||
|
* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.3-8
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
||||||
|
|
||||||
|
* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.3-7
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
|
||||||
|
|
||||||
|
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.3-6
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
|
||||||
|
|
||||||
|
* Thu Mar 21 2019 Adam Jackson <ajax@redhat.com> - 2.0.3-5
|
||||||
|
- Rebuild for xtrans 1.4.0
|
||||||
|
|
||||||
|
* Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.3-4
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
|
||||||
|
|
||||||
|
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.3-3
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
|
||||||
|
|
||||||
* Fri Jun 29 2018 Adam Jackson <ajax@redhat.com> - 2.0.3-2
|
* Fri Jun 29 2018 Adam Jackson <ajax@redhat.com> - 2.0.3-2
|
||||||
- Use ldconfig scriptlet macros
|
- Use ldconfig scriptlet macros
|
||||||
@ -1,6 +0,0 @@
|
|||||||
--- !Policy
|
|
||||||
product_versions:
|
|
||||||
- rhel-8
|
|
||||||
decision_context: osci_compose_gate
|
|
||||||
rules:
|
|
||||||
- !PassingTestCaseRule {test_case_name: desktop-qe.desktop-ci.tier1-gating.functional}
|
|
||||||
@ -1,511 +0,0 @@
|
|||||||
From fa38750d94ec161fc57d3f53d44a00bb1dfc3d89 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
Date: Mon, 13 Jul 2026 15:50:09 +1000
|
|
||||||
Subject: [PATCH] fserve: bounds-check cumulative glyph data writes in
|
|
||||||
fs_read_glyphs
|
|
||||||
|
|
||||||
fs_read_glyphs() copies each glyph's bitmap into a single allbits
|
|
||||||
buffer allocated to rep->nbytes bytes. The per-glyph guard validates
|
|
||||||
only that the source slice (position, length) lies within the pbitmaps
|
|
||||||
source buffer. It does not check whether the running destination cursor
|
|
||||||
has exceeded the allocation.
|
|
||||||
|
|
||||||
A malicious font server can send overlapping source offsets (e.g. 1000
|
|
||||||
glyphs each referencing {position:0, length:64} with nbytes=64). Each
|
|
||||||
individual source range passes validation, but the cumulative writes
|
|
||||||
total 64000 bytes into a 64-byte destination buffer.
|
|
||||||
|
|
||||||
Interestingly there was an unconditional debug printf in place that
|
|
||||||
sort-of warned about this but didn't prevent this. Let's remove that and
|
|
||||||
instead use the actual check to bail out before we run OOB.
|
|
||||||
|
|
||||||
A regression test is included that sends 100 glyphs each referencing
|
|
||||||
the same 64-byte source slice into a 64-byte destination buffer, and
|
|
||||||
verifies the library rejects the overflow.
|
|
||||||
|
|
||||||
CVE-2026-44950
|
|
||||||
|
|
||||||
Found-by: Zhixi "Jace" Sun, independent security researcher
|
|
||||||
Assisted-by: Claude:claude-opus-4-6
|
|
||||||
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxfont/-/merge_requests/36>
|
|
||||||
---
|
|
||||||
src/fc/fserve.c | 23 +-
|
|
||||||
test/test-fserve-read-glyphs.c | 412 +++++++++++++++++++++++++++++++++
|
|
||||||
2 files changed, 426 insertions(+), 9 deletions(-)
|
|
||||||
create mode 100644 test/test-fserve-read-glyphs.c
|
|
||||||
|
|
||||||
diff --git a/src/fc/fserve.c b/src/fc/fserve.c
|
|
||||||
index 708fc35..f17cffa 100644
|
|
||||||
--- a/src/fc/fserve.c
|
|
||||||
+++ b/src/fc/fserve.c
|
|
||||||
@@ -1923,10 +1923,7 @@ fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
|
|
||||||
fsOffset32 local_off;
|
|
||||||
char *off_adr;
|
|
||||||
pointer pbitmaps;
|
|
||||||
- char *bits, *allbits;
|
|
||||||
-#ifdef DEBUG
|
|
||||||
- char *origallbits;
|
|
||||||
-#endif
|
|
||||||
+ char *bits, *allbits, *origallbits;
|
|
||||||
int i,
|
|
||||||
err;
|
|
||||||
int nranges = 0;
|
|
||||||
@@ -2016,8 +2013,8 @@ fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
-#ifdef DEBUG
|
|
||||||
origallbits = allbits;
|
|
||||||
+#ifdef DEBUG
|
|
||||||
fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n",
|
|
||||||
(int) rep->num_chars, (int) rep->nbytes, fsd->name);
|
|
||||||
#endif
|
|
||||||
@@ -2038,6 +2035,18 @@ fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
|
|
||||||
(local_off.position < rep->nbytes) &&
|
|
||||||
(local_off.length <= (rep->nbytes - local_off.position)))
|
|
||||||
{
|
|
||||||
+ /* Check that the destination buffer has enough room
|
|
||||||
+ for this glyph to prevent a heap overflow from
|
|
||||||
+ overlapping source offsets. */
|
|
||||||
+ if (local_off.length >
|
|
||||||
+ rep->nbytes - (allbits - origallbits))
|
|
||||||
+ {
|
|
||||||
+ ErrorF("fserve: glyph data overflow: "
|
|
||||||
+ "cumulative write exceeds nbytes (%u)\n",
|
|
||||||
+ (unsigned) rep->nbytes);
|
|
||||||
+ err = AllocError;
|
|
||||||
+ goto bail;
|
|
||||||
+ }
|
|
||||||
bits = allbits;
|
|
||||||
allbits += local_off.length;
|
|
||||||
memcpy(bits, (char *)pbitmaps + local_off.position,
|
|
||||||
@@ -2065,10 +2074,6 @@ fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
|
|
||||||
}
|
|
||||||
off_adr += SIZEOF(fsOffset32);
|
|
||||||
}
|
|
||||||
-#ifdef DEBUG
|
|
||||||
- fprintf (stderr, "Used %d bytes instead of %d\n",
|
|
||||||
- (int) (allbits - origallbits), (int) rep->nbytes);
|
|
||||||
-#endif
|
|
||||||
|
|
||||||
if (blockrec->type == FS_OPEN_FONT)
|
|
||||||
{
|
|
||||||
diff --git a/test/test-fserve-read-glyphs.c b/test/test-fserve-read-glyphs.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..21c3410
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/test/test-fserve-read-glyphs.c
|
|
||||||
@@ -0,0 +1,412 @@
|
|
||||||
+/*
|
|
||||||
+ * Security regression tests for fs_read_glyphs() in src/fc/fserve.c.
|
|
||||||
+ *
|
|
||||||
+ * Approach: include fserve.c directly to access the static fs_read_glyphs()
|
|
||||||
+ * function. Pre-fill the FSFpeRec.inBuf with a crafted protocol reply so
|
|
||||||
+ * fs_get_reply() returns it without any network I/O.
|
|
||||||
+ *
|
|
||||||
+ * Copyright (c) 2026, Red Hat, Inc.
|
|
||||||
+ *
|
|
||||||
+ * Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
+ * copy of this software and associated documentation files (the "Software"),
|
|
||||||
+ * to deal in the Software without restriction, including without limitation
|
|
||||||
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
+ * and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
+ * Software is furnished to do so, subject to the following conditions:
|
|
||||||
+ *
|
|
||||||
+ * The above copyright notice and this permission notice (including the next
|
|
||||||
+ * paragraph) shall be included in all copies or substantial portions of the
|
|
||||||
+ * Software.
|
|
||||||
+ *
|
|
||||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
+ * DEALINGS IN THE SOFTWARE.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Include fserve.c directly to access the static fs_read_glyphs().
|
|
||||||
+ * All non-static symbols from fserve.c are hidden in libXfont2.so
|
|
||||||
+ * (via the linker version script), so there are no duplicate symbol
|
|
||||||
+ * conflicts when linking against the library.
|
|
||||||
+ */
|
|
||||||
+#include "src/fc/fserve.c"
|
|
||||||
+
|
|
||||||
+#include <stdio.h>
|
|
||||||
+#include <stdlib.h>
|
|
||||||
+#include <string.h>
|
|
||||||
+#include <unistd.h>
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Set up an FSFpeRec with its inBuf pre-filled with the given data.
|
|
||||||
+ * fs_get_reply() will return this data without attempting any network I/O
|
|
||||||
+ * because fs_inqueued(conn) >= size.
|
|
||||||
+ */
|
|
||||||
+static void
|
|
||||||
+setup_conn(FSFpeRec *conn, const void *reply_data, long reply_size)
|
|
||||||
+{
|
|
||||||
+ memset(conn, 0, sizeof(*conn));
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * fs_get_reply() checks: conn->fs_fd != -1 && conn->fs_listening
|
|
||||||
+ * Use a dup'd fd so it's valid but harmless.
|
|
||||||
+ */
|
|
||||||
+ conn->fs_fd = dup(STDERR_FILENO);
|
|
||||||
+ conn->fs_listening = TRUE;
|
|
||||||
+
|
|
||||||
+ /* Pre-fill the input buffer with our crafted reply */
|
|
||||||
+ conn->inBuf.buf = malloc(reply_size);
|
|
||||||
+ if (!conn->inBuf.buf) {
|
|
||||||
+ fprintf(stderr, "FAIL: malloc for inBuf\n");
|
|
||||||
+ exit(1);
|
|
||||||
+ }
|
|
||||||
+ memcpy(conn->inBuf.buf, reply_data, reply_size);
|
|
||||||
+ conn->inBuf.size = reply_size;
|
|
||||||
+ conn->inBuf.insert = reply_size;
|
|
||||||
+ conn->inBuf.remove = 0;
|
|
||||||
+ conn->inNeed = 0;
|
|
||||||
+
|
|
||||||
+ /* Allocate a minimal output buffer to keep _fs_flush happy */
|
|
||||||
+ conn->outBuf.buf = calloc(1, FS_BUF_INC);
|
|
||||||
+ conn->outBuf.size = FS_BUF_INC;
|
|
||||||
+ conn->outBuf.insert = 0;
|
|
||||||
+ conn->outBuf.remove = 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+cleanup_conn(FSFpeRec *conn)
|
|
||||||
+{
|
|
||||||
+ if (conn->fs_fd >= 0)
|
|
||||||
+ close(conn->fs_fd);
|
|
||||||
+ free(conn->inBuf.buf);
|
|
||||||
+ free(conn->outBuf.buf);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Set up the minimum font state needed by fs_read_glyphs():
|
|
||||||
+ * - FontPathElementRec (fpe) with fpe->private = conn
|
|
||||||
+ * - FontRec (pfont) with info, fontPrivate, fpePrivate
|
|
||||||
+ * - FSFontRec (fsfont) with encoding[] array
|
|
||||||
+ * - FSFontDataRec (fsd)
|
|
||||||
+ * - FSBlockDataRec (blockrec) of type FS_OPEN_FONT
|
|
||||||
+ * - FSBlockedFontRec (bfont) embedded in blockrec->data
|
|
||||||
+ */
|
|
||||||
+struct test_font_state {
|
|
||||||
+ FontPathElementRec fpe;
|
|
||||||
+ FontRec pfont;
|
|
||||||
+ FSFontRec fsfont;
|
|
||||||
+ FSFontDataRec fsd;
|
|
||||||
+ FSBlockDataRec blockrec;
|
|
||||||
+ FSBlockedFontRec bfont;
|
|
||||||
+ CharInfoPtr encoding;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+setup_font_state(struct test_font_state *s, FSFpeRec *conn,
|
|
||||||
+ int num_encoding)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ memset(s, 0, sizeof(*s));
|
|
||||||
+
|
|
||||||
+ /* Font path element */
|
|
||||||
+ s->fpe.name = (char *)"test-fserve";
|
|
||||||
+ s->fpe.name_length = strlen(s->fpe.name);
|
|
||||||
+ s->fpe.private = conn;
|
|
||||||
+
|
|
||||||
+ /* Font data (fpePrivate) */
|
|
||||||
+ s->fsd.name = (char *)"test-font";
|
|
||||||
+ s->fsd.namelen = strlen(s->fsd.name);
|
|
||||||
+ s->fsd.glyphs_to_get = 0;
|
|
||||||
+
|
|
||||||
+ /* Encoding array -- this is what num_extents sized */
|
|
||||||
+ s->encoding = calloc(num_encoding, sizeof(CharInfoRec));
|
|
||||||
+ if (!s->encoding) {
|
|
||||||
+ fprintf(stderr, "FAIL: calloc encoding\n");
|
|
||||||
+ exit(1);
|
|
||||||
+ }
|
|
||||||
+ /* Mark all glyphs as having nonzero metrics and undefined bits
|
|
||||||
+ * so fs_read_glyphs will try to process them */
|
|
||||||
+ for (i = 0; i < num_encoding; i++) {
|
|
||||||
+ s->encoding[i].metrics.ascent = 10;
|
|
||||||
+ s->encoding[i].metrics.descent = 2;
|
|
||||||
+ s->encoding[i].metrics.characterWidth = 8;
|
|
||||||
+ s->encoding[i].metrics.leftSideBearing = 0;
|
|
||||||
+ s->encoding[i].metrics.rightSideBearing = 8;
|
|
||||||
+ s->encoding[i].bits = &_fs_glyph_undefined;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* FSFontRec */
|
|
||||||
+ s->fsfont.encoding = s->encoding;
|
|
||||||
+ s->fsfont.num_encoding = num_encoding;
|
|
||||||
+ s->fsfont.pDefault = NULL;
|
|
||||||
+ s->fsfont.inkMetrics = s->encoding;
|
|
||||||
+ s->fsfont.glyphs = NULL;
|
|
||||||
+
|
|
||||||
+ /* FontRec */
|
|
||||||
+ s->pfont.fontPrivate = &s->fsfont;
|
|
||||||
+ s->pfont.fpePrivate = &s->fsd;
|
|
||||||
+ s->pfont.fpe = &s->fpe;
|
|
||||||
+ s->pfont.info.firstRow = 0;
|
|
||||||
+ s->pfont.info.lastRow = 0;
|
|
||||||
+ s->pfont.info.firstCol = 0;
|
|
||||||
+ s->pfont.info.lastCol = num_encoding > 0 ? num_encoding - 1 : 0;
|
|
||||||
+ s->pfont.info.maxbounds.ascent = 20;
|
|
||||||
+ s->pfont.info.maxbounds.descent = 10;
|
|
||||||
+ s->pfont.info.maxbounds.characterWidth = 20;
|
|
||||||
+
|
|
||||||
+ /* Block record -- simulating FS_OPEN_FONT path */
|
|
||||||
+ s->bfont.pfont = &s->pfont;
|
|
||||||
+ s->bfont.flags = FontLoadBitmaps;
|
|
||||||
+ s->bfont.state = FS_GLYPHS_REPLY;
|
|
||||||
+ s->bfont.freeFont = FALSE;
|
|
||||||
+
|
|
||||||
+ s->blockrec.type = FS_OPEN_FONT;
|
|
||||||
+ s->blockrec.data = (pointer)&s->bfont;
|
|
||||||
+ s->blockrec.client = NULL;
|
|
||||||
+ s->blockrec.sequenceNumber = 0;
|
|
||||||
+ s->blockrec.errcode = 0;
|
|
||||||
+ s->blockrec.depending = NULL;
|
|
||||||
+ s->blockrec.next = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+cleanup_font_state(struct test_font_state *s)
|
|
||||||
+{
|
|
||||||
+ FSGlyphPtr g, next;
|
|
||||||
+
|
|
||||||
+ /* Free any glyph allocations made by fs_alloc_glyphs */
|
|
||||||
+ for (g = s->fsfont.glyphs; g; g = next) {
|
|
||||||
+ next = g->next;
|
|
||||||
+ free(g);
|
|
||||||
+ }
|
|
||||||
+ free(s->encoding);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Build a crafted fsQueryXBitmaps16Reply in a buffer.
|
|
||||||
+ * Returns the total buffer size. Caller must free *out_buf.
|
|
||||||
+ *
|
|
||||||
+ * The reply contains:
|
|
||||||
+ * - fsQueryXBitmaps16Reply header
|
|
||||||
+ * - num_chars fsOffset32 entries
|
|
||||||
+ * - nbytes of bitmap data
|
|
||||||
+ */
|
|
||||||
+static long
|
|
||||||
+build_reply(char **out_buf,
|
|
||||||
+ CARD32 num_chars, CARD32 nbytes,
|
|
||||||
+ CARD32 off_position, CARD32 off_length)
|
|
||||||
+{
|
|
||||||
+ long hdr_size = SIZEOF(fsQueryXBitmaps16Reply);
|
|
||||||
+ long offsets_size = SIZEOF(fsOffset32) * num_chars;
|
|
||||||
+ /* Bitmap data area: at least nbytes, but we need off_position + off_length
|
|
||||||
+ * to be valid source, so ensure bitmap area is large enough */
|
|
||||||
+ long bitmap_size = nbytes;
|
|
||||||
+ long total = hdr_size + offsets_size + bitmap_size;
|
|
||||||
+ long total_padded = (total + 3) & ~3; /* pad to 4 bytes */
|
|
||||||
+ char *buf;
|
|
||||||
+ fsQueryXBitmaps16Reply *rep;
|
|
||||||
+ fsOffset32 off;
|
|
||||||
+ long i;
|
|
||||||
+
|
|
||||||
+ buf = calloc(1, total_padded);
|
|
||||||
+ if (!buf) {
|
|
||||||
+ fprintf(stderr, "FAIL: calloc reply buffer\n");
|
|
||||||
+ exit(1);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Fill header */
|
|
||||||
+ rep = (fsQueryXBitmaps16Reply *)buf;
|
|
||||||
+ rep->type = FS_Reply; /* normal reply (0), not FS_Error (1) */
|
|
||||||
+ rep->sequenceNumber = 0;
|
|
||||||
+ rep->length = total_padded >> 2; /* length in 32-bit words */
|
|
||||||
+ rep->replies_hint = 0;
|
|
||||||
+ rep->num_chars = num_chars;
|
|
||||||
+ rep->nbytes = nbytes;
|
|
||||||
+
|
|
||||||
+ /* Fill offset entries -- all pointing to the same source range */
|
|
||||||
+ off.position = off_position;
|
|
||||||
+ off.length = off_length;
|
|
||||||
+ for (i = 0; i < (long)num_chars; i++) {
|
|
||||||
+ memcpy(buf + hdr_size + i * SIZEOF(fsOffset32),
|
|
||||||
+ &off, SIZEOF(fsOffset32));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Fill bitmap data with recognizable pattern */
|
|
||||||
+ memset(buf + hdr_size + offsets_size, 0xAA, bitmap_size);
|
|
||||||
+
|
|
||||||
+ *out_buf = buf;
|
|
||||||
+ return total_padded;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Test 1: num_chars > num_encoding
|
|
||||||
+ *
|
|
||||||
+ * Allocate encoding[] with 2 entries, but send a reply with
|
|
||||||
+ * num_chars = 100. Without the fix, this would read/write
|
|
||||||
+ * encoding[2..99] out of bounds.
|
|
||||||
+ */
|
|
||||||
+static int
|
|
||||||
+test_num_chars_exceeds_encoding(void)
|
|
||||||
+{
|
|
||||||
+ FSFpeRec conn;
|
|
||||||
+ struct test_font_state state;
|
|
||||||
+ char *reply_buf;
|
|
||||||
+ long reply_size;
|
|
||||||
+ int result;
|
|
||||||
+ int num_encoding = 2;
|
|
||||||
+ CARD32 num_chars = 100;
|
|
||||||
+ CARD32 nbytes = num_chars * 16; /* enough bitmap data */
|
|
||||||
+
|
|
||||||
+ /* Build a reply with num_chars=100 but valid source data */
|
|
||||||
+ reply_size = build_reply(&reply_buf, num_chars, nbytes, 0, 16);
|
|
||||||
+ setup_conn(&conn, reply_buf, reply_size);
|
|
||||||
+ setup_font_state(&state, &conn, num_encoding);
|
|
||||||
+
|
|
||||||
+ result = fs_read_glyphs(&state.fpe, &state.blockrec);
|
|
||||||
+
|
|
||||||
+ cleanup_font_state(&state);
|
|
||||||
+ cleanup_conn(&conn);
|
|
||||||
+ free(reply_buf);
|
|
||||||
+
|
|
||||||
+ if (result != Successful) {
|
|
||||||
+ printf("ok 1 - num_chars (%u) > num_encoding (%d) rejected\n",
|
|
||||||
+ (unsigned)num_chars, num_encoding);
|
|
||||||
+ return 0;
|
|
||||||
+ } else {
|
|
||||||
+ printf("not ok 1 - num_chars (%u) > num_encoding (%d) "
|
|
||||||
+ "should have been rejected\n",
|
|
||||||
+ (unsigned)num_chars, num_encoding);
|
|
||||||
+ return 1;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Test 2: cumulative glyph data overflow
|
|
||||||
+ *
|
|
||||||
+ * Allocate allbits with nbytes=64, but send 100 glyphs each
|
|
||||||
+ * with offset {position:0, length:64}. Each individual source
|
|
||||||
+ * range is valid, but the cumulative writes total 6400 bytes
|
|
||||||
+ * into a 64-byte buffer.
|
|
||||||
+ */
|
|
||||||
+static int
|
|
||||||
+test_cumulative_allbits_overflow(void)
|
|
||||||
+{
|
|
||||||
+ FSFpeRec conn;
|
|
||||||
+ struct test_font_state state;
|
|
||||||
+ char *reply_buf;
|
|
||||||
+ long reply_size;
|
|
||||||
+ int result;
|
|
||||||
+ int num_encoding = 100; /* match num_chars so encoding[] is fine */
|
|
||||||
+ CARD32 num_chars = 100;
|
|
||||||
+ CARD32 nbytes = 64; /* tiny destination buffer */
|
|
||||||
+
|
|
||||||
+ /* All offsets point to {position:0, length:64} -- each source
|
|
||||||
+ * range is valid but they overlap, causing 100*64=6400 bytes
|
|
||||||
+ * to be written to a 64-byte buffer */
|
|
||||||
+ reply_size = build_reply(&reply_buf, num_chars, nbytes, 0, 64);
|
|
||||||
+ setup_conn(&conn, reply_buf, reply_size);
|
|
||||||
+ setup_font_state(&state, &conn, num_encoding);
|
|
||||||
+
|
|
||||||
+ result = fs_read_glyphs(&state.fpe, &state.blockrec);
|
|
||||||
+
|
|
||||||
+ cleanup_font_state(&state);
|
|
||||||
+ cleanup_conn(&conn);
|
|
||||||
+ free(reply_buf);
|
|
||||||
+
|
|
||||||
+ if (result != Successful) {
|
|
||||||
+ printf("ok 2 - cumulative allbits overflow (100 * 64 into 64) rejected\n");
|
|
||||||
+ return 0;
|
|
||||||
+ } else {
|
|
||||||
+ printf("not ok 2 - cumulative allbits overflow (100 * 64 into 64) "
|
|
||||||
+ "should have been rejected\n");
|
|
||||||
+ return 1;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Test 3: legitimate reply should still be accepted
|
|
||||||
+ *
|
|
||||||
+ * num_chars == num_encoding, each glyph has unique non-overlapping
|
|
||||||
+ * offsets, and total data fits in nbytes.
|
|
||||||
+ */
|
|
||||||
+static int
|
|
||||||
+test_legitimate_reply(void)
|
|
||||||
+{
|
|
||||||
+ FSFpeRec conn;
|
|
||||||
+ struct test_font_state state;
|
|
||||||
+ char *reply_buf;
|
|
||||||
+ long hdr_size = SIZEOF(fsQueryXBitmaps16Reply);
|
|
||||||
+ long offsets_size;
|
|
||||||
+ int result;
|
|
||||||
+ int num_encoding = 4;
|
|
||||||
+ CARD32 num_chars = 4;
|
|
||||||
+ CARD32 glyph_size = 16;
|
|
||||||
+ CARD32 nbytes = num_chars * glyph_size;
|
|
||||||
+ long total, total_padded;
|
|
||||||
+ fsQueryXBitmaps16Reply *rep;
|
|
||||||
+ fsOffset32 off;
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ offsets_size = SIZEOF(fsOffset32) * num_chars;
|
|
||||||
+ total = hdr_size + offsets_size + nbytes;
|
|
||||||
+ total_padded = (total + 3) & ~3;
|
|
||||||
+
|
|
||||||
+ reply_buf = calloc(1, total_padded);
|
|
||||||
+ if (!reply_buf) {
|
|
||||||
+ fprintf(stderr, "FAIL: calloc\n");
|
|
||||||
+ return 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ rep = (fsQueryXBitmaps16Reply *)reply_buf;
|
|
||||||
+ rep->type = FS_Reply;
|
|
||||||
+ rep->sequenceNumber = 0;
|
|
||||||
+ rep->length = total_padded >> 2;
|
|
||||||
+ rep->replies_hint = 0;
|
|
||||||
+ rep->num_chars = num_chars;
|
|
||||||
+ rep->nbytes = nbytes;
|
|
||||||
+
|
|
||||||
+ /* Each glyph gets its own non-overlapping slice */
|
|
||||||
+ for (i = 0; i < (int)num_chars; i++) {
|
|
||||||
+ off.position = i * glyph_size;
|
|
||||||
+ off.length = glyph_size;
|
|
||||||
+ memcpy(reply_buf + hdr_size + i * SIZEOF(fsOffset32),
|
|
||||||
+ &off, SIZEOF(fsOffset32));
|
|
||||||
+ }
|
|
||||||
+ memset(reply_buf + hdr_size + offsets_size, 0xBB, nbytes);
|
|
||||||
+
|
|
||||||
+ setup_conn(&conn, reply_buf, total_padded);
|
|
||||||
+ setup_font_state(&state, &conn, num_encoding);
|
|
||||||
+
|
|
||||||
+ result = fs_read_glyphs(&state.fpe, &state.blockrec);
|
|
||||||
+
|
|
||||||
+ cleanup_font_state(&state);
|
|
||||||
+ cleanup_conn(&conn);
|
|
||||||
+ free(reply_buf);
|
|
||||||
+
|
|
||||||
+ if (result == Successful) {
|
|
||||||
+ printf("ok 3 - legitimate reply (4 glyphs, non-overlapping) accepted\n");
|
|
||||||
+ return 0;
|
|
||||||
+ } else {
|
|
||||||
+ printf("not ok 3 - legitimate reply (4 glyphs, non-overlapping) "
|
|
||||||
+ "rejected with error %d\n", result);
|
|
||||||
+ return 1;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+int
|
|
||||||
+main(int argc, char **argv)
|
|
||||||
+{
|
|
||||||
+ int failures = 0;
|
|
||||||
+
|
|
||||||
+ printf("1..3\n");
|
|
||||||
+
|
|
||||||
+ failures += test_num_chars_exceeds_encoding();
|
|
||||||
+ failures += test_cumulative_allbits_overflow();
|
|
||||||
+ failures += test_legitimate_reply();
|
|
||||||
+
|
|
||||||
+ return failures ? 1 : 0;
|
|
||||||
+}
|
|
||||||
Loading…
Reference in New Issue
Block a user