Blame SOURCES/freeradius-make-data2vp_extended-be-more-like-data2vp_wimax.patch

653d32
From 87390bfe6d266ab81312e072759203ccbb261906 Mon Sep 17 00:00:00 2001
653d32
From: "Alan T. DeKok" <aland@freeradius.org>
653d32
Date: Wed, 28 Jun 2017 12:13:03 -0400
653d32
Subject: [PATCH] make data2vp_extended() be more like data2vp_wimax()
653d32
653d32
There is no exploit, but making the code simpler is good.
653d32
---
653d32
 src/lib/radius.c            | 170 ++++++++++++++++++++++++++++++--------------
653d32
 src/tests/unit/extended.txt |   2 +-
653d32
 2 files changed, 116 insertions(+), 56 deletions(-)
653d32
653d32
diff --git a/src/lib/radius.c b/src/lib/radius.c
653d32
index ea4cbf06b..b9f0f59c9 100644
653d32
--- a/src/lib/radius.c
653d32
+++ b/src/lib/radius.c
653d32
@@ -3161,70 +3161,143 @@ static ssize_t data2vp_extended(TALLOC_CTX *ctx, RADIUS_PACKET *packet,
653d32
 				VALUE_PAIR **pvp)
653d32
 {
653d32
 	ssize_t rcode;
653d32
-	size_t fraglen;
653d32
+	size_t ext_len;
653d32
+	bool more;
653d32
 	uint8_t *head, *tail;
653d32
-	uint8_t const *frag, *end;
653d32
-	uint8_t const *attr;
653d32
-	int fragments;
653d32
-	bool last_frag;
653d32
+	uint8_t const *attr, *end;
653d32
+	DICT_ATTR const *child;
653d32
+
653d32
+	/*
653d32
+	 *	data = Ext-Attr Flag ...
653d32
+	 */
653d32
+
653d32
+	/*
653d32
+	 *	Not enough room for Ext-Attr + Flag + data, it's a bad
653d32
+	 *	attribute.
653d32
+	 */
653d32
+	if (attrlen < 3) {
653d32
+	raw:
653d32
+		/*
653d32
+		 *	It's not an Extended attribute, it's unknown...
653d32
+		 */
653d32
+		child = dict_unknown_afrom_fields(ctx, (da->vendor/ FR_MAX_VENDOR) & 0xff, 0);
653d32
+		if (!child) {
653d32
+			fr_strerror_printf("Internal sanity check %d", __LINE__);
653d32
+			return -1;
653d32
+		}
653d32
+
653d32
+		rcode = data2vp(ctx, packet, original, secret, child,
653d32
+				data, attrlen, attrlen, pvp);
653d32
+		if (rcode < 0) return rcode;
653d32
+		return attrlen;
653d32
+	}
653d32
+
653d32
+	/*
653d32
+	 *	No continued data, just decode the attribute in place.
653d32
+	 */
653d32
+	if ((data[1] & 0x80) == 0) {
653d32
+		rcode = data2vp(ctx, packet, original, secret, da,
653d32
+				data + 2, attrlen - 2, attrlen - 2,
653d32
+				pvp);
653d32
 
653d32
-	if (attrlen < 3) return -1;
653d32
+		if ((rcode < 0) || (((size_t) rcode + 2) != attrlen)) goto raw; /* didn't decode all of the data */
653d32
+		return attrlen;
653d32
+	}
653d32
+
653d32
+	/*
653d32
+	 *	It's continued, but there are no subsequent fragments,
653d32
+	 *	it's bad.
653d32
+	 */
653d32
+	if (attrlen >= packetlen) goto raw;
653d32
 
653d32
 	/*
653d32
 	 *	Calculate the length of all of the fragments.  For
653d32
 	 *	now, they MUST be contiguous in the packet, and they
653d32
-	 *	MUST be all of the same TYPE and EXTENDED-TYPE
653d32
+	 *	MUST be all of the same Type and Ext-Type
653d32
+	 *
653d32
+	 *	We skip the first fragment, which doesn't have a
653d32
+	 *	RADIUS attribute header.
653d32
 	 */
653d32
-	attr = data - 2;
653d32
-	fraglen = attrlen - 2;
653d32
-	frag = data + attrlen;
653d32
+	ext_len = attrlen - 2;
653d32
+	attr = data + attrlen;
653d32
 	end = data + packetlen;
653d32
-	fragments = 1;
653d32
-	last_frag = false;
653d32
-
653d32
-	while (frag < end) {
653d32
-		if (last_frag ||
653d32
-		    (frag[0] != attr[0]) ||
653d32
-		    (frag[1] < 4) ||		       /* too short for long-extended */
653d32
-		    (frag[2] != attr[2]) ||
653d32
-		    ((frag + frag[1]) > end)) {		/* overflow */
653d32
-			end = frag;
653d32
-			break;
653d32
-		}
653d32
 
653d32
-		last_frag = ((frag[3] & 0x80) == 0);
653d32
+	while (attr < end) {
653d32
+		/*
653d32
+		 *	Not enough room for Attr + length + Ext-Attr
653d32
+		 *	continuation, it's bad.
653d32
+		 */
653d32
+		if ((end - attr) < 4) goto raw;
653d32
+
653d32
+		if (attr[1] < 4) goto raw;
653d32
+
653d32
+		/*
653d32
+		 *	If the attribute overflows the packet, it's
653d32
+		 *	bad.
653d32
+		 */
653d32
+		if ((attr + attr[1]) > end) goto raw;
653d32
+
653d32
+		if (attr[0] != ((da->vendor / FR_MAX_VENDOR) & 0xff)) goto raw; /* not the same Extended-Attribute-X */
653d32
+
653d32
+		if (attr[2] != data[0]) goto raw; /* Not the same Ext-Attr */
653d32
+
653d32
+		/*
653d32
+		 *	Check the continuation flag.
653d32
+		 */
653d32
+		more = ((attr[2] & 0x80) != 0);
653d32
+
653d32
+		/*
653d32
+		 *	Or, there's no more data, in which case we
653d32
+		 *	shorten "end" to finish at this attribute.
653d32
+		 */
653d32
+		if (!more) end = attr + attr[1];
653d32
+
653d32
+		/*
653d32
+		 *	There's more data, but we're at the end of the
653d32
+		 *	packet.  The attribute is malformed!
653d32
+		 */
653d32
+		if (more && ((attr + attr[1]) == end)) goto raw;
653d32
+
653d32
+		/*
653d32
+		 *	Add in the length of the data we need to
653d32
+		 *	concatenate together.
653d32
+		 */
653d32
+		ext_len += attr[1] - 4;
653d32
 
653d32
-		fraglen += frag[1] - 4;
653d32
-		frag += frag[1];
653d32
-		fragments++;
653d32
+		/*
653d32
+		 *	Go to the next attribute, and stop if there's
653d32
+		 *	no more.
653d32
+		 */
653d32
+		attr += attr[1];
653d32
+		if (!more) break;
653d32
 	}
653d32
 
653d32
-	head = tail = malloc(fraglen);
653d32
-	if (!head) return -1;
653d32
+	if (!ext_len) goto raw;
653d32
 
653d32
-	VP_TRACE("Fragments %d, total length %d\n", fragments, (int) fraglen);
653d32
+	head = tail = malloc(ext_len);
653d32
+	if (!head) goto raw;
653d32
 
653d32
 	/*
653d32
-	 *	And again, but faster and looser.
653d32
-	 *
653d32
-	 *	We copy the first fragment, followed by the rest of
653d32
-	 *	the fragments.
653d32
+	 *	Copy the data over, this time trusting the attribute
653d32
+	 *	contents.
653d32
 	 */
653d32
-	frag = attr;
653d32
+	attr = data;
653d32
+	memcpy(tail, attr + 2, attrlen - 2);
653d32
+	tail += attrlen - 2;
653d32
+	attr += attrlen;
653d32
 
653d32
-	while (fragments >  0) {
653d32
-		memcpy(tail, frag + 4, frag[1] - 4);
653d32
-		tail += frag[1] - 4;
653d32
-		frag += frag[1];
653d32
-		fragments--;
653d32
+	while (attr < end) {
653d32
+		memcpy(tail, attr + 4, attr[1] - 4);
653d32
+		tail += attr[1] - 4;
653d32
+		attr += attr[1]; /* skip VID+WiMax header */
653d32
 	}
653d32
 
653d32
-	VP_HEXDUMP("long-extended fragments", head, fraglen);
653d32
+	VP_HEXDUMP("long-extended fragments", head, ext_len);
653d32
 
653d32
 	rcode = data2vp(ctx, packet, original, secret, da,
653d32
-			head, fraglen, fraglen, pvp);
653d32
+			head, ext_len, ext_len, pvp);
653d32
 	free(head);
653d32
-	if (rcode < 0) return rcode;
653d32
+	if (rcode < 0) goto raw;
653d32
 
653d32
 	return end - data;
653d32
 }
653d32
@@ -3827,19 +3900,6 @@ ssize_t data2vp(TALLOC_CTX *ctx,
653d32
 		}
653d32
 
653d32
 		/*
653d32
-		 *	If there no more fragments, then the contents
653d32
-		 *	have to be a well-known data type.
653d32
-		 *
653d32
-		 */
653d32
-		if ((data[1] & 0x80) == 0) {
653d32
-			rcode = data2vp(ctx, packet, original, secret, child,
653d32
-					data + 2, attrlen - 2, attrlen - 2,
653d32
-					pvp);
653d32
-			if (rcode < 0) goto raw;
653d32
-			return 2 + rcode;
653d32
-		}
653d32
-
653d32
-		/*
653d32
 		 *	This requires a whole lot more work.
653d32
 		 */
653d32
 		return data2vp_extended(ctx, packet, original, secret, child,
653d32
diff --git a/src/tests/unit/extended.txt b/src/tests/unit/extended.txt
653d32
index 8b0e3a2c4..9810b194c 100644
653d32
--- a/src/tests/unit/extended.txt
653d32
+++ b/src/tests/unit/extended.txt
653d32
@@ -80,7 +80,7 @@ data Attr-245.26.1.6 = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
653d32
 
653d32
 # again, but the second one attr is not an extended attr
653d32
 decode f5 ff 1a 80 00 00 00 01 06 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ab bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb 01 05 62 6f 62
653d32
-data Attr-245.26.1.6 = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, User-Name = "bob"
653d32
+data Attr-245 = 0x1a800000000106aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, User-Name = "bob"
653d32
 
653d32
 # No data means that the attribute is an "invalid attribute"
653d32
 decode f5 04 01 00
653d32
-- 
653d32
2.13.2
653d32