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

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