aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
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/util.c
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/util.c')
-rw-r--r--net/mac80211/util.c34
1 files changed, 27 insertions, 7 deletions
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,