26c0d4
From: Antonio Torres <antorres@redhat.com>
26c0d4
Date: Fri, 09 Dec 2022
26c0d4
Subject: Fix crash on unknown option in EAP-SIM
26c0d4
26c0d4
When an EAP-SIM supplicant sends an unknown SIM option, the server will try to
26c0d4
look that option up in the internal dictionaries. This lookup will fail, but the
26c0d4
SIM code will not check for that failure. Instead, it will dereference a NULL
26c0d4
pointer, and cause the server to crash.
26c0d4
26c0d4
Backport of:
26c0d4
https://github.com/FreeRADIUS/freeradius-server/commit/f1cdbb33ec61c4a64a
26c0d4
https://github.com/FreeRADIUS/freeradius-server/commit/71128cac3ee236a88a05cc7bddd43e43a88a3089
26c0d4
26c0d4
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2151704
26c0d4
Signed-off-by: Antonio Torres <antorres@redhat.com>
26c0d4
---
26c0d4
diff --git a/src/modules/rlm_eap/libeap/eapsimlib.c b/src/modules/rlm_eap/libeap/eapsimlib.c
26c0d4
index cf1e8a7dd92..e438a844eab 100644
26c0d4
--- a/src/modules/rlm_eap/libeap/eapsimlib.c
26c0d4
+++ b/src/modules/rlm_eap/libeap/eapsimlib.c
26c0d4
@@ -307,42 +307,77 @@ int unmap_eapsim_basictypes(RADIUS_PACKET *r,
26c0d4
 	newvp->vp_length = 1;
26c0d4
 	fr_pair_add(&(r->vps), newvp);
26c0d4
 
26c0d4
+	/*
26c0d4
+	 *	EAP-SIM has a 1 octet of subtype, and 2 octets
26c0d4
+	 *	reserved.
26c0d4
+	 */
26c0d4
 	attr     += 3;
26c0d4
 	attrlen  -= 3;
26c0d4
 
26c0d4
-	/* now, loop processing each attribute that we find */
26c0d4
-	while(attrlen > 0) {
26c0d4
+	/*
26c0d4
+	 *	Loop over each attribute.  The format is:
26c0d4
+	 *
26c0d4
+	 *	1 octet of type
26c0d4
+	 *	1 octet of length (value 1..255)
26c0d4
+	 *	((4 * length) - 2) octets of data.
26c0d4
+	 */
26c0d4
+	while (attrlen > 0) {
26c0d4
 		uint8_t *p;
26c0d4
 
26c0d4
-		if(attrlen < 2) {
26c0d4
+		if (attrlen < 2) {
26c0d4
 			fr_strerror_printf("EAP-Sim attribute %d too short: %d < 2", es_attribute_count, attrlen);
26c0d4
 			return 0;
26c0d4
 		}
26c0d4
 
26c0d4
+		if (!attr[1]) {
26c0d4
+			fr_strerror_printf("EAP-Sim attribute %d (no.%d) has no data", attr[0],
26c0d4
+					   es_attribute_count);
26c0d4
+			return 0;
26c0d4
+		}
26c0d4
+
26c0d4
 		eapsim_attribute = attr[0];
26c0d4
 		eapsim_len = attr[1] * 4;
26c0d4
 
26c0d4
+		/*
26c0d4
+		 *	The length includes the 2-byte header.
26c0d4
+		 */
26c0d4
 		if (eapsim_len > attrlen) {
26c0d4
 			fr_strerror_printf("EAP-Sim attribute %d (no.%d) has length longer than data (%d > %d)",
26c0d4
 					   eapsim_attribute, es_attribute_count, eapsim_len, attrlen);
26c0d4
 			return 0;
26c0d4
 		}
26c0d4
 
26c0d4
-		if(eapsim_len > MAX_STRING_LEN) {
26c0d4
-			eapsim_len = MAX_STRING_LEN;
26c0d4
-		}
26c0d4
-		if (eapsim_len < 2) {
26c0d4
-			fr_strerror_printf("EAP-Sim attribute %d (no.%d) has length too small", eapsim_attribute,
26c0d4
-					   es_attribute_count);
26c0d4
-			return 0;
26c0d4
-		}
26c0d4
+		newvp = fr_pair_afrom_num(r, eapsim_attribute + PW_EAP_SIM_BASE, 0);
26c0d4
+		if (!newvp) {
26c0d4
+			/*
26c0d4
+			 *	RFC 4186 Section 8.1 says 0..127 are
26c0d4
+			 *	"non-skippable".  If one such
26c0d4
+			 *	attribute is found and we don't
26c0d4
+			 *	understand it, the server has to send:
26c0d4
+			 *
26c0d4
+			 *	EAP-Request/SIM/Notification packet with an
26c0d4
+			 *	(AT_NOTIFICATION code, which implies general failure ("General
26c0d4
+			 *	failure after authentication" (0), or "General failure" (16384),
26c0d4
+			 *	depending on the phase of the exchange), which terminates the
26c0d4
+			 *	authentication exchange.
26c0d4
+			 */
26c0d4
+			if (eapsim_attribute <= 127) {
26c0d4
+				fr_strerror_printf("Unknown mandatory attribute %d, failing",
26c0d4
+						   eapsim_attribute);
26c0d4
+				return 0;
26c0d4
+			}
26c0d4
 
26c0d4
-		newvp = fr_pair_afrom_num(r, eapsim_attribute+PW_EAP_SIM_BASE, 0);
26c0d4
-		newvp->vp_length = eapsim_len-2;
26c0d4
-		newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->vp_length);
26c0d4
-		memcpy(p, &attr[2], eapsim_len-2);
26c0d4
-		fr_pair_add(&(r->vps), newvp);
26c0d4
-		newvp = NULL;
26c0d4
+		} else {
26c0d4
+			/*
26c0d4
+			 *	It's known, ccount for header, and
26c0d4
+			 *	copy the value over.
26c0d4
+			 */
26c0d4
+			newvp->vp_length = eapsim_len - 2;
26c0d4
+
26c0d4
+			newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->vp_length);
26c0d4
+			memcpy(p, &attr[2], newvp->vp_length);
26c0d4
+			fr_pair_add(&(r->vps), newvp);
26c0d4
+		}
26c0d4
 
26c0d4
 		/* advance pointers, decrement length */
26c0d4
 		attr += eapsim_len;