Module Name:    xsrc
Committed By:   spz
Date:           Tue May 13 15:17:33 UTC 2014

Modified Files:
        xsrc/external/mit/libXfont/dist/src/fc: fsconvert.c fserve.c
        xsrc/external/mit/libXfont/dist/src/fontfile: dirfile.c
        xsrc/xfree/xc/lib/font/fc: fsconvert.c fserve.c
        xsrc/xfree/xc/lib/font/fontfile: dirfile.c

Log Message:
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.3 -r1.2 \
    xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c \
    xsrc/external/mit/libXfont/dist/src/fc/fserve.c
cvs rdiff -u -r1.1.1.3 -r1.2 \
    xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c
cvs rdiff -u -r1.4 -r1.5 xsrc/xfree/xc/lib/font/fc/fsconvert.c \
    xsrc/xfree/xc/lib/font/fc/fserve.c
cvs rdiff -u -r1.4 -r1.5 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.3 xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c:1.2
--- xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c:1.1.1.3	Fri May 31 01:08:57 2013
+++ xsrc/external/mit/libXfont/dist/src/fc/fsconvert.c	Tue May 13 15:17:33 2014
@@ -118,6 +118,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) {
@@ -125,10 +129,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;
@@ -712,7 +721,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.3 xsrc/external/mit/libXfont/dist/src/fc/fserve.c:1.2
--- xsrc/external/mit/libXfont/dist/src/fc/fserve.c:1.1.1.3	Fri May 31 01:08:57 2013
+++ xsrc/external/mit/libXfont/dist/src/fc/fserve.c	Tue May 13 15:17:33 2014
@@ -70,6 +70,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
@@ -91,6 +92,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 );
@@ -206,9 +216,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
@@ -600,6 +623,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)
     {
@@ -682,13 +720,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;
     }
 
@@ -815,6 +855,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;
@@ -824,13 +865,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;
     }
 
@@ -844,6 +887,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);
 
@@ -851,17 +897,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)
@@ -951,13 +1030,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;
     }
 
@@ -970,7 +1051,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)
     {
@@ -1809,6 +1909,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;
@@ -1825,21 +1926,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;
 
@@ -1898,7 +2026,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;
@@ -2228,31 +2358,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;
@@ -2358,12 +2505,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;
     }
     /*
@@ -2786,7 +2936,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;
 
@@ -2813,8 +2963,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);
@@ -2823,10 +2974,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.3 xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c:1.2
--- xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c:1.1.1.3	Fri May 31 01:08:57 2013
+++ xsrc/external/mit/libXfont/dist/src/fontfile/dirfile.c	Tue May 13 15:17:33 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,
@@ -374,6 +375,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.5
--- 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	Tue May 13 15:17:33 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.5
--- 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	Tue May 13 15:17:33 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.5
--- 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	Tue May 13 15:17:33 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)

Reply via email to