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