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>