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