untrusted comment: verify with openbsd-78-base.pub RWS3/nvFmk4SWe5ihcRBFx2woUvJy3AzrG41bI9W8upt2cOQ4uRULUKrtFcefWXlbsDyPpXqNV7T7liSJjd10N0b7GUj+hfBjwI= OpenBSD 7.8 errata 056, September 14, 2026: Multiple vulnerabilities in the X server and server side font library. CVE-2026-55999 CVE-2026-56000 CVE-2026-56001 CVE-2026-56002 CVE-2026-56003 Apply by doing: signify -Vep /etc/signify/openbsd-78-base.pub -x 056_xserver.patch.sig \ -m - | (cd /usr/xenocara && patch -p0) And then rebuild and install the X font library and X server: cd /usr/xenocara/lib/libXfont2 make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build cd /usr/xenocara/xserver make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build Index: xserver/Xi/xichangecursor.c =================================================================== RCS file: /cvs/xenocara/xserver/Xi/xichangecursor.c,v diff -u -p -r1.6 xichangecursor.c --- xserver/Xi/xichangecursor.c 27 Jul 2019 07:57:08 -0000 1.6 +++ xserver/Xi/xichangecursor.c 7 Sep 2026 14:58:26 -0000 @@ -89,6 +89,9 @@ ProcXIChangeCursor(ClientPtr client) return rc; } + if (pWin == NullWindow) + return BadWindow; + if (stuff->cursor == None) { if (pWin == pWin->drawable.pScreen->root) pCursor = rootCursor; Index: xserver/fb/fbglyph.c =================================================================== RCS file: /cvs/xenocara/xserver/fb/fbglyph.c,v diff -u -p -r1.7 fbglyph.c --- xserver/fb/fbglyph.c 27 Jul 2019 07:57:10 -0000 1.7 +++ xserver/fb/fbglyph.c 7 Sep 2026 14:58:26 -0000 @@ -95,7 +95,7 @@ fbPolyGlyphBlt(DrawablePtr pDrawable, pglyph = FONTGLYPHBITS(pglyphBase, pci); gWidth = GLYPHWIDTHPIXELS(pci); gHeight = GLYPHHEIGHTPIXELS(pci); - if (gWidth && gHeight) { + if (gWidth > 0 && gHeight > 0) { gx = x + pci->metrics.leftSideBearing; gy = y - pci->metrics.ascent; if (glyph && gWidth <= sizeof(FbStip) * 8 && @@ -197,7 +197,7 @@ fbImageGlyphBlt(DrawablePtr pDrawable, pglyph = FONTGLYPHBITS(pglyphBase, pci); gWidth = GLYPHWIDTHPIXELS(pci); gHeight = GLYPHHEIGHTPIXELS(pci); - if (gWidth && gHeight) { + if (gWidth > 0 && gHeight > 0) { gx = x + pci->metrics.leftSideBearing; gy = y - pci->metrics.ascent; if (glyph && gWidth <= sizeof(FbStip) * 8 && Index: xserver/glamor/glamor_font.c =================================================================== RCS file: /cvs/xenocara/xserver/glamor/glamor_font.c,v diff -u -p -r1.6 glamor_font.c --- xserver/glamor/glamor_font.c 11 Nov 2021 09:03:03 -0000 1.6 +++ xserver/glamor/glamor_font.c 7 Sep 2026 14:58:27 -0000 @@ -71,6 +71,9 @@ glamor_font_get(ScreenPtr screen, FontPt glyph_width_pixels = font->info.maxbounds.rightSideBearing - font->info.minbounds.leftSideBearing; glyph_height = font->info.maxbounds.ascent + font->info.maxbounds.descent; + if (glyph_width_pixels <= 0 || glyph_height <= 0) + return NULL; + glyph_width_bytes = (glyph_width_pixels + 7) >> 3; glamor_font->glyph_width_pixels = glyph_width_pixels; @@ -130,7 +133,28 @@ glamor_font_get(ScreenPtr screen, FontPt if (count) { char *dst; char *src = glyph->bits; - unsigned y; + int gw = GLYPHWIDTHBYTES(glyph); + int gh = GLYPHHEIGHTPIXELS(glyph); + + /* Reject fonts where any per-glyph metric is negative + * or exceeds the atlas slot size derived from maxbounds. + * The PCF parser in libXfont2 does not recompute + * maxbounds from per-glyph data, so a crafted PCF file + * can violate the maxbounds invariant. + * + * gw is passed as size_t to memcpy and a negative value + * would thus result in OOB access. + * + * Returning NULL makes glamor fall back to software + * rendering. + */ + if (gw < 0 || gh < 0 || + gw > glyph_width_bytes || gh > glyph_height) { + glDeleteTextures(1, &glamor_font->texture_id); + glamor_font->texture_id = 0; + free(bits); + return NULL; + } dst = bits; /* get offset of start of first row */ @@ -139,8 +163,8 @@ glamor_font_get(ScreenPtr screen, FontPt dst += (row & 1) ? glamor_font->row_width : 0; dst += col * glyph_width_bytes; - for (y = 0; y < GLYPHHEIGHTPIXELS(glyph); y++) { - memcpy(dst, src, GLYPHWIDTHBYTES(glyph)); + for (int y = 0; y < gh; y++) { + memcpy(dst, src, gw); dst += overall_width; src += GLYPHWIDTHBYTESPADDED(glyph); } Index: xserver/glamor/glamor_glyphblt.c =================================================================== RCS file: /cvs/xenocara/xserver/glamor/glamor_glyphblt.c,v diff -u -p -r1.5 glamor_glyphblt.c --- xserver/glamor/glamor_glyphblt.c 5 Nov 2024 08:13:06 -0000 1.5 +++ xserver/glamor/glamor_glyphblt.c 7 Sep 2026 14:58:27 -0000 @@ -89,7 +89,7 @@ glamor_poly_glyph_blt_gl(DrawablePtr dra int h = GLYPHHEIGHTPIXELS(charinfo); uint8_t *glyphbits = FONTGLYPHBITS(NULL, charinfo); - if (w && h) { + if (w > 0 && h > 0) { int glyph_x = x + charinfo->metrics.leftSideBearing; int glyph_y = y - charinfo->metrics.ascent; int glyph_stride = GLYPHWIDTHBYTESPADDED(charinfo); Index: xserver/glx/vndcmds.c =================================================================== RCS file: /cvs/xenocara/xserver/glx/vndcmds.c,v diff -u -p -r1.3 vndcmds.c --- xserver/glx/vndcmds.c 11 Nov 2021 09:03:03 -0000 1.3 +++ xserver/glx/vndcmds.c 7 Sep 2026 14:58:27 -0000 @@ -165,9 +165,6 @@ static int CommonLoseCurrent(ClientPtr c tagInfo->tag, // No old context tag, None, None, None, 0); - if (ret == Success) { - GlxFreeContextTag(tagInfo); - } return ret; } @@ -259,6 +256,10 @@ static int CommonMakeCurrent(ClientPtr c if (ret != Success) { return ret; } + // Free the old tag before calling CommonMakeNewCurrent(), + // which may call GlxAllocContextTag() and realloc the + // contextTags array, invalidating the oldTag pointer. + GlxFreeContextTag(oldTag); oldTag = NULL; } Index: xserver/mi/miglblt.c =================================================================== RCS file: /cvs/xenocara/xserver/mi/miglblt.c,v diff -u -p -r1.12 miglblt.c --- xserver/mi/miglblt.c 11 Nov 2021 09:03:13 -0000 1.12 +++ xserver/mi/miglblt.c 7 Sep 2026 14:58:27 -0000 @@ -143,7 +143,7 @@ miPolyGlyphBlt(DrawablePtr pDrawable, GC pglyph = FONTGLYPHBITS(pglyphBase, pci); gWidth = GLYPHWIDTHPIXELS(pci); gHeight = GLYPHHEIGHTPIXELS(pci); - if (gWidth && gHeight) { + if (gWidth > 0 && gHeight > 0) { nbyGlyphWidth = GLYPHWIDTHBYTESPADDED(pci); nbyPadGlyph = BitmapBytePad(gWidth); Index: lib/libXfont2/src/bitmap/bitscale.c =================================================================== RCS file: /cvs/xenocara/lib/libXfont2/src/bitmap/bitscale.c,v diff -u -p -r1.4 bitscale.c --- lib/libXfont2/src/bitmap/bitscale.c 5 Nov 2024 08:14:56 -0000 1.4 +++ lib/libXfont2/src/bitmap/bitscale.c 7 Sep 2026 14:58:27 -0000 @@ -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 *wasSt 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 *wasSt 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 sour n = NPROPS; n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp, fp, isStringProp, sourceFontInfo->nprops, dx, dy, - sdx, sdy); + sdx, sdy, nProps - NPROPS); return n; } @@ -1456,7 +1457,7 @@ BitmapScaleBitmaps(FontPtr pf, 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 +1484,25 @@ BitmapScaleBitmaps(FontPtr pf, 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 ? */ Index: lib/libXfont2/src/bitmap/pcfread.c =================================================================== RCS file: /cvs/xenocara/lib/libXfont2/src/bitmap/pcfread.c,v diff -u -p -r1.4 pcfread.c --- lib/libXfont2/src/bitmap/pcfread.c 31 Aug 2022 08:05:53 -0000 1.4 +++ lib/libXfont2/src/bitmap/pcfread.c 7 Sep 2026 14:58:27 -0000 @@ -531,25 +531,74 @@ pcfReadFont(FontPtr pFont, FontFilePtr f 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 f 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)]=