DragonFlyBSD Kernel Audit
DF-0751 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netproto/mpls/mpls_input.c b/sys/netproto/mpls/mpls_input.c
--- a/sys/netproto/mpls/mpls_input.c
+++ b/sys/netproto/mpls/mpls_input.c
@@ -45,6 +45,14 @@
 #include <netproto/mpls/mpls.h>
 #include <netproto/mpls/mpls_var.h>
 
+/*
+ * Maximum number of MPLS labels we will process in one mpls_input()
+ * call.  RFC 3032 does not bound the label stack, but a legitimate
+ * stack is never deeper than a handful of entries; cap it to prevent a
+ * malicious or malformed frame from spinning the netisr thread forever.
+ */
+#define MPLS_LABEL_TTL_MAX	32
+
 struct mpls_stats	mplsstats_percpu[MAXCPU];
 struct route		mplsforward_rt[MAXCPU];
 
@@ -89,6 +97,7 @@
 {
 	struct mpls *mpls = NULL;
 	mpls_label_t label;
+	int depth = 0;
 
 	M_ASSERTPKTHDR(m);
 
@@ -99,6 +108,11 @@
 	    ("mpls_input: mpls header too small"));
 	
 again:
+	if (++depth > MPLS_LABEL_TTL_MAX) {
+		mplsstat.mplss_invalid++;
+		m_freem(m);
+		return;
+	}
 	if (m->m_len < sizeof(struct mpls)) {
 		m = m_pullup(m, sizeof(struct mpls));
 		if (m == NULL) {
@@ -120,6 +134,7 @@
 			netisr_queue(NETISR_IP, m);
 			return;
 		}
+		m_adj(m, sizeof(struct mpls));
 		goto again; /* If not the bottom label, per RFC4182. */
 
 	case 1:
@@ -139,6 +154,7 @@
 			netisr_queue(NETISR_IPV6, m);
 			return;
 		}
+		m_adj(m, sizeof(struct mpls));
 		goto again; /* If not the bottom label, per RFC4182. */
 
 	case 3: