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. How-to-reproduce: Set an MCS (real or bogus - with 0x80 bit set) rate in ibp_rate0 field for any device that uses ieee80211_isratevalid() for rate checks - rum(4), run(4), ural(4), bwi(4) or ral(4); if kernel is compiled with INVARIANTS the check will result in "rate %d is basic/mcs?" panic. Tested with WUSB54GC (rum(4)), AP mode. MFC after: 1 week
This commit is contained in:
parent
b9dee1ff02
commit
e42e878b35
@ -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
|
||||
@ -718,6 +809,10 @@ ieee80211_output(struct ifnet *ifp, struct mbuf *m,
|
||||
} 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)) {
|
||||
IEEE80211_NODE_STAT(ni, tx_mcast);
|
||||
|
Loading…
Reference in New Issue
Block a user