aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-11-29 06:45:18 -0500
committerJohannes Berg <johannes.berg@intel.com>2012-11-30 07:41:26 -0500
commitc604b9f219422e969fe371cc7259de34c3c5601d (patch)
tree01f8773dbdc25cc7d044b0e371acf3a763af1604 /net/mac80211
parentf94f8b168cf2e46da180bbba2afd626d7af0579d (diff)
mac80211: make ieee80211_build_preq_ies safer
Instead of assuming 200 bytes are always enough for all the IEs we add, give the length of the buffer to the function and warn instead of overrunning. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/scan.c21
-rw-r--r--net/mac80211/util.c34
3 files changed, 41 insertions, 17 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8d8bf7136386..53e97dc4e06a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1034,6 +1034,7 @@ struct ieee80211_local {
1034 enum ieee80211_band hw_scan_band; 1034 enum ieee80211_band hw_scan_band;
1035 int scan_channel_idx; 1035 int scan_channel_idx;
1036 int scan_ies_len; 1036 int scan_ies_len;
1037 int hw_scan_ies_bufsize;
1037 1038
1038 struct work_struct sched_scan_stopped_work; 1039 struct work_struct sched_scan_stopped_work;
1039 struct ieee80211_sub_if_data __rcu *sched_scan_sdata; 1040 struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
@@ -1573,7 +1574,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
1573 const u8 *bssid, u16 stype, u16 reason, 1574 const u8 *bssid, u16 stype, u16 reason,
1574 bool send_frame, u8 *frame_buf); 1575 bool send_frame, u8 *frame_buf);
1575int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 1576int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1576 const u8 *ie, size_t ie_len, 1577 size_t buffer_len, const u8 *ie, size_t ie_len,
1577 enum ieee80211_band band, u32 rate_mask, 1578 enum ieee80211_band band, u32 rate_mask,
1578 u8 channel); 1579 u8 channel);
1579struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, 1580struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index ddd1a9aaff38..d7c190b80670 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -247,6 +247,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
247 local->hw_scan_req->n_channels = n_chans; 247 local->hw_scan_req->n_channels = n_chans;
248 248
249 ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, 249 ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
250 local->hw_scan_ies_bufsize,
250 req->ie, req->ie_len, band, 251 req->ie, req->ie_len, band,
251 req->rates[band], 0); 252 req->rates[band], 0);
252 local->hw_scan_req->ie_len = ielen; 253 local->hw_scan_req->ie_len = ielen;
@@ -445,11 +446,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
445 if (local->ops->hw_scan) { 446 if (local->ops->hw_scan) {
446 u8 *ies; 447 u8 *ies;
447 448
449 local->hw_scan_ies_bufsize = 2 + IEEE80211_MAX_SSID_LEN +
450 local->scan_ies_len +
451 req->ie_len;
448 local->hw_scan_req = kmalloc( 452 local->hw_scan_req = kmalloc(
449 sizeof(*local->hw_scan_req) + 453 sizeof(*local->hw_scan_req) +
450 req->n_channels * sizeof(req->channels[0]) + 454 req->n_channels * sizeof(req->channels[0]) +
451 2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + 455 local->hw_scan_ies_bufsize, GFP_KERNEL);
452 req->ie_len, GFP_KERNEL);
453 if (!local->hw_scan_req) 456 if (!local->hw_scan_req)
454 return -ENOMEM; 457 return -ENOMEM;
455 458
@@ -928,7 +931,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
928{ 931{
929 struct ieee80211_local *local = sdata->local; 932 struct ieee80211_local *local = sdata->local;
930 struct ieee80211_sched_scan_ies sched_scan_ies; 933 struct ieee80211_sched_scan_ies sched_scan_ies;
931 int ret, i; 934 int ret, i, iebufsz;
935
936 iebufsz = 2 + IEEE80211_MAX_SSID_LEN +
937 local->scan_ies_len + req->ie_len;
932 938
933 mutex_lock(&local->mtx); 939 mutex_lock(&local->mtx);
934 940
@@ -946,10 +952,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
946 if (!local->hw.wiphy->bands[i]) 952 if (!local->hw.wiphy->bands[i])
947 continue; 953 continue;
948 954
949 sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + 955 sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL);
950 local->scan_ies_len +
951 req->ie_len,
952 GFP_KERNEL);
953 if (!sched_scan_ies.ie[i]) { 956 if (!sched_scan_ies.ie[i]) {
954 ret = -ENOMEM; 957 ret = -ENOMEM;
955 goto out_free; 958 goto out_free;
@@ -957,8 +960,8 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
957 960
958 sched_scan_ies.len[i] = 961 sched_scan_ies.len[i] =
959 ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], 962 ieee80211_build_preq_ies(local, sched_scan_ies.ie[i],
960 req->ie, req->ie_len, i, 963 iebufsz, req->ie, req->ie_len,
961 (u32) -1, 0); 964 i, (u32) -1, 0);
962 } 965 }
963 966
964 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); 967 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 6e4c8bd5bfee..f119b1b6c1a7 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1107,12 +1107,12 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
1107} 1107}
1108 1108
1109int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 1109int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1110 const u8 *ie, size_t ie_len, 1110 size_t buffer_len, const u8 *ie, size_t ie_len,
1111 enum ieee80211_band band, u32 rate_mask, 1111 enum ieee80211_band band, u32 rate_mask,
1112 u8 channel) 1112 u8 channel)
1113{ 1113{
1114 struct ieee80211_supported_band *sband; 1114 struct ieee80211_supported_band *sband;
1115 u8 *pos; 1115 u8 *pos = buffer, *end = buffer + buffer_len;
1116 size_t offset = 0, noffset; 1116 size_t offset = 0, noffset;
1117 int supp_rates_len, i; 1117 int supp_rates_len, i;
1118 u8 rates[32]; 1118 u8 rates[32];
@@ -1123,8 +1123,6 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1123 if (WARN_ON_ONCE(!sband)) 1123 if (WARN_ON_ONCE(!sband))
1124 return 0; 1124 return 0;
1125 1125
1126 pos = buffer;
1127
1128 num_rates = 0; 1126 num_rates = 0;
1129 for (i = 0; i < sband->n_bitrates; i++) { 1127 for (i = 0; i < sband->n_bitrates; i++) {
1130 if ((BIT(i) & rate_mask) == 0) 1128 if ((BIT(i) & rate_mask) == 0)
@@ -1134,6 +1132,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1134 1132
1135 supp_rates_len = min_t(int, num_rates, 8); 1133 supp_rates_len = min_t(int, num_rates, 8);
1136 1134
1135 if (end - pos < 2 + supp_rates_len)
1136 goto out_err;
1137 *pos++ = WLAN_EID_SUPP_RATES; 1137 *pos++ = WLAN_EID_SUPP_RATES;
1138 *pos++ = supp_rates_len; 1138 *pos++ = supp_rates_len;
1139 memcpy(pos, rates, supp_rates_len); 1139 memcpy(pos, rates, supp_rates_len);
@@ -1150,6 +1150,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1150 before_extrates, 1150 before_extrates,
1151 ARRAY_SIZE(before_extrates), 1151 ARRAY_SIZE(before_extrates),
1152 offset); 1152 offset);
1153 if (end - pos < noffset - offset)
1154 goto out_err;
1153 memcpy(pos, ie + offset, noffset - offset); 1155 memcpy(pos, ie + offset, noffset - offset);
1154 pos += noffset - offset; 1156 pos += noffset - offset;
1155 offset = noffset; 1157 offset = noffset;
@@ -1157,6 +1159,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1157 1159
1158 ext_rates_len = num_rates - supp_rates_len; 1160 ext_rates_len = num_rates - supp_rates_len;
1159 if (ext_rates_len > 0) { 1161 if (ext_rates_len > 0) {
1162 if (end - pos < 2 + ext_rates_len)
1163 goto out_err;
1160 *pos++ = WLAN_EID_EXT_SUPP_RATES; 1164 *pos++ = WLAN_EID_EXT_SUPP_RATES;
1161 *pos++ = ext_rates_len; 1165 *pos++ = ext_rates_len;
1162 memcpy(pos, rates + supp_rates_len, ext_rates_len); 1166 memcpy(pos, rates + supp_rates_len, ext_rates_len);
@@ -1164,6 +1168,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1164 } 1168 }
1165 1169
1166 if (channel && sband->band == IEEE80211_BAND_2GHZ) { 1170 if (channel && sband->band == IEEE80211_BAND_2GHZ) {
1171 if (end - pos < 3)
1172 goto out_err;
1167 *pos++ = WLAN_EID_DS_PARAMS; 1173 *pos++ = WLAN_EID_DS_PARAMS;
1168 *pos++ = 1; 1174 *pos++ = 1;
1169 *pos++ = channel; 1175 *pos++ = channel;
@@ -1182,14 +1188,19 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1182 noffset = ieee80211_ie_split(ie, ie_len, 1188 noffset = ieee80211_ie_split(ie, ie_len,
1183 before_ht, ARRAY_SIZE(before_ht), 1189 before_ht, ARRAY_SIZE(before_ht),
1184 offset); 1190 offset);
1191 if (end - pos < noffset - offset)
1192 goto out_err;
1185 memcpy(pos, ie + offset, noffset - offset); 1193 memcpy(pos, ie + offset, noffset - offset);
1186 pos += noffset - offset; 1194 pos += noffset - offset;
1187 offset = noffset; 1195 offset = noffset;
1188 } 1196 }
1189 1197
1190 if (sband->ht_cap.ht_supported) 1198 if (sband->ht_cap.ht_supported) {
1199 if (end - pos < 2 + sizeof(struct ieee80211_ht_cap))
1200 goto out_err;
1191 pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, 1201 pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
1192 sband->ht_cap.cap); 1202 sband->ht_cap.cap);
1203 }
1193 1204
1194 /* 1205 /*
1195 * If adding more here, adjust code in main.c 1206 * If adding more here, adjust code in main.c
@@ -1199,15 +1210,23 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1199 /* add any remaining custom IEs */ 1210 /* add any remaining custom IEs */
1200 if (ie && ie_len) { 1211 if (ie && ie_len) {
1201 noffset = ie_len; 1212 noffset = ie_len;
1213 if (end - pos < noffset - offset)
1214 goto out_err;
1202 memcpy(pos, ie + offset, noffset - offset); 1215 memcpy(pos, ie + offset, noffset - offset);
1203 pos += noffset - offset; 1216 pos += noffset - offset;
1204 } 1217 }
1205 1218
1206 if (sband->vht_cap.vht_supported) 1219 if (sband->vht_cap.vht_supported) {
1220 if (end - pos < 2 + sizeof(struct ieee80211_vht_cap))
1221 goto out_err;
1207 pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, 1222 pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
1208 sband->vht_cap.cap); 1223 sband->vht_cap.cap);
1224 }
1209 1225
1210 return pos - buffer; 1226 return pos - buffer;
1227 out_err:
1228 WARN_ONCE(1, "not enough space for preq IEs\n");
1229 return pos - buffer;
1211} 1230}
1212 1231
1213struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, 1232struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
@@ -1239,7 +1258,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1239 else 1258 else
1240 chan_no = ieee80211_frequency_to_channel(chan->center_freq); 1259 chan_no = ieee80211_frequency_to_channel(chan->center_freq);
1241 1260
1242 buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band, 1261 buf_len = ieee80211_build_preq_ies(local, buf, 200 + ie_len,
1262 ie, ie_len, chan->band,
1243 ratemask, chan_no); 1263 ratemask, chan_no);
1244 1264
1245 skb = ieee80211_probereq_get(&local->hw, &sdata->vif, 1265 skb = ieee80211_probereq_get(&local->hw, &sdata->vif,