Module Name: xsrc Committed By: msaitoh Date: Wed May 14 03:55:40 UTC 2014
Modified Files: xsrc/external/mit/libXfont/dist/src/fc [netbsd-6-0]: fsconvert.c fserve.c xsrc/external/mit/libXfont/dist/src/fontfile [netbsd-6-0]: dirfile.c xsrc/xfree/xc/lib/font/fc [netbsd-6-0]: fsconvert.c fserve.c xsrc/xfree/xc/lib/font/fontfile [netbsd-6-0]: dirfile.c Log Message: Pull up following revision(s) (requested by spz in ticket #1063): xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c 1.2 xsrc/external/mit/libXfont/dist/src/fc/fserve.c 1.2 xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c 1.2 xsrc/xfree/xc/lib/font/fc/fsconvert.c 1.5 xsrc/xfree/xc/lib/font/fc/fserve.c 1.5 xsrc/xfree/xc/lib/font/fontfile/dirfile.c 1.5 Fix multiple vulnerabilities in libXfont: - CVE-2014-0209: integer overflow of allocations in font metadata file parsing When a local user who is already authenticated to the X server adds a new directory to the font path, the X server calls libXfont to open the fonts.dir and fonts.alias files in that directory and add entries to the font tables for every line in it. A large file (~2-4 gb) could cause the allocations to overflow, and allow the remaining data read from the file to overwrite other memory in the heap. Affected functions: FontFileAddEntry(), lexAlias() - CVE-2014-0210: unvalidated length fields when parsing xfs protocol replies When parsing replies received from the font server, these calls do not check that the lengths and/or indexes returned by the font server are within the size of the reply or the bounds of the memory allocated to store the data, so could write past the bounds of allocated memory when storing the returned data. Affected functions: _fs_recv_conn_setup(), fs_read_open_font(), fs_read_query_info(), fs_read_extent_info(), fs_read_glyphs(), fs_read_list(), fs_read_list_info() - CVE-2014-0211: integer overflows calculating memory needs for xfs replies These calls do not check that their calculations for how much memory is needed to handle the returned data have not overflowed, so can result in allocating too little memory and then writing the returned data past the end of the allocated buffer. Affected functions: fs_get_reply(), fs_alloc_glyphs(), fs_read_extent_info() See also: http://lists.x.org/archives/xorg-announce/2014-May/002431.html To generate a diff of this commit: cvs rdiff -u -r1.1.1.2 -r1.1.1.2.4.1 \ xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c \ xsrc/external/mit/libXfont/dist/src/fc/fserve.c cvs rdiff -u -r1.1.1.2 -r1.1.1.2.4.1 \ xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c cvs rdiff -u -r1.4 -r1.4.28.1 xsrc/xfree/xc/lib/font/fc/fsconvert.c \ xsrc/xfree/xc/lib/font/fc/fserve.c cvs rdiff -u -r1.4 -r1.4.16.1 xsrc/xfree/xc/lib/font/fontfile/dirfile.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c diff -u xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c:1.1.1.2 xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c:1.1.1.2.4.1 --- xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c:1.1.1.2 Wed Jun 10 07:33:40 2009 +++ xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c Wed May 14 03:55:40 2014 @@ -120,6 +120,10 @@ _fs_convert_props(fsPropInfo *pi, fsProp for (i = 0; i < nprops; i++, dprop++, is_str++) { memcpy(&local_off, off_adr, SIZEOF(fsPropOffset)); + if ((local_off.name.position >= pi->data_len) || + (local_off.name.length > + (pi->data_len - local_off.name.position))) + goto bail; dprop->name = MakeAtom(&pdc[local_off.name.position], local_off.name.length, 1); if (local_off.type != PropTypeString) { @@ -127,10 +131,15 @@ _fs_convert_props(fsPropInfo *pi, fsProp dprop->value = local_off.value.position; } else { *is_str = TRUE; + if ((local_off.name.position >= pi->data_len) || + (local_off.name.length > + (pi->data_len - local_off.name.position))) + goto bail; dprop->value = (INT32) MakeAtom(&pdc[local_off.value.position], local_off.value.length, 1); if (dprop->value == BAD_RESOURCE) { + bail: free (pfi->props); pfi->nprops = 0; pfi->props = 0; @@ -714,7 +723,12 @@ fs_alloc_glyphs (FontPtr pFont, int size FSGlyphPtr glyphs; FSFontPtr fsfont = (FSFontPtr) pFont->fontPrivate; - glyphs = malloc (sizeof (FSGlyphRec) + size); + if (size < (INT_MAX - sizeof (FSGlyphRec))) + glyphs = malloc (sizeof (FSGlyphRec) + size); + else + glyphs = NULL; + if (glyphs == NULL) + return NULL; glyphs->next = fsfont->glyphs; fsfont->glyphs = glyphs; return (pointer) (glyphs + 1); Index: xsrc/external/mit/libXfont/dist/src/fc/fserve.c diff -u xsrc/external/mit/libXfont/dist/src/fc/fserve.c:1.1.1.2 xsrc/external/mit/libXfont/dist/src/fc/fserve.c:1.1.1.2.4.1 --- xsrc/external/mit/libXfont/dist/src/fc/fserve.c:1.1.1.2 Wed Jun 10 07:33:40 2009 +++ xsrc/external/mit/libXfont/dist/src/fc/fserve.c Wed May 14 03:55:40 2014 @@ -73,6 +73,7 @@ in this Software without prior written a #include "fservestr.h" #include <X11/fonts/fontutil.h> #include <errno.h> +#include <limits.h> #include <time.h> #define Time_t time_t @@ -94,6 +95,15 @@ in this Software without prior written a (pci)->descent || \ (pci)->characterWidth) +/* + * SIZEOF(r) is in bytes, length fields in the protocol are in 32-bit words, + * so this converts for doing size comparisons. + */ +#define LENGTHOF(r) (SIZEOF(r) >> 2) + +/* Somewhat arbitrary limit on maximum reply size we'll try to read. */ +#define MAX_REPLY_LENGTH ((64 * 1024 * 1024) >> 2) + extern void ErrorF(const char *f, ...); static int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec ); @@ -209,9 +219,22 @@ _fs_add_rep_log (FSFpePtr conn, fsGeneri rep->sequenceNumber, conn->reqbuffer[i].opcode); } + +#define _fs_reply_failed(rep, name, op) do { \ + if (rep) { \ + if (rep->type == FS_Error) \ + fprintf (stderr, "Error: %d Request: %s\n", \ + ((fsError *)rep)->request, #name); \ + else \ + fprintf (stderr, "Bad Length for %s Reply: %d %s %d\n", \ + #name, rep->length, op, LENGTHOF(name)); \ + } \ +} while (0) + #else #define _fs_add_req_log(conn,op) ((conn)->current_seq++) #define _fs_add_rep_log(conn,rep) +#define _fs_reply_failed(rep,name,op) #endif static Bool @@ -603,6 +626,21 @@ fs_get_reply (FSFpePtr conn, int *error) rep = (fsGenericReply *) buf; + /* + * Refuse to accept replies longer than a maximum reasonable length, + * before we pass to _fs_start_read, since it will try to resize the + * incoming connection buffer to this size. Also avoids integer overflow + * on 32-bit systems. + */ + if (rep->length > MAX_REPLY_LENGTH) + { + ErrorF("fserve: reply length %d > MAX_REPLY_LENGTH, disconnecting" + " from font server\n", rep->length); + _fs_connection_died (conn); + *error = FSIO_ERROR; + return 0; + } + ret = _fs_start_read (conn, rep->length << 2, &buf); if (ret != FSIO_READY) { @@ -685,13 +723,15 @@ fs_read_open_font(FontPathElementPtr fpe int ret; rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length != LENGTHOF(fsOpenBitmapFontReply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); fs_cleanup_bfont (bfont); + _fs_reply_failed (rep, fsOpenBitmapFontReply, "!="); return BadFontName; } @@ -818,6 +858,7 @@ fs_read_query_info(FontPathElementPtr fp FSFpePtr conn = (FSFpePtr) fpe->private; fsQueryXInfoReply *rep; char *buf; + long bufleft; /* length of reply left to use */ fsPropInfo *pi; fsPropOffset *po; pointer pd; @@ -827,13 +868,15 @@ fs_read_query_info(FontPathElementPtr fp int ret; rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length < LENGTHOF(fsQueryXInfoReply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); fs_cleanup_bfont (bfont); + _fs_reply_failed (rep, fsQueryXInfoReply, "<"); return BadFontName; } @@ -846,6 +889,9 @@ fs_read_query_info(FontPathElementPtr fp buf = (char *) rep; buf += SIZEOF(fsQueryXInfoReply); + + bufleft = rep->length << 2; + bufleft -= SIZEOF(fsQueryXInfoReply); /* move the data over */ fsUnpack_XFontInfoHeader(rep, pInfo); @@ -854,17 +900,50 @@ fs_read_query_info(FontPathElementPtr fp _fs_init_fontinfo(conn, pInfo); /* Compute offsets into the reply */ + if (bufleft < SIZEOF(fsPropInfo)) + { + ret = -1; +#ifdef DEBUG + fprintf(stderr, "fsQueryXInfo: bufleft (%ld) < SIZEOF(fsPropInfo)\n", + bufleft); +#endif + goto bail; + } pi = (fsPropInfo *) buf; buf += SIZEOF (fsPropInfo); + bufleft -= SIZEOF(fsPropInfo); + if ((bufleft / SIZEOF(fsPropOffset)) < pi->num_offsets) + { + ret = -1; +#ifdef DEBUG + fprintf(stderr, + "fsQueryXInfo: bufleft (%ld) / SIZEOF(fsPropOffset) < %d\n", + bufleft, pi->num_offsets); +#endif + goto bail; + } po = (fsPropOffset *) buf; buf += pi->num_offsets * SIZEOF(fsPropOffset); + bufleft -= pi->num_offsets * SIZEOF(fsPropOffset); + if (bufleft < pi->data_len) + { + ret = -1; +#ifdef DEBUG + fprintf(stderr, + "fsQueryXInfo: bufleft (%ld) < data_len (%d)\n", + bufleft, pi->data_len); +#endif + goto bail; + } pd = (pointer) buf; buf += pi->data_len; + bufleft -= pi->data_len; /* convert the properties and step over the reply */ ret = _fs_convert_props(pi, po, pd, pInfo); + bail: _fs_done_read (conn, rep->length << 2); if (ret == -1) @@ -954,13 +1033,15 @@ fs_read_extent_info(FontPathElementPtr f FontInfoRec *fi = &bfont->pfont->info; rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length < LENGTHOF(fsQueryXExtents16Reply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); fs_cleanup_bfont (bfont); + _fs_reply_failed (rep, fsQueryXExtents16Reply, "<"); return BadFontName; } @@ -973,7 +1054,26 @@ fs_read_extent_info(FontPathElementPtr f numInfos *= 2; haveInk = TRUE; } - ci = pCI = malloc(sizeof(CharInfoRec) * numInfos); + if (numInfos >= (INT_MAX / sizeof(CharInfoRec))) { +#ifdef DEBUG + fprintf(stderr, + "fsQueryXExtents16: numInfos (%d) >= %ld\n", + numInfos, (INT_MAX / sizeof(CharInfoRec))); +#endif + pCI = NULL; + } + else if (numExtents > ((rep->length - LENGTHOF(fsQueryXExtents16Reply)) + / LENGTHOF(fsXCharInfo))) { +#ifdef DEBUG + fprintf(stderr, + "fsQueryXExtents16: numExtents (%d) > (%d - %d) / %d\n", + numExtents, rep->length, + LENGTHOF(fsQueryXExtents16Reply), LENGTHOF(fsXCharInfo)); +#endif + pCI = NULL; + } + else + pCI = malloc(sizeof(CharInfoRec) * numInfos); if (!pCI) { @@ -1812,6 +1912,7 @@ fs_read_glyphs(FontPathElementPtr fpe, F FontInfoPtr pfi = &pfont->info; fsQueryXBitmaps16Reply *rep; char *buf; + long bufleft; /* length of reply left to use */ fsOffset32 *ppbits; fsOffset32 local_off; char *off_adr; @@ -1828,21 +1929,48 @@ fs_read_glyphs(FontPathElementPtr fpe, F unsigned long minchar, maxchar; rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length < LENGTHOF(fsQueryXBitmaps16Reply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); err = AllocError; + _fs_reply_failed (rep, fsQueryXBitmaps16Reply, "<"); goto bail; } buf = (char *) rep; buf += SIZEOF (fsQueryXBitmaps16Reply); + bufleft = rep->length << 2; + bufleft -= SIZEOF (fsQueryXBitmaps16Reply); + + if ((bufleft / SIZEOF (fsOffset32)) < rep->num_chars) + { +#ifdef DEBUG + fprintf(stderr, + "fsQueryXBitmaps16: num_chars (%d) > bufleft (%ld) / %d\n", + rep->num_chars, bufleft, SIZEOF (fsOffset32)); +#endif + err = AllocError; + goto bail; + } ppbits = (fsOffset32 *) buf; buf += SIZEOF (fsOffset32) * (rep->num_chars); + bufleft -= SIZEOF (fsOffset32) * (rep->num_chars); + + if (bufleft < rep->nbytes) + { +#ifdef DEBUG + fprintf(stderr, + "fsQueryXBitmaps16: nbytes (%d) > bufleft (%ld)\n", + rep->nbytes, bufleft); +#endif + err = AllocError; + goto bail; + } pbitmaps = (pointer ) buf; @@ -1901,7 +2029,9 @@ fs_read_glyphs(FontPathElementPtr fpe, F */ if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics)) { - if (local_off.length) + if (local_off.length && + (local_off.position < rep->nbytes) && + (local_off.length <= (rep->nbytes - local_off.position))) { bits = allbits; allbits += local_off.length; @@ -2231,31 +2361,48 @@ fs_read_list(FontPathElementPtr fpe, FSB FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data; fsListFontsReply *rep; char *data; + long dataleft; /* length of reply left to use */ int length, i, ret; int err; rep = (fsListFontsReply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length < LENGTHOF(fsListFontsReply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); + _fs_reply_failed (rep, fsListFontsReply, "<"); return AllocError; } data = (char *) rep + SIZEOF (fsListFontsReply); + dataleft = (rep->length << 2) - SIZEOF (fsListFontsReply); err = Successful; /* copy data into FontPathRecord */ for (i = 0; i < rep->nFonts; i++) { + if (dataleft < 1) + break; length = *(unsigned char *)data++; + dataleft--; /* used length byte */ + if (length > dataleft) { +#ifdef DEBUG + fprintf(stderr, + "fsListFonts: name length (%d) > dataleft (%ld)\n", + length, dataleft); +#endif + err = BadFontName; + break; + } err = AddFontNamesName(blist->names, data, length); if (err != Successful) break; data += length; + dataleft -= length; } _fs_done_read (conn, rep->length << 2); return err; @@ -2361,12 +2508,15 @@ fs_read_list_info(FontPathElementPtr fpe _fs_free_props (&binfo->info); rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + ((rep->nameLength != 0) && + (rep->length < LENGTHOF(fsListFontsWithXInfoReply)))) { if (ret == FSIO_BLOCK) return StillWorking; binfo->status = FS_LFWI_FINISHED; err = AllocError; + _fs_reply_failed (rep, fsListFontsWithXInfoReply, "<"); goto done; } /* @@ -2789,7 +2939,7 @@ _fs_recv_conn_setup (FSFpePtr conn) int ret = FSIO_ERROR; fsConnSetup *setup; FSFpeAltPtr alts; - int i, alt_len; + unsigned int i, alt_len; int setup_len; char *alt_save, *alt_names; @@ -2816,8 +2966,9 @@ _fs_recv_conn_setup (FSFpePtr conn) } if (setup->num_alternates) { + size_t alt_name_len = setup->alternate_len << 2; alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) + - (setup->alternate_len << 2)); + alt_name_len); if (alts) { alt_names = (char *) (setup + 1); @@ -2826,10 +2977,25 @@ _fs_recv_conn_setup (FSFpePtr conn) { alts[i].subset = alt_names[0]; alt_len = alt_names[1]; + if (alt_len >= alt_name_len) { + /* + * Length is longer than setup->alternate_len + * told us to allocate room for, assume entire + * alternate list is corrupted. + */ +#ifdef DEBUG + fprintf (stderr, + "invalid alt list (length %lx >= %lx)\n", + (long) alt_len, (long) alt_name_len); +#endif + free(alts); + return FSIO_ERROR; + } alts[i].name = alt_save; memcpy (alt_save, alt_names + 2, alt_len); alt_save[alt_len] = '\0'; alt_save += alt_len + 1; + alt_name_len -= alt_len + 1; alt_names += _fs_pad_length (alt_len + 2); } conn->numAlts = setup->num_alternates; Index: xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c diff -u xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c:1.1.1.2 xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c:1.1.1.2.4.1 --- xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c:1.1.1.2 Wed Jun 10 07:33:40 2009 +++ xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c Wed May 14 03:55:40 2014 @@ -45,6 +45,7 @@ in this Software without prior written a #include <sys/types.h> #include <sys/stat.h> #include <errno.h> +#include <limits.h> static Bool AddFileNameAliases ( FontDirectoryPtr dir ); static int ReadFontAlias ( char *directory, Bool isFile, @@ -377,6 +378,9 @@ lexAlias(FILE *file, char **lexToken) int nsize; char *nbuf; + if (tokenSize >= (INT_MAX >> 2)) + /* Stop before we overflow */ + return EALLOC; nsize = tokenSize ? (tokenSize << 1) : 64; nbuf = realloc(tokenBuf, nsize); if (!nbuf) Index: xsrc/xfree/xc/lib/font/fc/fsconvert.c diff -u xsrc/xfree/xc/lib/font/fc/fsconvert.c:1.4 xsrc/xfree/xc/lib/font/fc/fsconvert.c:1.4.28.1 --- xsrc/xfree/xc/lib/font/fc/fsconvert.c:1.4 Fri Mar 5 16:32:52 2004 +++ xsrc/xfree/xc/lib/font/fc/fsconvert.c Wed May 14 03:55:40 2014 @@ -120,6 +120,10 @@ _fs_convert_props(fsPropInfo *pi, fsProp for (i = 0; i < nprops; i++, dprop++, is_str++) { memcpy(&local_off, off_adr, SIZEOF(fsPropOffset)); + if ((local_off.name.position >= pi->data_len) || + (local_off.name.length > + (pi->data_len - local_off.name.position))) + goto bail; dprop->name = MakeAtom(&pdc[local_off.name.position], local_off.name.length, 1); if (local_off.type != PropTypeString) { @@ -127,10 +131,15 @@ _fs_convert_props(fsPropInfo *pi, fsProp dprop->value = local_off.value.position; } else { *is_str = TRUE; + if ((local_off.name.position >= pi->data_len) || + (local_off.name.length > + (pi->data_len - local_off.name.position))) + goto bail; dprop->value = (INT32) MakeAtom(&pdc[local_off.value.position], local_off.value.length, 1); if (dprop->value == BAD_RESOURCE) { + bail: xfree (pfi->props); pfi->nprops = 0; pfi->props = 0; @@ -750,7 +759,12 @@ fs_alloc_glyphs (FontPtr pFont, int size FSGlyphPtr glyphs; FSFontPtr fsfont = (FSFontPtr) pFont->fontPrivate; - glyphs = xalloc (sizeof (FSGlyphRec) + size); + if (size < (INT_MAX - sizeof (FSGlyphRec))) + glyphs = xalloc (sizeof (FSGlyphRec) + size); + else + glyphs = NULL; + if (glyphs == NULL) + return NULL; glyphs->next = fsfont->glyphs; fsfont->glyphs = glyphs; return (pointer) (glyphs + 1); Index: xsrc/xfree/xc/lib/font/fc/fserve.c diff -u xsrc/xfree/xc/lib/font/fc/fserve.c:1.4 xsrc/xfree/xc/lib/font/fc/fserve.c:1.4.28.1 --- xsrc/xfree/xc/lib/font/fc/fserve.c:1.4 Fri Mar 5 16:32:52 2004 +++ xsrc/xfree/xc/lib/font/fc/fserve.c Wed May 14 03:55:40 2014 @@ -66,6 +66,7 @@ in this Software without prior written a #include "fservestr.h" #include "fontutil.h" #include <errno.h> +#include <limits.h> #include <time.h> #define Time_t time_t @@ -87,6 +88,15 @@ in this Software without prior written a (pci)->descent || \ (pci)->characterWidth) +/* + * SIZEOF(r) is in bytes, length fields in the protocol are in 32-bit words, + * so this converts for doing size comparisons. + */ +#define LENGTHOF(r) (SIZEOF(r) >> 2) + +/* Somewhat arbitrary limit on maximum reply size we'll try to read. */ +#define MAX_REPLY_LENGTH ((64 * 1024 * 1024) >> 2) + extern void ErrorF(const char *f, ...); static int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec ); @@ -202,9 +212,22 @@ _fs_add_rep_log (FSFpePtr conn, fsGeneri rep->sequenceNumber, conn->reqbuffer[i].opcode); } + +#define _fs_reply_failed(rep, name, op) do { \ + if (rep) { \ + if (rep->type == FS_Error) \ + fprintf (stderr, "Error: %d Request: %s\n", \ + ((fsError *)rep)->request, #name); \ + else \ + fprintf (stderr, "Bad Length for %s Reply: %d %s %d\n", \ + #name, rep->length, op, LENGTHOF(name)); \ + } \ +} while (0) + #else #define _fs_add_req_log(conn,op) ((conn)->current_seq++) #define _fs_add_rep_log(conn,rep) +#define _fs_reply_failed(rep,name,op) #endif static Bool @@ -604,6 +627,21 @@ fs_get_reply (FSFpePtr conn, int *error) rep = (fsGenericReply *) buf; + /* + * Refuse to accept replies longer than a maximum reasonable length, + * before we pass to _fs_start_read, since it will try to resize the + * incoming connection buffer to this size. Also avoids integer overflow + * on 32-bit systems. + */ + if (rep->length > MAX_REPLY_LENGTH) + { + ErrorF("fserve: reply length %d > MAX_REPLY_LENGTH, disconnecting" + " from font server\n", rep->length); + _fs_connection_died (conn); + *error = FSIO_ERROR; + return 0; + } + ret = _fs_start_read (conn, rep->length << 2, &buf); if (ret != FSIO_READY) { @@ -686,13 +724,15 @@ fs_read_open_font(FontPathElementPtr fpe int ret; rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length != LENGTHOF(fsOpenBitmapFontReply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); fs_cleanup_bfont (bfont); + _fs_reply_failed (rep, fsOpenBitmapFontReply, "!="); return BadFontName; } @@ -819,6 +859,7 @@ fs_read_query_info(FontPathElementPtr fp FSFpePtr conn = (FSFpePtr) fpe->private; fsQueryXInfoReply *rep; char *buf; + long bufleft; /* length of reply left to use */ fsPropInfo *pi; fsPropOffset *po; pointer pd; @@ -828,13 +869,15 @@ fs_read_query_info(FontPathElementPtr fp int ret; rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length < LENGTHOF(fsQueryXInfoReply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); fs_cleanup_bfont (bfont); + _fs_reply_failed (rep, fsQueryXInfoReply, "<"); return BadFontName; } @@ -848,6 +891,9 @@ fs_read_query_info(FontPathElementPtr fp buf = (char *) rep; buf += SIZEOF(fsQueryXInfoReply); + bufleft = rep->length << 2; + bufleft -= SIZEOF(fsQueryXInfoReply); + /* move the data over */ fsUnpack_XFontInfoHeader(rep, pInfo); @@ -855,17 +901,50 @@ fs_read_query_info(FontPathElementPtr fp _fs_init_fontinfo(conn, pInfo); /* Compute offsets into the reply */ + if (bufleft < SIZEOF(fsPropInfo)) + { + ret = -1; +#ifdef DEBUG + fprintf(stderr, "fsQueryXInfo: bufleft (%ld) < SIZEOF(fsPropInfo)\n", + bufleft); +#endif + goto bail; + } pi = (fsPropInfo *) buf; buf += SIZEOF (fsPropInfo); - + bufleft -= SIZEOF(fsPropInfo); + + if ((bufleft / SIZEOF(fsPropOffset)) < pi->num_offsets) + { + ret = -1; +#ifdef DEBUG + fprintf(stderr, + "fsQueryXInfo: bufleft (%ld) / SIZEOF(fsPropOffset) < %d\n", + bufleft, pi->num_offsets); +#endif + goto bail; + } po = (fsPropOffset *) buf; buf += pi->num_offsets * SIZEOF(fsPropOffset); + bufleft -= pi->num_offsets * SIZEOF(fsPropOffset); + if (bufleft < pi->data_len) + { + ret = -1; +#ifdef DEBUG + fprintf(stderr, + "fsQueryXInfo: bufleft (%ld) < data_len (%d)\n", + bufleft, pi->data_len); +#endif + goto bail; + } pd = (pointer) buf; buf += pi->data_len; + bufleft -= pi->data_len; /* convert the properties and step over the reply */ ret = _fs_convert_props(pi, po, pd, pInfo); + bail: _fs_done_read (conn, rep->length << 2); if (ret == -1) @@ -955,13 +1034,15 @@ fs_read_extent_info(FontPathElementPtr f FontInfoRec *fi = &bfont->pfont->info; rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length < LENGTHOF(fsQueryXExtents16Reply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); fs_cleanup_bfont (bfont); + _fs_reply_failed (rep, fsQueryXExtents16Reply, "<"); return BadFontName; } @@ -974,7 +1055,26 @@ fs_read_extent_info(FontPathElementPtr f numInfos *= 2; haveInk = TRUE; } - ci = pCI = (CharInfoPtr) xalloc(sizeof(CharInfoRec) * numInfos); + if (numInfos >= (INT_MAX / sizeof(CharInfoRec))) { +#ifdef DEBUG + fprintf(stderr, + "fsQueryXExtents16: numInfos (%d) >= %ld\n", + numInfos, (INT_MAX / sizeof(CharInfoRec))); +#endif + pCI = NULL; + } + else if (numExtents > ((rep->length - LENGTHOF(fsQueryXExtents16Reply)) + / LENGTHOF(fsXCharInfo))) { +#ifdef DEBUG + fprintf(stderr, + "fsQueryXExtents16: numExtents (%d) > (%d - %d) / %d\n", + numExtents, rep->length, + LENGTHOF(fsQueryXExtents16Reply), LENGTHOF(fsXCharInfo)); +#endif + pCI = NULL; + } + else + pCI = (CharInfoPtr) xalloc(sizeof(CharInfoRec) * numInfos); if (!pCI) { @@ -1810,6 +1910,7 @@ fs_read_glyphs(FontPathElementPtr fpe, F FontInfoPtr pfi = &pfont->info; fsQueryXBitmaps16Reply *rep; char *buf; + long bufleft; /* length of reply left to use */ fsOffset32 *ppbits; fsOffset32 local_off; char *off_adr; @@ -1826,22 +1927,49 @@ fs_read_glyphs(FontPathElementPtr fpe, F unsigned long minchar, maxchar; rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length < LENGTHOF(fsQueryXBitmaps16Reply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); err = AllocError; + _fs_reply_failed (rep, fsQueryXBitmaps16Reply, "<"); goto bail; } buf = (char *) rep; buf += SIZEOF (fsQueryXBitmaps16Reply); + bufleft = rep->length << 2; + bufleft -= SIZEOF (fsQueryXBitmaps16Reply); + + if ((bufleft / SIZEOF (fsOffset32)) < rep->num_chars) + { +#ifdef DEBUG + fprintf(stderr, + "fsQueryXBitmaps16: num_chars (%d) > bufleft (%ld) / %d\n", + rep->num_chars, bufleft, SIZEOF (fsOffset32)); +#endif + err = AllocError; + goto bail; + } + ppbits = (fsOffset32 *) buf; buf += SIZEOF (fsOffset32) * (rep->num_chars); + bufleft -= SIZEOF (fsOffset32) * (rep->num_chars); + if (bufleft < rep->nbytes) + { +#ifdef DEBUG + fprintf(stderr, + "fsQueryXBitmaps16: nbytes (%d) > bufleft (%ld)\n", + rep->nbytes, bufleft); +#endif + err = AllocError; + goto bail; + } pbitmaps = (pointer ) buf; if (blockrec->type == FS_LOAD_GLYPHS) @@ -1899,7 +2027,9 @@ fs_read_glyphs(FontPathElementPtr fpe, F */ if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics)) { - if (local_off.length) + if (local_off.length && + (local_off.position < rep->nbytes) && + (local_off.length <= (rep->nbytes - local_off.position))) { bits = allbits; allbits += local_off.length; @@ -2230,31 +2360,48 @@ fs_read_list(FontPathElementPtr fpe, FSB FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data; fsListFontsReply *rep; char *data; + long dataleft; /* length of reply left to use */ int length, i, ret; int err; rep = (fsListFontsReply *) fs_get_reply (conn, &ret); - if (!rep || rep->type == FS_Error) + if (!rep || rep->type == FS_Error || + (rep->length < LENGTHOF(fsListFontsReply))) { if (ret == FSIO_BLOCK) return StillWorking; if (rep) _fs_done_read (conn, rep->length << 2); + _fs_reply_failed (rep, fsListFontsReply, "<"); return AllocError; } data = (char *) rep + SIZEOF (fsListFontsReply); + dataleft = (rep->length << 2) - SIZEOF (fsListFontsReply); err = Successful; /* copy data into FontPathRecord */ for (i = 0; i < rep->nFonts; i++) { + if (dataleft < 1) + break; length = *(unsigned char *)data++; + dataleft--; /* used length byte */ + if (length > dataleft) { +#ifdef DEBUG + fprintf(stderr, + "fsListFonts: name length (%d) > dataleft (%ld)\n", + length, dataleft); +#endif + err = BadFontName; + break; + } err = AddFontNamesName(blist->names, data, length); if (err != Successful) break; data += length; + dataleft -= length; } _fs_done_read (conn, rep->length << 2); return err; @@ -2348,6 +2495,7 @@ fs_read_list_info(FontPathElementPtr fpe FSBlockedListInfoPtr binfo = (FSBlockedListInfoPtr) blockrec->data; fsListFontsWithXInfoReply *rep; char *buf; + long bufleft; FSFpePtr conn = (FSFpePtr) fpe->private; fsPropInfo *pi; fsPropOffset *po; @@ -2359,12 +2507,15 @@ fs_read_list_info(FontPathElementPtr fpe _fs_free_props (&binfo->info); rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret); - if (rep == 0) + if (!rep || rep->type == FS_Error || + ((rep->nameLength != 0) && + (rep->length < LENGTHOF(fsListFontsWithXInfoReply)))) { if (ret == FSIO_BLOCK) return StillWorking; binfo->status = FS_LFWI_FINISHED; err = AllocError; + _fs_reply_failed (rep, fsListFontsWithXInfoReply, "<"); goto done; } /* @@ -2381,6 +2532,7 @@ fs_read_list_info(FontPathElementPtr fpe } buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply); + bufleft = (rep->length << 2) - SIZEOF (fsListFontsWithXInfoReply); /* * The original FS implementation didn't match @@ -2389,19 +2541,71 @@ fs_read_list_info(FontPathElementPtr fpe */ if (conn->fsMajorVersion <= 1) { + if (rep->nameLength > bufleft) { +#ifdef DEBUG + fprintf(stderr, + "fsListFontsWithXInfo: name length (%d) > bufleft (%ld)\n", + (int) rep->nameLength, bufleft); +#endif + err = AllocError; + goto done; + } + /* binfo->name is a 256 char array, rep->nameLength is a CARD8 */ memcpy (binfo->name, buf, rep->nameLength); buf += _fs_pad_length (rep->nameLength); + bufleft -= _fs_pad_length (rep->nameLength); } pi = (fsPropInfo *) buf; + if (SIZEOF (fsPropInfo) > bufleft) { +#ifdef DEBUG + fprintf(stderr, + "fsListFontsWithXInfo: PropInfo length (%d) > bufleft (%ld)\n", + (int) SIZEOF (fsPropInfo), bufleft); +#endif + err = AllocError; + goto done; + } + bufleft -= SIZEOF (fsPropInfo); buf += SIZEOF (fsPropInfo); po = (fsPropOffset *) buf; + if (pi->num_offsets > (bufleft / SIZEOF (fsPropOffset))) { +#ifdef DEBUG + fprintf(stderr, + "fsListFontsWithXInfo: offset length (%d * %d) > bufleft (%ld)\n", + pi->num_offsets, (int) SIZEOF (fsPropOffset), bufleft); +#endif + err = AllocError; + goto done; + } + bufleft -= pi->num_offsets * SIZEOF (fsPropOffset); buf += pi->num_offsets * SIZEOF (fsPropOffset); pd = (pointer) buf; + if (pi->data_len > bufleft) { +#ifdef DEBUG + fprintf(stderr, + "fsListFontsWithXInfo: data length (%d) > bufleft (%ld)\n", + pi->data_len, bufleft); +#endif + err = AllocError; + goto done; + } + bufleft -= pi->data_len; buf += pi->data_len; if (conn->fsMajorVersion > 1) { + if (rep->nameLength > bufleft) { +#ifdef DEBUG + fprintf(stderr, + "fsListFontsWithXInfo: name length (%d) > bufleft (%ld)\n", + (int) rep->nameLength, bufleft); +#endif + err = AllocError; + goto done; + } + /* binfo->name is a 256 char array, rep->nameLength is a CARD8 */ memcpy (binfo->name, buf, rep->nameLength); buf += _fs_pad_length (rep->nameLength); + bufleft -= _fs_pad_length (rep->nameLength); } #ifdef DEBUG @@ -2775,7 +2979,7 @@ _fs_recv_conn_setup (FSFpePtr conn) int ret; fsConnSetup *setup; FSFpeAltPtr alts; - int i, alt_len; + unsigned int i, alt_len; int setup_len; char *alt_save, *alt_names; @@ -2802,9 +3006,10 @@ _fs_recv_conn_setup (FSFpePtr conn) } if (setup->num_alternates) { + size_t alt_name_len = setup->alternate_len << 2; alts = (FSFpeAltPtr) xalloc (setup->num_alternates * sizeof (FSFpeAltRec) + - (setup->alternate_len << 2)); + alt_name_len); if (alts) { alt_names = (char *) (setup + 1); @@ -2813,10 +3018,25 @@ _fs_recv_conn_setup (FSFpePtr conn) { alts[i].subset = alt_names[0]; alt_len = alt_names[1]; + if (alt_len >= alt_name_len) { + /* + * Length is longer than setup->alternate_len + * told us to allocate room for, assume entire + * alternate list is corrupted. + */ +#ifdef DEBUG + fprintf (stderr, + "invalid alt list (length %lx >= %lx)\n", + (long) alt_len, (long) alt_name_len); +#endif + free(alts); + return FSIO_ERROR; + } alts[i].name = alt_save; memcpy (alt_save, alt_names + 2, alt_len); alt_save[alt_len] = '\0'; alt_save += alt_len + 1; + alt_name_len -= alt_len + 1; alt_names += _fs_pad_length (alt_len + 2); } conn->numAlts = setup->num_alternates; Index: xsrc/xfree/xc/lib/font/fontfile/dirfile.c diff -u xsrc/xfree/xc/lib/font/fontfile/dirfile.c:1.4 xsrc/xfree/xc/lib/font/fontfile/dirfile.c:1.4.16.1 --- xsrc/xfree/xc/lib/font/fontfile/dirfile.c:1.4 Fri Mar 18 14:55:10 2005 +++ xsrc/xfree/xc/lib/font/fontfile/dirfile.c Wed May 14 03:55:40 2014 @@ -42,6 +42,7 @@ in this Software without prior written a #include <sys/types.h> #include <sys/stat.h> #include <errno.h> +#include <limits.h> static Bool AddFileNameAliases ( FontDirectoryPtr dir ); static int ReadFontAlias ( char *directory, Bool isFile, @@ -369,6 +370,9 @@ lexAlias(FILE *file, char **lexToken) int nsize; char *nbuf; + if (tokenSize >= (INT_MAX >> 2)) + /* Stop before we overflow */ + return EALLOC; nsize = tokenSize ? (tokenSize << 1) : 64; nbuf = (char *) xrealloc(tokenBuf, nsize); if (!nbuf)