Blame SOURCES/freeradius-fix-crash-unknown-eap-sim.patch

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