From 6df8a63d34b7514077188e2062a13774f920c085 Mon Sep 17 00:00:00 2001
From: Alan Coopersmith <alan.coopersmith@oracle.com>
Date: Fri, 1 Mar 2013 21:05:27 -0800
Subject: [PATCH] integer overflow in _XQueryFont() on 32-bit platforms
 [CVE-2013-1981 1/13]

If the CARD32 reply.nCharInfos * sizeof(XCharStruct) overflows an
unsigned long, then too small of a buffer will be allocated for the
data copied in from the reply.

v2: Fix reply_left calculations, check calculated sizes fit in reply_left

Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
---
 src/Font.c | 35 +++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 12 deletions(-)

Index: libX11-1.1.5/src/Font.c
===================================================================
--- libX11-1.1.5.orig/src/Font.c
+++ libX11-1.1.5/src/Font.c
@@ -34,6 +34,7 @@ authorization from the X Consortium and
 #include <config.h>
 #endif
 #include "Xlibint.h"
+#include <limits.h>
 
 #if defined(XF86BIGFONT) && !defined(MUSTCOPY)
 #define USE_XF86BIGFONT
@@ -52,6 +53,7 @@ authorization from the X Consortium and
 
 #include "Xlcint.h"
 #include "XlcPubI.h"
+#include "eat.h"
 
 
 static XFontStruct *_XQueryFont(
@@ -186,7 +188,8 @@ _XQueryFont (
     unsigned long seq)
 {
     register XFontStruct *fs;
-    register long nbytes;
+    unsigned long nbytes;
+    unsigned long reply_left; /* unused data words left in reply buffer */
     xQueryFontReply reply;
     register xResourceReq *req;
     register _XExtension *ext;
@@ -214,9 +217,10 @@ _XQueryFont (
     }
     if (seq)
 	DeqAsyncHandler(dpy, &async);
+    reply_left = reply.length -
+	((SIZEOF(xQueryFontReply) - SIZEOF(xReply)) >> 2);
     if (! (fs = (XFontStruct *) Xmalloc (sizeof (XFontStruct)))) {
-	_XEatData(dpy, (unsigned long)(reply.nFontProps * SIZEOF(xFontProp) +
-				       reply.nCharInfos * SIZEOF(xCharInfo)));
+	_XEatDataWords(dpy, reply_left);
 	return (XFontStruct *)NULL;
     }
     fs->ext_data 		= NULL;
@@ -264,16 +268,19 @@ _XQueryFont (
      */
     fs->properties = NULL;
     if (fs->n_properties > 0) {
-	    nbytes = reply.nFontProps * sizeof(XFontProp);
-	    fs->properties = (XFontProp *) Xmalloc ((unsigned) nbytes);
+	    /* nFontProps is a CARD16 */
 	    nbytes = reply.nFontProps * SIZEOF(xFontProp);
+	    if ((nbytes >> 2) <= reply_left) {
+		size_t pbytes = reply.nFontProps * sizeof(XFontProp);
+		fs->properties = Xmalloc (pbytes);
+	    }
 	    if (! fs->properties) {
 		Xfree((char *) fs);
-		_XEatData(dpy, (unsigned long)
-			  (nbytes + reply.nCharInfos * SIZEOF(xCharInfo)));
+		_XEatDataWords(dpy, reply_left);
 		return (XFontStruct *)NULL;
 	    }
 	    _XRead32 (dpy, (long *)fs->properties, nbytes);
+	    reply_left -= (nbytes >> 2);
     }
     /*
      * If no characters in font, then it is a bad font, but
@@ -282,12 +289,18 @@ _XQueryFont (
     /* have to unpack charinfos on some machines (CRAY) */
     fs->per_char = NULL;
     if (reply.nCharInfos > 0){
-	nbytes = reply.nCharInfos * sizeof(XCharStruct);
-	if (! (fs->per_char = (XCharStruct *) Xmalloc ((unsigned) nbytes))) {
+	/* nCharInfos is a CARD32 */
+	if (reply.nCharInfos < (INT_MAX / sizeof(XCharStruct))) {
+	    nbytes = reply.nCharInfos * SIZEOF(xCharInfo);
+	    if ((nbytes >> 2) <= reply_left) {
+		size_t cibytes = reply.nCharInfos * sizeof(XCharStruct);
+		fs->per_char = Xmalloc (cibytes);
+	    }
+	}
+	if (! fs->per_char) {
 	    if (fs->properties) Xfree((char *) fs->properties);
 	    Xfree((char *) fs);
-	    _XEatData(dpy, (unsigned long)
-			    (reply.nCharInfos * SIZEOF(xCharInfo)));
+	    _XEatDataWords(dpy, reply_left);
 	    return (XFontStruct *)NULL;
 	}
 	    
@@ -309,7 +322,6 @@ _XQueryFont (
 	    }
 	}
 #else
-	nbytes = reply.nCharInfos * SIZEOF(xCharInfo);
 	_XRead16 (dpy, (char *)fs->per_char, nbytes);
 #endif
     }
Index: libX11-1.1.5/src/eat.h
===================================================================
--- /dev/null
+++ libX11-1.1.5/src/eat.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef HAVE__XEATDATAWORDS
+#include <X11/Xmd.h>  /* for LONG64 on 64-bit platforms */
+#include <limits.h>
+
+static inline void _XEatDataWords(Display *dpy, unsigned long n)
+{
+# ifndef LONG64
+    if (n >= (ULONG_MAX >> 2))
+        _XIOError(dpy);
+# endif
+    _XEatData (dpy, n << 2);
+}
+#endif
