|
|
653d32 |
From c4685b85f61f28ea0d5cf4e41cb8feaa5193d9dd Mon Sep 17 00:00:00 2001
|
|
|
653d32 |
From: "Alan T. DeKok" <aland@freeradius.org>
|
|
|
653d32 |
Date: Tue, 27 Jun 2017 21:49:20 -0400
|
|
|
653d32 |
Subject: [PATCH] FR-GV-301 - handle malformed WiMAX attributes
|
|
|
653d32 |
|
|
|
653d32 |
---
|
|
|
653d32 |
src/lib/radius.c | 177 ++++++++++++++++++++++++++++++++++-------------
|
|
|
653d32 |
src/tests/unit/wimax.txt | 12 ++++
|
|
|
653d32 |
2 files changed, 142 insertions(+), 47 deletions(-)
|
|
|
653d32 |
|
|
|
653d32 |
diff --git a/src/lib/radius.c b/src/lib/radius.c
|
|
|
653d32 |
index 7114e1650..ea4cbf06b 100644
|
|
|
653d32 |
--- a/src/lib/radius.c
|
|
|
653d32 |
+++ b/src/lib/radius.c
|
|
|
653d32 |
@@ -3229,7 +3229,7 @@ static ssize_t data2vp_extended(TALLOC_CTX *ctx, RADIUS_PACKET *packet,
|
|
|
653d32 |
return end - data;
|
|
|
653d32 |
}
|
|
|
653d32 |
|
|
|
653d32 |
-/** Convert a Vendor-Specific WIMAX to vps
|
|
|
653d32 |
+/** Convert a Vendor-Specific WIMAX to VPs
|
|
|
653d32 |
*
|
|
|
653d32 |
* @note Called ONLY for Vendor-Specific
|
|
|
653d32 |
*/
|
|
|
653d32 |
@@ -3241,25 +3241,54 @@ static ssize_t data2vp_wimax(TALLOC_CTX *ctx,
|
|
|
653d32 |
VALUE_PAIR **pvp)
|
|
|
653d32 |
{
|
|
|
653d32 |
ssize_t rcode;
|
|
|
653d32 |
- size_t fraglen;
|
|
|
653d32 |
- bool last_frag;
|
|
|
653d32 |
+ size_t wimax_len;
|
|
|
653d32 |
+ bool more;
|
|
|
653d32 |
uint8_t *head, *tail;
|
|
|
653d32 |
- uint8_t const *frag, *end;
|
|
|
653d32 |
+ uint8_t const *attr, *end;
|
|
|
653d32 |
DICT_ATTR const *child;
|
|
|
653d32 |
|
|
|
653d32 |
- if (attrlen < 8) return -1;
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * data = VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * Not enough room for WiMAX Vendor + Wimax attr + length
|
|
|
653d32 |
+ * + continuation, it's a bad attribute.
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+ if (attrlen < 8) {
|
|
|
653d32 |
+ raw:
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * It's not a Vendor-Specific, it's unknown...
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+ child = dict_unknown_afrom_fields(ctx, PW_VENDOR_SPECIFIC, 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 |
- if (((size_t) (data[5] + 4)) != attrlen) return -1;
|
|
|
653d32 |
+ if (data[5] < 3) goto raw; /* WiMAX-Length is too small */
|
|
|
653d32 |
|
|
|
653d32 |
child = dict_attrbyvalue(data[4], vendor);
|
|
|
653d32 |
- if (!child) return -1;
|
|
|
653d32 |
+ if (!child) goto raw;
|
|
|
653d32 |
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * No continued data, just decode the attribute in place.
|
|
|
653d32 |
+ */
|
|
|
653d32 |
if ((data[6] & 0x80) == 0) {
|
|
|
653d32 |
+ if ((data[5] + 4) != attrlen) goto raw; /* WiMAX attribute doesn't fill Vendor-Specific */
|
|
|
653d32 |
+
|
|
|
653d32 |
rcode = data2vp(ctx, packet, original, secret, child,
|
|
|
653d32 |
data + 7, data[5] - 3, data[5] - 3,
|
|
|
653d32 |
pvp);
|
|
|
653d32 |
- if (rcode < 0) return -1;
|
|
|
653d32 |
- return 7 + rcode;
|
|
|
653d32 |
+
|
|
|
653d32 |
+ if ((rcode < 0) || (((size_t) rcode + 7) != attrlen)) goto raw; /* didn't decode all of the data */
|
|
|
653d32 |
+ return attrlen;
|
|
|
653d32 |
}
|
|
|
653d32 |
|
|
|
653d32 |
/*
|
|
|
653d32 |
@@ -3268,61 +3297,115 @@ static ssize_t data2vp_wimax(TALLOC_CTX *ctx,
|
|
|
653d32 |
* MUST be all of the same VSA, WiMAX, and WiMAX-attr.
|
|
|
653d32 |
*
|
|
|
653d32 |
* The first fragment doesn't have a RADIUS attribute
|
|
|
653d32 |
- * header, so it needs to be treated a little special.
|
|
|
653d32 |
+ * header.
|
|
|
653d32 |
*/
|
|
|
653d32 |
- fraglen = data[5] - 3;
|
|
|
653d32 |
- frag = data + attrlen;
|
|
|
653d32 |
+ wimax_len = 0;
|
|
|
653d32 |
+ attr = data + 4;
|
|
|
653d32 |
end = data + packetlen;
|
|
|
653d32 |
- last_frag = false;
|
|
|
653d32 |
|
|
|
653d32 |
- while (frag < end) {
|
|
|
653d32 |
- if (last_frag ||
|
|
|
653d32 |
- (frag[0] != PW_VENDOR_SPECIFIC) ||
|
|
|
653d32 |
- (frag[1] < 9) || /* too short for wimax */
|
|
|
653d32 |
- ((frag + frag[1]) > end) || /* overflow */
|
|
|
653d32 |
- (memcmp(frag + 2, data, 4) != 0) || /* not wimax */
|
|
|
653d32 |
- (frag[6] != data[4]) || /* not the same wimax attr */
|
|
|
653d32 |
- ((frag[7] + 6) != frag[1])) { /* doesn't fill the attr */
|
|
|
653d32 |
- end = frag;
|
|
|
653d32 |
- break;
|
|
|
653d32 |
- }
|
|
|
653d32 |
+ while (attr < end) {
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * Not enough room for Attribute + length +
|
|
|
653d32 |
+ * continuation, it's bad.
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+ if ((end - attr) < 3) goto raw;
|
|
|
653d32 |
|
|
|
653d32 |
- last_frag = ((frag[8] & 0x80) == 0);
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * Must have non-zero data in the attribute.
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+ if (attr[1] <= 3) goto raw;
|
|
|
653d32 |
|
|
|
653d32 |
- fraglen += frag[7] - 3;
|
|
|
653d32 |
- frag += frag[1];
|
|
|
653d32 |
- }
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * If the WiMAX attribute overflows the packet,
|
|
|
653d32 |
+ * it's bad.
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+ if ((attr + attr[1]) > end) goto raw;
|
|
|
653d32 |
|
|
|
653d32 |
- head = tail = malloc(fraglen);
|
|
|
653d32 |
- if (!head) return -1;
|
|
|
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 |
+ wimax_len += attr[1] - 3;
|
|
|
653d32 |
+
|
|
|
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 |
+ * data = VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
|
|
|
653d32 |
+ *
|
|
|
653d32 |
+ * attr = Vendor-Specific VSA-Length VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
|
|
|
653d32 |
+ *
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * No room for Vendor-Specific + length +
|
|
|
653d32 |
+ * Vendor(4) + attr + length + continuation + data
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+ if ((end - attr) < 9) goto raw;
|
|
|
653d32 |
+
|
|
|
653d32 |
+ if (attr[0] != PW_VENDOR_SPECIFIC) goto raw;
|
|
|
653d32 |
+ if (attr[1] < 9) goto raw;
|
|
|
653d32 |
+ if ((attr + attr[1]) > end) goto raw;
|
|
|
653d32 |
+ if (memcmp(data, attr + 2, 4) != 0) goto raw; /* not WiMAX Vendor ID */
|
|
|
653d32 |
+
|
|
|
653d32 |
+ if (attr[1] != (attr[7] + 6)) goto raw; /* WiMAX attr doesn't exactly fill the VSA */
|
|
|
653d32 |
+
|
|
|
653d32 |
+ if (data[4] != attr[6]) goto raw; /* different WiMAX attribute */
|
|
|
653d32 |
+
|
|
|
653d32 |
+ /*
|
|
|
653d32 |
+ * Skip over the Vendor-Specific header, and
|
|
|
653d32 |
+ * continue with the WiMAX attributes.
|
|
|
653d32 |
+ */
|
|
|
653d32 |
+ attr += 6;
|
|
|
653d32 |
+ }
|
|
|
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 |
+ * No data in the WiMAX attribute, make a "raw" one.
|
|
|
653d32 |
*/
|
|
|
653d32 |
- frag = data;
|
|
|
653d32 |
+ if (!wimax_len) goto raw;
|
|
|
653d32 |
|
|
|
653d32 |
- memcpy(tail, frag + 4 + 3, frag[4 + 1] - 3);
|
|
|
653d32 |
- tail += frag[4 + 1] - 3;
|
|
|
653d32 |
- frag += attrlen; /* should be frag[1] - 7 */
|
|
|
653d32 |
+ head = tail = malloc(wimax_len);
|
|
|
653d32 |
+ if (!head) return -1;
|
|
|
653d32 |
|
|
|
653d32 |
/*
|
|
|
653d32 |
- * frag now points to RADIUS attributes
|
|
|
653d32 |
+ * Copy the data over, this time trusting the attribute
|
|
|
653d32 |
+ * contents.
|
|
|
653d32 |
*/
|
|
|
653d32 |
- do {
|
|
|
653d32 |
- memcpy(tail, frag + 2 + 4 + 3, frag[2 + 4 + 1] - 3);
|
|
|
653d32 |
- tail += frag[2 + 4 + 1] - 3;
|
|
|
653d32 |
- frag += frag[1];
|
|
|
653d32 |
- } while (frag < end);
|
|
|
653d32 |
+ attr = data;
|
|
|
653d32 |
+ while (attr < end) {
|
|
|
653d32 |
+ memcpy(tail, attr + 4 + 3, attr[4 + 1] - 3);
|
|
|
653d32 |
+ tail += attr[4 + 1] - 3;
|
|
|
653d32 |
+ attr += 4 + attr[4 + 1]; /* skip VID+WiMax header */
|
|
|
653d32 |
+ attr += 2; /* skip Vendor-Specific header */
|
|
|
653d32 |
+ }
|
|
|
653d32 |
|
|
|
653d32 |
- VP_HEXDUMP("wimax fragments", head, fraglen);
|
|
|
653d32 |
+ VP_HEXDUMP("wimax fragments", head, wimax_len);
|
|
|
653d32 |
|
|
|
653d32 |
rcode = data2vp(ctx, packet, original, secret, child,
|
|
|
653d32 |
- head, fraglen, fraglen, pvp);
|
|
|
653d32 |
+ head, wimax_len, wimax_len, pvp);
|
|
|
653d32 |
free(head);
|
|
|
653d32 |
- if (rcode < 0) return rcode;
|
|
|
653d32 |
+ if (rcode < 0) goto raw;
|
|
|
653d32 |
|
|
|
653d32 |
return end - data;
|
|
|
653d32 |
}
|
|
|
653d32 |
diff --git a/src/tests/unit/wimax.txt b/src/tests/unit/wimax.txt
|
|
|
653d32 |
index 191b37e25..6e373d59a 100644
|
|
|
653d32 |
--- a/src/tests/unit/wimax.txt
|
|
|
653d32 |
+++ b/src/tests/unit/wimax.txt
|
|
|
653d32 |
@@ -7,6 +7,12 @@ data 1a 0e 00 00 60 b5 01 08 00 01 05 31 2e 30
|
|
|
653d32 |
decode -
|
|
|
653d32 |
data WiMAX-Release = "1.0"
|
|
|
653d32 |
|
|
|
653d32 |
+decode 1a 08 00 00 60 b5 01 02
|
|
|
653d32 |
+data Attr-26 = 0x000060b50102
|
|
|
653d32 |
+
|
|
|
653d32 |
+decode 1a 0a 00 00 60 b5 01 04 00 01
|
|
|
653d32 |
+data Attr-26.24757.1 = 0x01
|
|
|
653d32 |
+
|
|
|
653d32 |
encode WiMAX-Accounting-Capabilities = 1
|
|
|
653d32 |
data 1a 0c 00 00 60 b5 01 06 00 02 03 01
|
|
|
653d32 |
|
|
|
653d32 |
@@ -143,3 +149,9 @@ data 1a ff 00 00 60 b5 01 f9 80 01 ff 45 45 45 45 45 45 45 45 45 45 45 45 45 45
|
|
|
653d32 |
|
|
|
653d32 |
decode -
|
|
|
653d32 |
data WiMAX-Release = "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", WiMAX-Idle-Mode-Notification-Cap = Supported
|
|
|
653d32 |
+
|
|
|
653d32 |
+#
|
|
|
653d32 |
+# Continuation is set, but there's no continued data.
|
|
|
653d32 |
+decode 1a 0b 00 00 60 b5 31 05 80 00 00
|
|
|
653d32 |
+data Attr-26 = 0x000060b53105800000
|
|
|
653d32 |
+
|
|
|
653d32 |
--
|
|
|
653d32 |
2.13.2
|
|
|
653d32 |
|