mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
cfg80211-wext: return -E2BIG when buffer can't hold full BSS entry
When using the wext compatibility code in cfg80211, part of the IEs can be truncated if the passed user buffer is large enough for part of the BSS but not large enough for all of the IEs. This can cause an EAP network to show up as a PSK network. Always return -E2BIG in this case to avoid truncating data. Since this changes the control flow, use an on-stack variable for a small buffer instead of allocating it. Signed-off-by: James Minor <james.minor@ni.com> [rework patch to error out immediately, use _check wrappers] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
36ef906ee8
commit
76a70e9c4b
1 changed files with 135 additions and 75 deletions
|
@ -1239,15 +1239,15 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
|||
}
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
|
||||
|
||||
static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
const struct cfg80211_bss_ies *ies,
|
||||
char **current_ev, char *end_buf)
|
||||
static char *ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
const struct cfg80211_bss_ies *ies,
|
||||
char *current_ev, char *end_buf)
|
||||
{
|
||||
const u8 *pos, *end, *next;
|
||||
struct iw_event iwe;
|
||||
|
||||
if (!ies)
|
||||
return;
|
||||
return current_ev;
|
||||
|
||||
/*
|
||||
* If needed, fragment the IEs buffer (at IE boundaries) into short
|
||||
|
@ -1264,10 +1264,11 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
|||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = next - pos;
|
||||
*current_ev = iwe_stream_add_point(info, *current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
pos = next;
|
||||
}
|
||||
|
||||
|
@ -1275,10 +1276,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
|||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = end - pos;
|
||||
*current_ev = iwe_stream_add_point(info, *current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -1289,7 +1294,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
const struct cfg80211_bss_ies *ies;
|
||||
struct iw_event iwe;
|
||||
const u8 *ie;
|
||||
u8 *buf, *cfg, *p;
|
||||
u8 buf[50];
|
||||
u8 *cfg, *p, *tmp;
|
||||
int rem, i, sig;
|
||||
bool ismesh = false;
|
||||
|
||||
|
@ -1297,22 +1303,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
|
||||
iwe.u.freq.e = 0;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = bss->pub.channel->center_freq;
|
||||
iwe.u.freq.e = 6;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -1341,8 +1353,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
/* not reached */
|
||||
break;
|
||||
}
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
IW_EV_QUAL_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -1352,8 +1367,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, "");
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
|
||||
&iwe, "");
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(bss->pub.ies);
|
||||
|
@ -1371,66 +1388,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = ie[1];
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, (u8 *)ie + 2);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf, &iwe,
|
||||
(u8 *)ie + 2);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_MESH_ID:
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = ie[1];
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, (u8 *)ie + 2);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf, &iwe,
|
||||
(u8 *)ie + 2);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_MESH_CONFIG:
|
||||
ismesh = true;
|
||||
if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
|
||||
break;
|
||||
buf = kmalloc(50, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
break;
|
||||
cfg = (u8 *)ie + 2;
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "Mesh Network Path Selection Protocol ID: "
|
||||
"0x%02X", cfg[0]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Path Selection Metric ID: 0x%02X",
|
||||
cfg[1]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Congestion Control Mode ID: 0x%02X",
|
||||
cfg[2]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
kfree(buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_SUPP_RATES:
|
||||
case WLAN_EID_EXT_SUPP_RATES:
|
||||
|
@ -1445,8 +1487,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
for (i = 0; i < ie[1]; i++) {
|
||||
iwe.u.bitrate.value =
|
||||
((ie[i + 2] & 0x7f) * 500000);
|
||||
tmp = p;
|
||||
p = iwe_stream_add_value(info, current_ev, p,
|
||||
end_buf, &iwe, IW_EV_PARAM_LEN);
|
||||
end_buf, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
if (p == tmp) {
|
||||
current_ev = ERR_PTR(-E2BIG);
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
current_ev = p;
|
||||
break;
|
||||
|
@ -1465,31 +1513,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
IW_EV_UINT_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
buf = kmalloc(31, GFP_ATOMIC);
|
||||
if (buf) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, " Last beacon: %ums ago",
|
||||
elapsed_jiffies_msecs(bss->ts));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf, &iwe, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, " Last beacon: %ums ago",
|
||||
elapsed_jiffies_msecs(bss->ts));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
|
||||
ieee80211_scan_add_ies(info, ies, ¤t_ev, end_buf);
|
||||
current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf);
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
|
@ -1501,19 +1553,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
|
|||
char *current_ev = buf;
|
||||
char *end_buf = buf + len;
|
||||
struct cfg80211_internal_bss *bss;
|
||||
int err = 0;
|
||||
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
cfg80211_bss_expire(rdev);
|
||||
|
||||
list_for_each_entry(bss, &rdev->bss_list, list) {
|
||||
if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
return -E2BIG;
|
||||
err = -E2BIG;
|
||||
break;
|
||||
}
|
||||
current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
|
||||
current_ev, end_buf);
|
||||
if (IS_ERR(current_ev)) {
|
||||
err = PTR_ERR(current_ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
return current_ev - buf;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue