aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Minor <james.minor@ni.com>2015-02-24 13:58:20 -0500
committerJohannes Berg <johannes.berg@intel.com>2015-02-28 15:31:12 -0500
commit76a70e9c4b45fc1dbcbff6f7ae88ac7e1ddfb677 (patch)
tree1f23e9cf5066d66b207484ff6839a8e53fa6c70f
parent36ef906ee8fefbfac3844206e66d8450e6221c69 (diff)
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>
-rw-r--r--net/wireless/scan.c212
1 files changed, 136 insertions, 76 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 25e1e1fad905..ceb8f0040dae 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1239,15 +1239,15 @@ int cfg80211_wext_siwscan(struct net_device *dev,
1239} 1239}
1240EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan); 1240EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
1241 1241
1242static void ieee80211_scan_add_ies(struct iw_request_info *info, 1242static char *ieee80211_scan_add_ies(struct iw_request_info *info,
1243 const struct cfg80211_bss_ies *ies, 1243 const struct cfg80211_bss_ies *ies,
1244 char **current_ev, char *end_buf) 1244 char *current_ev, char *end_buf)
1245{ 1245{
1246 const u8 *pos, *end, *next; 1246 const u8 *pos, *end, *next;
1247 struct iw_event iwe; 1247 struct iw_event iwe;
1248 1248
1249 if (!ies) 1249 if (!ies)
1250 return; 1250 return current_ev;
1251 1251
1252 /* 1252 /*
1253 * If needed, fragment the IEs buffer (at IE boundaries) into short 1253 * 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,
1264 memset(&iwe, 0, sizeof(iwe)); 1264 memset(&iwe, 0, sizeof(iwe));
1265 iwe.cmd = IWEVGENIE; 1265 iwe.cmd = IWEVGENIE;
1266 iwe.u.data.length = next - pos; 1266 iwe.u.data.length = next - pos;
1267 *current_ev = iwe_stream_add_point(info, *current_ev, 1267 current_ev = iwe_stream_add_point_check(info, current_ev,
1268 end_buf, &iwe, 1268 end_buf, &iwe,
1269 (void *)pos); 1269 (void *)pos);
1270 1270 if (IS_ERR(current_ev))
1271 return current_ev;
1271 pos = next; 1272 pos = next;
1272 } 1273 }
1273 1274
@@ -1275,10 +1276,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
1275 memset(&iwe, 0, sizeof(iwe)); 1276 memset(&iwe, 0, sizeof(iwe));
1276 iwe.cmd = IWEVGENIE; 1277 iwe.cmd = IWEVGENIE;
1277 iwe.u.data.length = end - pos; 1278 iwe.u.data.length = end - pos;
1278 *current_ev = iwe_stream_add_point(info, *current_ev, 1279 current_ev = iwe_stream_add_point_check(info, current_ev,
1279 end_buf, &iwe, 1280 end_buf, &iwe,
1280 (void *)pos); 1281 (void *)pos);
1282 if (IS_ERR(current_ev))
1283 return current_ev;
1281 } 1284 }
1285
1286 return current_ev;
1282} 1287}
1283 1288
1284static char * 1289static char *
@@ -1289,7 +1294,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1289 const struct cfg80211_bss_ies *ies; 1294 const struct cfg80211_bss_ies *ies;
1290 struct iw_event iwe; 1295 struct iw_event iwe;
1291 const u8 *ie; 1296 const u8 *ie;
1292 u8 *buf, *cfg, *p; 1297 u8 buf[50];
1298 u8 *cfg, *p, *tmp;
1293 int rem, i, sig; 1299 int rem, i, sig;
1294 bool ismesh = false; 1300 bool ismesh = false;
1295 1301
@@ -1297,22 +1303,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1297 iwe.cmd = SIOCGIWAP; 1303 iwe.cmd = SIOCGIWAP;
1298 iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 1304 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1299 memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN); 1305 memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
1300 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1306 current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
1301 IW_EV_ADDR_LEN); 1307 IW_EV_ADDR_LEN);
1308 if (IS_ERR(current_ev))
1309 return current_ev;
1302 1310
1303 memset(&iwe, 0, sizeof(iwe)); 1311 memset(&iwe, 0, sizeof(iwe));
1304 iwe.cmd = SIOCGIWFREQ; 1312 iwe.cmd = SIOCGIWFREQ;
1305 iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq); 1313 iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
1306 iwe.u.freq.e = 0; 1314 iwe.u.freq.e = 0;
1307 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1315 current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
1308 IW_EV_FREQ_LEN); 1316 IW_EV_FREQ_LEN);
1317 if (IS_ERR(current_ev))
1318 return current_ev;
1309 1319
1310 memset(&iwe, 0, sizeof(iwe)); 1320 memset(&iwe, 0, sizeof(iwe));
1311 iwe.cmd = SIOCGIWFREQ; 1321 iwe.cmd = SIOCGIWFREQ;
1312 iwe.u.freq.m = bss->pub.channel->center_freq; 1322 iwe.u.freq.m = bss->pub.channel->center_freq;
1313 iwe.u.freq.e = 6; 1323 iwe.u.freq.e = 6;
1314 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1324 current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
1315 IW_EV_FREQ_LEN); 1325 IW_EV_FREQ_LEN);
1326 if (IS_ERR(current_ev))
1327 return current_ev;
1316 1328
1317 if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { 1329 if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
1318 memset(&iwe, 0, sizeof(iwe)); 1330 memset(&iwe, 0, sizeof(iwe));
@@ -1341,8 +1353,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1341 /* not reached */ 1353 /* not reached */
1342 break; 1354 break;
1343 } 1355 }
1344 current_ev = iwe_stream_add_event(info, current_ev, end_buf, 1356 current_ev = iwe_stream_add_event_check(info, current_ev,
1345 &iwe, IW_EV_QUAL_LEN); 1357 end_buf, &iwe,
1358 IW_EV_QUAL_LEN);
1359 if (IS_ERR(current_ev))
1360 return current_ev;
1346 } 1361 }
1347 1362
1348 memset(&iwe, 0, sizeof(iwe)); 1363 memset(&iwe, 0, sizeof(iwe));
@@ -1352,8 +1367,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1352 else 1367 else
1353 iwe.u.data.flags = IW_ENCODE_DISABLED; 1368 iwe.u.data.flags = IW_ENCODE_DISABLED;
1354 iwe.u.data.length = 0; 1369 iwe.u.data.length = 0;
1355 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1370 current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
1356 &iwe, ""); 1371 &iwe, "");
1372 if (IS_ERR(current_ev))
1373 return current_ev;
1357 1374
1358 rcu_read_lock(); 1375 rcu_read_lock();
1359 ies = rcu_dereference(bss->pub.ies); 1376 ies = rcu_dereference(bss->pub.ies);
@@ -1371,66 +1388,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1371 iwe.cmd = SIOCGIWESSID; 1388 iwe.cmd = SIOCGIWESSID;
1372 iwe.u.data.length = ie[1]; 1389 iwe.u.data.length = ie[1];
1373 iwe.u.data.flags = 1; 1390 iwe.u.data.flags = 1;
1374 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1391 current_ev = iwe_stream_add_point_check(info,
1375 &iwe, (u8 *)ie + 2); 1392 current_ev,
1393 end_buf, &iwe,
1394 (u8 *)ie + 2);
1395 if (IS_ERR(current_ev))
1396 goto unlock;
1376 break; 1397 break;
1377 case WLAN_EID_MESH_ID: 1398 case WLAN_EID_MESH_ID:
1378 memset(&iwe, 0, sizeof(iwe)); 1399 memset(&iwe, 0, sizeof(iwe));
1379 iwe.cmd = SIOCGIWESSID; 1400 iwe.cmd = SIOCGIWESSID;
1380 iwe.u.data.length = ie[1]; 1401 iwe.u.data.length = ie[1];
1381 iwe.u.data.flags = 1; 1402 iwe.u.data.flags = 1;
1382 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1403 current_ev = iwe_stream_add_point_check(info,
1383 &iwe, (u8 *)ie + 2); 1404 current_ev,
1405 end_buf, &iwe,
1406 (u8 *)ie + 2);
1407 if (IS_ERR(current_ev))
1408 goto unlock;
1384 break; 1409 break;
1385 case WLAN_EID_MESH_CONFIG: 1410 case WLAN_EID_MESH_CONFIG:
1386 ismesh = true; 1411 ismesh = true;
1387 if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) 1412 if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
1388 break; 1413 break;
1389 buf = kmalloc(50, GFP_ATOMIC);
1390 if (!buf)
1391 break;
1392 cfg = (u8 *)ie + 2; 1414 cfg = (u8 *)ie + 2;
1393 memset(&iwe, 0, sizeof(iwe)); 1415 memset(&iwe, 0, sizeof(iwe));
1394 iwe.cmd = IWEVCUSTOM; 1416 iwe.cmd = IWEVCUSTOM;
1395 sprintf(buf, "Mesh Network Path Selection Protocol ID: " 1417 sprintf(buf, "Mesh Network Path Selection Protocol ID: "
1396 "0x%02X", cfg[0]); 1418 "0x%02X", cfg[0]);
1397 iwe.u.data.length = strlen(buf); 1419 iwe.u.data.length = strlen(buf);
1398 current_ev = iwe_stream_add_point(info, current_ev, 1420 current_ev = iwe_stream_add_point_check(info,
1399 end_buf, 1421 current_ev,
1400 &iwe, buf); 1422 end_buf,
1423 &iwe, buf);
1424 if (IS_ERR(current_ev))
1425 goto unlock;
1401 sprintf(buf, "Path Selection Metric ID: 0x%02X", 1426 sprintf(buf, "Path Selection Metric ID: 0x%02X",
1402 cfg[1]); 1427 cfg[1]);
1403 iwe.u.data.length = strlen(buf); 1428 iwe.u.data.length = strlen(buf);
1404 current_ev = iwe_stream_add_point(info, current_ev, 1429 current_ev = iwe_stream_add_point_check(info,
1405 end_buf, 1430 current_ev,
1406 &iwe, buf); 1431 end_buf,
1432 &iwe, buf);
1433 if (IS_ERR(current_ev))
1434 goto unlock;
1407 sprintf(buf, "Congestion Control Mode ID: 0x%02X", 1435 sprintf(buf, "Congestion Control Mode ID: 0x%02X",
1408 cfg[2]); 1436 cfg[2]);
1409 iwe.u.data.length = strlen(buf); 1437 iwe.u.data.length = strlen(buf);
1410 current_ev = iwe_stream_add_point(info, current_ev, 1438 current_ev = iwe_stream_add_point_check(info,
1411 end_buf, 1439 current_ev,
1412 &iwe, buf); 1440 end_buf,
1441 &iwe, buf);
1442 if (IS_ERR(current_ev))
1443 goto unlock;
1413 sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]); 1444 sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
1414 iwe.u.data.length = strlen(buf); 1445 iwe.u.data.length = strlen(buf);
1415 current_ev = iwe_stream_add_point(info, current_ev, 1446 current_ev = iwe_stream_add_point_check(info,
1416 end_buf, 1447 current_ev,
1417 &iwe, buf); 1448 end_buf,
1449 &iwe, buf);
1450 if (IS_ERR(current_ev))
1451 goto unlock;
1418 sprintf(buf, "Authentication ID: 0x%02X", cfg[4]); 1452 sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
1419 iwe.u.data.length = strlen(buf); 1453 iwe.u.data.length = strlen(buf);
1420 current_ev = iwe_stream_add_point(info, current_ev, 1454 current_ev = iwe_stream_add_point_check(info,
1421 end_buf, 1455 current_ev,
1422 &iwe, buf); 1456 end_buf,
1457 &iwe, buf);
1458 if (IS_ERR(current_ev))
1459 goto unlock;
1423 sprintf(buf, "Formation Info: 0x%02X", cfg[5]); 1460 sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
1424 iwe.u.data.length = strlen(buf); 1461 iwe.u.data.length = strlen(buf);
1425 current_ev = iwe_stream_add_point(info, current_ev, 1462 current_ev = iwe_stream_add_point_check(info,
1426 end_buf, 1463 current_ev,
1427 &iwe, buf); 1464 end_buf,
1465 &iwe, buf);
1466 if (IS_ERR(current_ev))
1467 goto unlock;
1428 sprintf(buf, "Capabilities: 0x%02X", cfg[6]); 1468 sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
1429 iwe.u.data.length = strlen(buf); 1469 iwe.u.data.length = strlen(buf);
1430 current_ev = iwe_stream_add_point(info, current_ev, 1470 current_ev = iwe_stream_add_point_check(info,
1431 end_buf, 1471 current_ev,
1432 &iwe, buf); 1472 end_buf,
1433 kfree(buf); 1473 &iwe, buf);
1474 if (IS_ERR(current_ev))
1475 goto unlock;
1434 break; 1476 break;
1435 case WLAN_EID_SUPP_RATES: 1477 case WLAN_EID_SUPP_RATES:
1436 case WLAN_EID_EXT_SUPP_RATES: 1478 case WLAN_EID_EXT_SUPP_RATES:
@@ -1445,8 +1487,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1445 for (i = 0; i < ie[1]; i++) { 1487 for (i = 0; i < ie[1]; i++) {
1446 iwe.u.bitrate.value = 1488 iwe.u.bitrate.value =
1447 ((ie[i + 2] & 0x7f) * 500000); 1489 ((ie[i + 2] & 0x7f) * 500000);
1490 tmp = p;
1448 p = iwe_stream_add_value(info, current_ev, p, 1491 p = iwe_stream_add_value(info, current_ev, p,
1449 end_buf, &iwe, IW_EV_PARAM_LEN); 1492 end_buf, &iwe,
1493 IW_EV_PARAM_LEN);
1494 if (p == tmp) {
1495 current_ev = ERR_PTR(-E2BIG);
1496 goto unlock;
1497 }
1450 } 1498 }
1451 current_ev = p; 1499 current_ev = p;
1452 break; 1500 break;
@@ -1465,31 +1513,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1465 iwe.u.mode = IW_MODE_MASTER; 1513 iwe.u.mode = IW_MODE_MASTER;
1466 else 1514 else
1467 iwe.u.mode = IW_MODE_ADHOC; 1515 iwe.u.mode = IW_MODE_ADHOC;
1468 current_ev = iwe_stream_add_event(info, current_ev, end_buf, 1516 current_ev = iwe_stream_add_event_check(info, current_ev,
1469 &iwe, IW_EV_UINT_LEN); 1517 end_buf, &iwe,
1470 } 1518 IW_EV_UINT_LEN);
1471 1519 if (IS_ERR(current_ev))
1472 buf = kmalloc(31, GFP_ATOMIC); 1520 goto unlock;
1473 if (buf) {
1474 memset(&iwe, 0, sizeof(iwe));
1475 iwe.cmd = IWEVCUSTOM;
1476 sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
1477 iwe.u.data.length = strlen(buf);
1478 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1479 &iwe, buf);
1480 memset(&iwe, 0, sizeof(iwe));
1481 iwe.cmd = IWEVCUSTOM;
1482 sprintf(buf, " Last beacon: %ums ago",
1483 elapsed_jiffies_msecs(bss->ts));
1484 iwe.u.data.length = strlen(buf);
1485 current_ev = iwe_stream_add_point(info, current_ev,
1486 end_buf, &iwe, buf);
1487 kfree(buf);
1488 } 1521 }
1489 1522
1490 ieee80211_scan_add_ies(info, ies, &current_ev, end_buf); 1523 memset(&iwe, 0, sizeof(iwe));
1524 iwe.cmd = IWEVCUSTOM;
1525 sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
1526 iwe.u.data.length = strlen(buf);
1527 current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
1528 &iwe, buf);
1529 if (IS_ERR(current_ev))
1530 goto unlock;
1531 memset(&iwe, 0, sizeof(iwe));
1532 iwe.cmd = IWEVCUSTOM;
1533 sprintf(buf, " Last beacon: %ums ago",
1534 elapsed_jiffies_msecs(bss->ts));
1535 iwe.u.data.length = strlen(buf);
1536 current_ev = iwe_stream_add_point_check(info, current_ev,
1537 end_buf, &iwe, buf);
1538 if (IS_ERR(current_ev))
1539 goto unlock;
1540
1541 current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf);
1542
1543 unlock:
1491 rcu_read_unlock(); 1544 rcu_read_unlock();
1492
1493 return current_ev; 1545 return current_ev;
1494} 1546}
1495 1547
@@ -1501,19 +1553,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
1501 char *current_ev = buf; 1553 char *current_ev = buf;
1502 char *end_buf = buf + len; 1554 char *end_buf = buf + len;
1503 struct cfg80211_internal_bss *bss; 1555 struct cfg80211_internal_bss *bss;
1556 int err = 0;
1504 1557
1505 spin_lock_bh(&rdev->bss_lock); 1558 spin_lock_bh(&rdev->bss_lock);
1506 cfg80211_bss_expire(rdev); 1559 cfg80211_bss_expire(rdev);
1507 1560
1508 list_for_each_entry(bss, &rdev->bss_list, list) { 1561 list_for_each_entry(bss, &rdev->bss_list, list) {
1509 if (buf + len - current_ev <= IW_EV_ADDR_LEN) { 1562 if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
1510 spin_unlock_bh(&rdev->bss_lock); 1563 err = -E2BIG;
1511 return -E2BIG; 1564 break;
1512 } 1565 }
1513 current_ev = ieee80211_bss(&rdev->wiphy, info, bss, 1566 current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
1514 current_ev, end_buf); 1567 current_ev, end_buf);
1568 if (IS_ERR(current_ev)) {
1569 err = PTR_ERR(current_ev);
1570 break;
1571 }
1515 } 1572 }
1516 spin_unlock_bh(&rdev->bss_lock); 1573 spin_unlock_bh(&rdev->bss_lock);
1574
1575 if (err)
1576 return err;
1517 return current_ev - buf; 1577 return current_ev - buf;
1518} 1578}
1519 1579