Blame SOURCES/0006-CVE-2014-0210-unvalidated-length-fields-in-fs_read_q.patch

cf1e18
From 491291cabf78efdeec8f18b09e14726a9030cc8f Mon Sep 17 00:00:00 2001
cf1e18
From: Alan Coopersmith <alan.coopersmith@oracle.com>
cf1e18
Date: Fri, 25 Apr 2014 23:02:34 -0700
cf1e18
Subject: [PATCH 06/12] CVE-2014-0210: unvalidated length fields in fs_read_query_info()
cf1e18
cf1e18
fs_read_query_info() parses a reply from the font server.  The reply
cf1e18
contains embedded length fields, none of which are validated.  This
cf1e18
can cause out of bound reads in either fs_read_query_info() or in
cf1e18
_fs_convert_props() which it calls to parse the fsPropInfo in the reply.
cf1e18
cf1e18
Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
cf1e18
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
cf1e18
Reviewed-by: Adam Jackson <ajax@redhat.com>
cf1e18
Reviewed-by: Matthieu Herrb <matthieu@herrb.eu>
cf1e18
---
cf1e18
 src/fc/fsconvert.c |    9 +++++++++
cf1e18
 src/fc/fserve.c    |   37 +++++++++++++++++++++++++++++++++++++
cf1e18
 2 files changed, 46 insertions(+), 0 deletions(-)
cf1e18
cf1e18
diff --git a/src/fc/fsconvert.c b/src/fc/fsconvert.c
cf1e18
index 75b5372..dfa1317 100644
cf1e18
--- a/src/fc/fsconvert.c
cf1e18
+++ b/src/fc/fsconvert.c
cf1e18
@@ -118,6 +118,10 @@ _fs_convert_props(fsPropInfo *pi, fsPropOffset *po, pointer pd,
cf1e18
     for (i = 0; i < nprops; i++, dprop++, is_str++)
cf1e18
     {
cf1e18
 	memcpy(&local_off, off_adr, SIZEOF(fsPropOffset));
cf1e18
+	if ((local_off.name.position >= pi->data_len) ||
cf1e18
+		(local_off.name.length >
cf1e18
+		 (pi->data_len - local_off.name.position)))
cf1e18
+	    goto bail;
cf1e18
 	dprop->name = MakeAtom(&pdc[local_off.name.position],
cf1e18
 			       local_off.name.length, 1);
cf1e18
 	if (local_off.type != PropTypeString) {
cf1e18
@@ -125,10 +129,15 @@ _fs_convert_props(fsPropInfo *pi, fsPropOffset *po, pointer pd,
cf1e18
 	    dprop->value = local_off.value.position;
cf1e18
 	} else {
cf1e18
 	    *is_str = TRUE;
cf1e18
+	    if ((local_off.value.position >= pi->data_len) ||
cf1e18
+		(local_off.value.length >
cf1e18
+		 (pi->data_len - local_off.value.position)))
cf1e18
+		goto bail;
cf1e18
 	    dprop->value = (INT32) MakeAtom(&pdc[local_off.value.position],
cf1e18
 					    local_off.value.length, 1);
cf1e18
 	    if (dprop->value == BAD_RESOURCE)
cf1e18
 	    {
cf1e18
+	      bail:
cf1e18
 		free (pfi->props);
cf1e18
 		pfi->nprops = 0;
cf1e18
 		pfi->props = 0;
cf1e18
diff --git a/src/fc/fserve.c b/src/fc/fserve.c
cf1e18
index 3abbacf..ec5336e 100644
cf1e18
--- a/src/fc/fserve.c
cf1e18
+++ b/src/fc/fserve.c
cf1e18
@@ -854,6 +854,7 @@ fs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
cf1e18
     FSFpePtr		conn = (FSFpePtr) fpe->private;
cf1e18
     fsQueryXInfoReply	*rep;
cf1e18
     char		*buf;
cf1e18
+    long		bufleft; /* length of reply left to use */
cf1e18
     fsPropInfo		*pi;
cf1e18
     fsPropOffset	*po;
cf1e18
     pointer		pd;
cf1e18
@@ -885,6 +886,9 @@ fs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
cf1e18
     buf = (char *) rep;
cf1e18
     buf += SIZEOF(fsQueryXInfoReply);
cf1e18
 
cf1e18
+    bufleft = rep->length << 2;
cf1e18
+    bufleft -= SIZEOF(fsQueryXInfoReply);
cf1e18
+
cf1e18
     /* move the data over */
cf1e18
     fsUnpack_XFontInfoHeader(rep, pInfo);
cf1e18
 
cf1e18
@@ -892,17 +896,50 @@ fs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
cf1e18
     _fs_init_fontinfo(conn, pInfo);
cf1e18
 
cf1e18
     /* Compute offsets into the reply */
cf1e18
+    if (bufleft < SIZEOF(fsPropInfo))
cf1e18
+    {
cf1e18
+	ret = -1;
cf1e18
+#ifdef DEBUG
cf1e18
+	fprintf(stderr, "fsQueryXInfo: bufleft (%ld) < SIZEOF(fsPropInfo)\n",
cf1e18
+		bufleft);
cf1e18
+#endif
cf1e18
+	goto bail;
cf1e18
+    }
cf1e18
     pi = (fsPropInfo *) buf;
cf1e18
     buf += SIZEOF (fsPropInfo);
cf1e18
+    bufleft -= SIZEOF(fsPropInfo);
cf1e18
 
cf1e18
+    if ((bufleft / SIZEOF(fsPropOffset)) < pi->num_offsets)
cf1e18
+    {
cf1e18
+	ret = -1;
cf1e18
+#ifdef DEBUG
cf1e18
+	fprintf(stderr,
cf1e18
+		"fsQueryXInfo: bufleft (%ld) / SIZEOF(fsPropOffset) < %d\n",
cf1e18
+		bufleft, pi->num_offsets);
cf1e18
+#endif
cf1e18
+	goto bail;
cf1e18
+    }
cf1e18
     po = (fsPropOffset *) buf;
cf1e18
     buf += pi->num_offsets * SIZEOF(fsPropOffset);
cf1e18
+    bufleft -= pi->num_offsets * SIZEOF(fsPropOffset);
cf1e18
 
cf1e18
+    if (bufleft < pi->data_len)
cf1e18
+    {
cf1e18
+	ret = -1;
cf1e18
+#ifdef DEBUG
cf1e18
+	fprintf(stderr,
cf1e18
+		"fsQueryXInfo: bufleft (%ld) < data_len (%d)\n",
cf1e18
+		bufleft, pi->data_len);
cf1e18
+#endif
cf1e18
+	goto bail;
cf1e18
+    }
cf1e18
     pd = (pointer) buf;
cf1e18
     buf += pi->data_len;
cf1e18
+    bufleft -= pi->data_len;
cf1e18
 
cf1e18
     /* convert the properties and step over the reply */
cf1e18
     ret = _fs_convert_props(pi, po, pd, pInfo);
cf1e18
+  bail:
cf1e18
     _fs_done_read (conn, rep->length << 2);
cf1e18
 
cf1e18
     if (ret == -1)
cf1e18
-- 
cf1e18
1.7.1
cf1e18