diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2020-02-18 08:29:36 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2020-02-18 08:29:36 +0000 |
commit | 6b2f2bff46800a7981be3f06c542cadab65292bf (patch) | |
tree | 61f022739befa2ddf0b0b33ff9f7046c5dbeb77e /sys | |
parent | 8820d22ede4adc3d575fb32151efb75ce6214084 (diff) |
Fix an mbuf corruption issue which occurs in net80211 hostap mode.
When sizing a memory allocation for a probe response frame, the AP used
the SSID length stored in the node structure which represents the client,
but used the actual length of the SSID when copying it into the frame.
If the actual length is sufficiently large this will result in corruption
of an adjacent mbuf on the free list since m->m_next will be overwritten
with data written to the tail of the probe response frame.
Bad things happen later on when the adjacent mbuf is used. Sometimes
the corruption is detected by mbufpl's use-after-free checking, at
other times we end up crashing somewhere in the network stack.
To prevent such a mistake from occuring again I am removing the 'ni'
argument from ieee80211_get_probe_resp() altogether. It is not needed.
A quick workaround is to configure a short SSID.
Debugged with help from claudio, kettenis, and dlg.
ok claudio
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net80211/ieee80211_output.c | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 37cf81c8f2e..6880f7fc2d7 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_output.c,v 1.126 2019/07/29 10:50:09 stsp Exp $ */ +/* $OpenBSD: ieee80211_output.c,v 1.127 2020/02/18 08:29:35 stsp Exp $ */ /* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */ /*- @@ -73,8 +73,7 @@ struct mbuf *ieee80211_getmgmt(int, int, u_int); struct mbuf *ieee80211_get_probe_req(struct ieee80211com *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY -struct mbuf *ieee80211_get_probe_resp(struct ieee80211com *, - struct ieee80211_node *); +struct mbuf *ieee80211_get_probe_resp(struct ieee80211com *); #endif struct mbuf *ieee80211_get_auth(struct ieee80211com *, struct ieee80211_node *, u_int16_t, u_int16_t); @@ -1239,7 +1238,7 @@ ieee80211_get_probe_req(struct ieee80211com *ic, struct ieee80211_node *ni) * [tlv] HT Operation (802.11n) */ struct mbuf * -ieee80211_get_probe_resp(struct ieee80211com *ic, struct ieee80211_node *ni) +ieee80211_get_probe_resp(struct ieee80211com *ic) { const struct ieee80211_rateset *rs = &ic->ic_bss->ni_rates; struct mbuf *m; @@ -1247,7 +1246,7 @@ ieee80211_get_probe_resp(struct ieee80211com *ic, struct ieee80211_node *ni) m = ieee80211_getmgmt(M_DONTWAIT, MT_DATA, 8 + 2 + 2 + - 2 + ni->ni_esslen + + 2 + ic->ic_bss->ni_esslen + 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) + 2 + 1 + ((ic->ic_opmode == IEEE80211_M_IBSS) ? 2 + 2 : 0) + @@ -1268,13 +1267,13 @@ ieee80211_get_probe_resp(struct ieee80211com *ic, struct ieee80211_node *ni) frm = mtod(m, u_int8_t *); memset(frm, 0, 8); frm += 8; /* timestamp is set by hardware */ LE_WRITE_2(frm, ic->ic_bss->ni_intval); frm += 2; - frm = ieee80211_add_capinfo(frm, ic, ni); + frm = ieee80211_add_capinfo(frm, ic, ic->ic_bss); frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen); frm = ieee80211_add_rates(frm, rs); - frm = ieee80211_add_ds_params(frm, ic, ni); + frm = ieee80211_add_ds_params(frm, ic, ic->ic_bss); if (ic->ic_opmode == IEEE80211_M_IBSS) - frm = ieee80211_add_ibss_params(frm, ni); + frm = ieee80211_add_ibss_params(frm, ic->ic_bss); if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); if (rs->rs_nrates > IEEE80211_RATE_SIZE) @@ -1777,7 +1776,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, break; #ifndef IEEE80211_STA_ONLY case IEEE80211_FC0_SUBTYPE_PROBE_RESP: - if ((m = ieee80211_get_probe_resp(ic, ni)) == NULL) + if ((m = ieee80211_get_probe_resp(ic)) == NULL) senderr(ENOMEM, is_tx_nombuf); break; #endif |