diff options
author | Jean Tourrilhes <jt@hpl.hp.com> | 2007-03-22 20:31:16 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2007-03-27 14:10:26 -0400 |
commit | c2805fbb8630abb95d94ce7adc3f97976f7e0367 (patch) | |
tree | ca94be7f103d430d38ef6543db597e90f3a63999 /net/core/wireless.c | |
parent | ed4bb1063171b2f44a40b0a9c400dedb0590dce6 (diff) |
[PATCH] WE-22 : prevent information leak on 64 bit
Johannes Berg discovered that kernel space was leaking to
userspace on 64 bit platform. He made a first patch to fix that. This
is an improved version of his patch.
Signed-off-by: Jean Tourrilhes <jt@hpl.hp.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/core/wireless.c')
-rw-r--r-- | net/core/wireless.c | 82 |
1 files changed, 50 insertions, 32 deletions
diff --git a/net/core/wireless.c b/net/core/wireless.c index 9936ab11e6e0..b07fe270a508 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * This file implement the Wireless Extensions APIs. | 2 | * This file implement the Wireless Extensions APIs. |
3 | * | 3 | * |
4 | * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> | 4 | * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> |
5 | * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved. | 5 | * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. |
6 | * | 6 | * |
7 | * (As all part of the Linux kernel, this file is GPL) | 7 | * (As all part of the Linux kernel, this file is GPL) |
8 | */ | 8 | */ |
@@ -76,6 +76,9 @@ | |||
76 | * o Change length in ESSID and NICK to strlen() instead of strlen()+1 | 76 | * o Change length in ESSID and NICK to strlen() instead of strlen()+1 |
77 | * o Make standard_ioctl_num and standard_event_num unsigned | 77 | * o Make standard_ioctl_num and standard_event_num unsigned |
78 | * o Remove (struct net_device *)->get_wireless_stats() | 78 | * o Remove (struct net_device *)->get_wireless_stats() |
79 | * | ||
80 | * v10 - 16.3.07 - Jean II | ||
81 | * o Prevent leaking of kernel space in stream on 64 bits. | ||
79 | */ | 82 | */ |
80 | 83 | ||
81 | /***************************** INCLUDES *****************************/ | 84 | /***************************** INCLUDES *****************************/ |
@@ -427,6 +430,21 @@ static const int event_type_size[] = { | |||
427 | IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ | 430 | IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ |
428 | }; | 431 | }; |
429 | 432 | ||
433 | /* Size (in bytes) of various events, as packed */ | ||
434 | static const int event_type_pk_size[] = { | ||
435 | IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */ | ||
436 | 0, | ||
437 | IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */ | ||
438 | 0, | ||
439 | IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */ | ||
440 | IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */ | ||
441 | IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */ | ||
442 | 0, | ||
443 | IW_EV_POINT_PK_LEN, /* Without variable payload */ | ||
444 | IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */ | ||
445 | IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */ | ||
446 | }; | ||
447 | |||
430 | /************************ COMMON SUBROUTINES ************************/ | 448 | /************************ COMMON SUBROUTINES ************************/ |
431 | /* | 449 | /* |
432 | * Stuff that may be used in various place or doesn't fit in one | 450 | * Stuff that may be used in various place or doesn't fit in one |
@@ -1217,7 +1235,7 @@ static int rtnetlink_standard_get(struct net_device * dev, | |||
1217 | memcpy(buffer + IW_EV_POINT_OFF, request, request_len); | 1235 | memcpy(buffer + IW_EV_POINT_OFF, request, request_len); |
1218 | /* Use our own copy of wrqu */ | 1236 | /* Use our own copy of wrqu */ |
1219 | wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF | 1237 | wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF |
1220 | + IW_EV_LCP_LEN); | 1238 | + IW_EV_LCP_PK_LEN); |
1221 | 1239 | ||
1222 | /* No extra arguments. Trivial to handle */ | 1240 | /* No extra arguments. Trivial to handle */ |
1223 | ret = handler(dev, &info, wrqu, NULL); | 1241 | ret = handler(dev, &info, wrqu, NULL); |
@@ -1229,8 +1247,8 @@ static int rtnetlink_standard_get(struct net_device * dev, | |||
1229 | 1247 | ||
1230 | /* Get a temp copy of wrqu (skip pointer) */ | 1248 | /* Get a temp copy of wrqu (skip pointer) */ |
1231 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | 1249 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, |
1232 | ((char *) request) + IW_EV_LCP_LEN, | 1250 | ((char *) request) + IW_EV_LCP_PK_LEN, |
1233 | IW_EV_POINT_LEN - IW_EV_LCP_LEN); | 1251 | IW_EV_POINT_LEN - IW_EV_LCP_PK_LEN); |
1234 | 1252 | ||
1235 | /* Calculate space needed by arguments. Always allocate | 1253 | /* Calculate space needed by arguments. Always allocate |
1236 | * for max space. Easier, and won't last long... */ | 1254 | * for max space. Easier, and won't last long... */ |
@@ -1240,7 +1258,7 @@ static int rtnetlink_standard_get(struct net_device * dev, | |||
1240 | (wrqu_point.data.length > descr->max_tokens)) | 1258 | (wrqu_point.data.length > descr->max_tokens)) |
1241 | extra_size = (wrqu_point.data.length | 1259 | extra_size = (wrqu_point.data.length |
1242 | * descr->token_size); | 1260 | * descr->token_size); |
1243 | buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF; | 1261 | buffer_size = extra_size + IW_EV_POINT_PK_LEN + IW_EV_POINT_OFF; |
1244 | #ifdef WE_RTNETLINK_DEBUG | 1262 | #ifdef WE_RTNETLINK_DEBUG |
1245 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", | 1263 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", |
1246 | dev->name, extra_size, buffer_size); | 1264 | dev->name, extra_size, buffer_size); |
@@ -1254,15 +1272,15 @@ static int rtnetlink_standard_get(struct net_device * dev, | |||
1254 | 1272 | ||
1255 | /* Put wrqu in the right place (just before extra). | 1273 | /* Put wrqu in the right place (just before extra). |
1256 | * Leave space for IWE header and dummy pointer... | 1274 | * Leave space for IWE header and dummy pointer... |
1257 | * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned... | 1275 | * Note that IW_EV_LCP_PK_LEN==4 bytes, so it's still aligned. |
1258 | */ | 1276 | */ |
1259 | memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF, | 1277 | memcpy(buffer + IW_EV_LCP_PK_LEN + IW_EV_POINT_OFF, |
1260 | ((char *) &wrqu_point) + IW_EV_POINT_OFF, | 1278 | ((char *) &wrqu_point) + IW_EV_POINT_OFF, |
1261 | IW_EV_POINT_LEN - IW_EV_LCP_LEN); | 1279 | IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); |
1262 | wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN); | 1280 | wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_PK_LEN); |
1263 | 1281 | ||
1264 | /* Extra comes logically after that. Offset +12 bytes. */ | 1282 | /* Extra comes logically after that. Offset +12 bytes. */ |
1265 | extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN; | 1283 | extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_PK_LEN; |
1266 | 1284 | ||
1267 | /* Call the handler */ | 1285 | /* Call the handler */ |
1268 | ret = handler(dev, &info, wrqu, extra); | 1286 | ret = handler(dev, &info, wrqu, extra); |
@@ -1270,11 +1288,11 @@ static int rtnetlink_standard_get(struct net_device * dev, | |||
1270 | /* Calculate real returned length */ | 1288 | /* Calculate real returned length */ |
1271 | extra_size = (wrqu->data.length * descr->token_size); | 1289 | extra_size = (wrqu->data.length * descr->token_size); |
1272 | /* Re-adjust reply size */ | 1290 | /* Re-adjust reply size */ |
1273 | request->len = extra_size + IW_EV_POINT_LEN; | 1291 | request->len = extra_size + IW_EV_POINT_PK_LEN; |
1274 | 1292 | ||
1275 | /* Put the iwe header where it should, i.e. scrap the | 1293 | /* Put the iwe header where it should, i.e. scrap the |
1276 | * dummy pointer. */ | 1294 | * dummy pointer. */ |
1277 | memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN); | 1295 | memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_PK_LEN); |
1278 | 1296 | ||
1279 | #ifdef WE_RTNETLINK_DEBUG | 1297 | #ifdef WE_RTNETLINK_DEBUG |
1280 | printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); | 1298 | printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); |
@@ -1331,10 +1349,10 @@ static inline int rtnetlink_standard_set(struct net_device * dev, | |||
1331 | #endif /* WE_RTNETLINK_DEBUG */ | 1349 | #endif /* WE_RTNETLINK_DEBUG */ |
1332 | 1350 | ||
1333 | /* Extract fixed header from request. This is properly aligned. */ | 1351 | /* Extract fixed header from request. This is properly aligned. */ |
1334 | wrqu = &request->u; | 1352 | wrqu = (union iwreq_data *) (((char *) request) + IW_EV_LCP_PK_LEN); |
1335 | 1353 | ||
1336 | /* Check if wrqu is complete */ | 1354 | /* Check if wrqu is complete */ |
1337 | hdr_len = event_type_size[descr->header_type]; | 1355 | hdr_len = event_type_pk_size[descr->header_type]; |
1338 | if(request_len < hdr_len) { | 1356 | if(request_len < hdr_len) { |
1339 | #ifdef WE_RTNETLINK_DEBUG | 1357 | #ifdef WE_RTNETLINK_DEBUG |
1340 | printk(KERN_DEBUG | 1358 | printk(KERN_DEBUG |
@@ -1359,7 +1377,7 @@ static inline int rtnetlink_standard_set(struct net_device * dev, | |||
1359 | 1377 | ||
1360 | /* Put wrqu in the right place (skip pointer) */ | 1378 | /* Put wrqu in the right place (skip pointer) */ |
1361 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | 1379 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, |
1362 | wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN); | 1380 | wrqu, IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); |
1363 | /* Don't forget about the event code... */ | 1381 | /* Don't forget about the event code... */ |
1364 | wrqu = &wrqu_point; | 1382 | wrqu = &wrqu_point; |
1365 | 1383 | ||
@@ -1483,7 +1501,7 @@ static inline int rtnetlink_private_get(struct net_device * dev, | |||
1483 | hdr_len = extra_size; | 1501 | hdr_len = extra_size; |
1484 | extra_size = 0; | 1502 | extra_size = 0; |
1485 | } else { | 1503 | } else { |
1486 | hdr_len = IW_EV_POINT_LEN; | 1504 | hdr_len = IW_EV_POINT_PK_LEN; |
1487 | } | 1505 | } |
1488 | 1506 | ||
1489 | /* Check if wrqu is complete */ | 1507 | /* Check if wrqu is complete */ |
@@ -1514,7 +1532,7 @@ static inline int rtnetlink_private_get(struct net_device * dev, | |||
1514 | memcpy(buffer + IW_EV_POINT_OFF, request, request_len); | 1532 | memcpy(buffer + IW_EV_POINT_OFF, request, request_len); |
1515 | /* Use our own copy of wrqu */ | 1533 | /* Use our own copy of wrqu */ |
1516 | wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF | 1534 | wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF |
1517 | + IW_EV_LCP_LEN); | 1535 | + IW_EV_LCP_PK_LEN); |
1518 | 1536 | ||
1519 | /* No extra arguments. Trivial to handle */ | 1537 | /* No extra arguments. Trivial to handle */ |
1520 | ret = handler(dev, &info, wrqu, (char *) wrqu); | 1538 | ret = handler(dev, &info, wrqu, (char *) wrqu); |
@@ -1523,7 +1541,7 @@ static inline int rtnetlink_private_get(struct net_device * dev, | |||
1523 | char * extra; | 1541 | char * extra; |
1524 | 1542 | ||
1525 | /* Buffer for full reply */ | 1543 | /* Buffer for full reply */ |
1526 | buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF; | 1544 | buffer_size = extra_size + IW_EV_POINT_PK_LEN + IW_EV_POINT_OFF; |
1527 | 1545 | ||
1528 | #ifdef WE_RTNETLINK_DEBUG | 1546 | #ifdef WE_RTNETLINK_DEBUG |
1529 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", | 1547 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", |
@@ -1538,15 +1556,15 @@ static inline int rtnetlink_private_get(struct net_device * dev, | |||
1538 | 1556 | ||
1539 | /* Put wrqu in the right place (just before extra). | 1557 | /* Put wrqu in the right place (just before extra). |
1540 | * Leave space for IWE header and dummy pointer... | 1558 | * Leave space for IWE header and dummy pointer... |
1541 | * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned... | 1559 | * Note that IW_EV_LCP_PK_LEN==4 bytes, so it's still aligned. |
1542 | */ | 1560 | */ |
1543 | memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF, | 1561 | memcpy(buffer + IW_EV_LCP_PK_LEN + IW_EV_POINT_OFF, |
1544 | ((char *) request) + IW_EV_LCP_LEN, | 1562 | ((char *) request) + IW_EV_LCP_PK_LEN, |
1545 | IW_EV_POINT_LEN - IW_EV_LCP_LEN); | 1563 | IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); |
1546 | wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN); | 1564 | wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_PK_LEN); |
1547 | 1565 | ||
1548 | /* Extra comes logically after that. Offset +12 bytes. */ | 1566 | /* Extra comes logically after that. Offset +12 bytes. */ |
1549 | extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN; | 1567 | extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_PK_LEN; |
1550 | 1568 | ||
1551 | /* Call the handler */ | 1569 | /* Call the handler */ |
1552 | ret = handler(dev, &info, wrqu, extra); | 1570 | ret = handler(dev, &info, wrqu, extra); |
@@ -1556,11 +1574,11 @@ static inline int rtnetlink_private_get(struct net_device * dev, | |||
1556 | if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) | 1574 | if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) |
1557 | extra_size = adjust_priv_size(descr->get_args, wrqu); | 1575 | extra_size = adjust_priv_size(descr->get_args, wrqu); |
1558 | /* Re-adjust reply size */ | 1576 | /* Re-adjust reply size */ |
1559 | request->len = extra_size + IW_EV_POINT_LEN; | 1577 | request->len = extra_size + IW_EV_POINT_PK_LEN; |
1560 | 1578 | ||
1561 | /* Put the iwe header where it should, i.e. scrap the | 1579 | /* Put the iwe header where it should, i.e. scrap the |
1562 | * dummy pointer. */ | 1580 | * dummy pointer. */ |
1563 | memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN); | 1581 | memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_PK_LEN); |
1564 | 1582 | ||
1565 | #ifdef WE_RTNETLINK_DEBUG | 1583 | #ifdef WE_RTNETLINK_DEBUG |
1566 | printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); | 1584 | printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); |
@@ -1641,14 +1659,14 @@ static inline int rtnetlink_private_set(struct net_device * dev, | |||
1641 | /* Does it fits in wrqu ? */ | 1659 | /* Does it fits in wrqu ? */ |
1642 | if((descr->set_args & IW_PRIV_SIZE_FIXED) && | 1660 | if((descr->set_args & IW_PRIV_SIZE_FIXED) && |
1643 | (extra_size <= IFNAMSIZ)) { | 1661 | (extra_size <= IFNAMSIZ)) { |
1644 | hdr_len = IW_EV_LCP_LEN + extra_size; | 1662 | hdr_len = IW_EV_LCP_PK_LEN + extra_size; |
1645 | extra_size = 0; | 1663 | extra_size = 0; |
1646 | } else { | 1664 | } else { |
1647 | hdr_len = IW_EV_POINT_LEN; | 1665 | hdr_len = IW_EV_POINT_PK_LEN; |
1648 | } | 1666 | } |
1649 | 1667 | ||
1650 | /* Extract fixed header from request. This is properly aligned. */ | 1668 | /* Extract fixed header from request. This is properly aligned. */ |
1651 | wrqu = &request->u; | 1669 | wrqu = (union iwreq_data *) (((char *) request) + IW_EV_LCP_PK_LEN); |
1652 | 1670 | ||
1653 | /* Check if wrqu is complete */ | 1671 | /* Check if wrqu is complete */ |
1654 | if(request_len < hdr_len) { | 1672 | if(request_len < hdr_len) { |
@@ -1675,7 +1693,7 @@ static inline int rtnetlink_private_set(struct net_device * dev, | |||
1675 | 1693 | ||
1676 | /* Put wrqu in the right place (skip pointer) */ | 1694 | /* Put wrqu in the right place (skip pointer) */ |
1677 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | 1695 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, |
1678 | wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN); | 1696 | wrqu, IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); |
1679 | 1697 | ||
1680 | /* Does it fits within bounds ? */ | 1698 | /* Does it fits within bounds ? */ |
1681 | if(wrqu_point.data.length > (descr->set_args & | 1699 | if(wrqu_point.data.length > (descr->set_args & |
@@ -1738,7 +1756,7 @@ int wireless_rtnetlink_get(struct net_device * dev, | |||
1738 | iw_handler handler; | 1756 | iw_handler handler; |
1739 | 1757 | ||
1740 | /* Check length */ | 1758 | /* Check length */ |
1741 | if(len < IW_EV_LCP_LEN) { | 1759 | if(len < IW_EV_LCP_PK_LEN) { |
1742 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", | 1760 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", |
1743 | dev->name, len); | 1761 | dev->name, len); |
1744 | return -EINVAL; | 1762 | return -EINVAL; |
@@ -1822,7 +1840,7 @@ int wireless_rtnetlink_set(struct net_device * dev, | |||
1822 | iw_handler handler; | 1840 | iw_handler handler; |
1823 | 1841 | ||
1824 | /* Check length */ | 1842 | /* Check length */ |
1825 | if(len < IW_EV_LCP_LEN) { | 1843 | if(len < IW_EV_LCP_PK_LEN) { |
1826 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", | 1844 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", |
1827 | dev->name, len); | 1845 | dev->name, len); |
1828 | return -EINVAL; | 1846 | return -EINVAL; |