summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2020-02-18 08:29:36 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2020-02-18 08:29:36 +0000
commit6b2f2bff46800a7981be3f06c542cadab65292bf (patch)
tree61f022739befa2ddf0b0b33ff9f7046c5dbeb77e /sys
parent8820d22ede4adc3d575fb32151efb75ce6214084 (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.c17
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