Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Jan 2019 14:33:29 +0000 (UTC)
From:      Andriy Voskoboinyk <avos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r343216 - stable/12/sys/net80211
Message-ID:  <201901201433.x0KEXTtb034787@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avos
Date: Sun Jan 20 14:33:29 2019
New Revision: 343216
URL: https://svnweb.freebsd.org/changeset/base/343216

Log:
  MFC r342991:
  net80211: provide rate validation for injected frames.
  
  There may be various side effects (device timeout, firmware and / or
  kernel panic) when an invalid (or inapplicable - e.g., an MCS rate
  for 11g-only device) is set; check rates before sending the frame to
  the driver.

Modified:
  stable/12/sys/net80211/ieee80211_output.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/net80211/ieee80211_output.c
==============================================================================
--- stable/12/sys/net80211/ieee80211_output.c	Sun Jan 20 14:25:25 2019	(r343215)
+++ stable/12/sys/net80211/ieee80211_output.c	Sun Jan 20 14:33:29 2019	(r343216)
@@ -604,6 +604,97 @@ ieee80211_validate_frame(struct mbuf *m,
 	return (0);
 }
 
+static int
+ieee80211_validate_rate(struct ieee80211_node *ni, uint8_t rate)
+{
+	struct ieee80211com *ic = ni->ni_ic;
+
+	if (IEEE80211_IS_HT_RATE(rate)) {
+		if ((ic->ic_htcaps & IEEE80211_HTC_HT) == 0)
+			return (EINVAL);
+
+		rate = IEEE80211_RV(rate);
+		if (rate <= 31) {
+			if (rate > ic->ic_txstream * 8 - 1)
+				return (EINVAL);
+
+			return (0);
+		}
+
+		if (rate == 32) {
+			if ((ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0)
+				return (EINVAL);
+
+			return (0);
+		}
+
+		if ((ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) == 0)
+			return (EINVAL);
+
+		switch (ic->ic_txstream) {
+		case 0:
+		case 1:
+			return (EINVAL);
+		case 2:
+			if (rate > 38)
+				return (EINVAL);
+
+			return (0);
+		case 3:
+			if (rate > 52)
+				return (EINVAL);
+
+			return (0);
+		case 4:
+		default:
+			if (rate > 76)
+				return (EINVAL);
+
+			return (0);
+		}
+	}
+
+	if (!ieee80211_isratevalid(ic->ic_rt, rate))
+		return (EINVAL);
+
+	return (0);
+}
+
+static int
+ieee80211_sanitize_rates(struct ieee80211_node *ni, struct mbuf *m,
+    const struct ieee80211_bpf_params *params)
+{
+	int error;
+
+	if (!params)
+		return (0);	/* nothing to do */
+
+	/* NB: most drivers assume that ibp_rate0 is set (!= 0). */
+	if (params->ibp_rate0 != 0) {
+		error = ieee80211_validate_rate(ni, params->ibp_rate0);
+		if (error != 0)
+			return (error);
+	} else {
+		/* XXX pre-setup some default (e.g., mgmt / mcast) rate */
+		/* XXX __DECONST? */
+		(void) m;
+	}
+
+	if (params->ibp_rate1 != 0 &&
+	    (error = ieee80211_validate_rate(ni, params->ibp_rate1)) != 0)
+		return (error);
+
+	if (params->ibp_rate2 != 0 &&
+	    (error = ieee80211_validate_rate(ni, params->ibp_rate2)) != 0)
+		return (error);
+
+	if (params->ibp_rate3 != 0 &&
+	    (error = ieee80211_validate_rate(ni, params->ibp_rate3)) != 0)
+		return (error);
+
+	return (0);
+}
+
 /*
  * 802.11 output routine. This is (currently) used only to
  * connect bpf write calls to the 802.11 layer for injecting
@@ -717,6 +808,10 @@ ieee80211_output(struct ifnet *ifp, struct mbuf *m,
 		    m->m_pkthdr.len - ieee80211_hdrsize(wh));
 	} else
 		M_WME_SETAC(m, WME_AC_BE);
+
+	error = ieee80211_sanitize_rates(ni, m, params);
+	if (error != 0)
+		senderr(error);
 
 	IEEE80211_NODE_STAT(ni, tx_data);
 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201901201433.x0KEXTtb034787>