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

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