aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-10-25 18:36:40 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-10-26 16:52:42 -0400
commit9b395bc3be1cebf0144a127c7e67d56dbdac0930 (patch)
tree9cbe0d8566b890f43cd8d9f884f8b78104775f29 /net
parent4a4f1a5808c8bb0b72a4f6e5904c53fb8c9cd966 (diff)
mac80211: verify that skb data is present
A number of places in the mesh code don't check that the frame data is present and in the skb header when trying to access. Add those checks and the necessary pskb_may_pull() calls. This prevents accessing data that doesn't actually exist. To do this, export ieee80211_get_mesh_hdrlen() to be able to use it in mac80211. Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/rx.c32
-rw-r--r--net/wireless/util.c3
2 files changed, 33 insertions, 2 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 99cdee16e31b..265a032dec49 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -531,6 +531,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
531 531
532 if (ieee80211_is_action(hdr->frame_control)) { 532 if (ieee80211_is_action(hdr->frame_control)) {
533 u8 category; 533 u8 category;
534
535 /* make sure category field is present */
536 if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
537 return RX_DROP_MONITOR;
538
534 mgmt = (struct ieee80211_mgmt *)hdr; 539 mgmt = (struct ieee80211_mgmt *)hdr;
535 category = mgmt->u.action.category; 540 category = mgmt->u.action.category;
536 if (category != WLAN_CATEGORY_MESH_ACTION && 541 if (category != WLAN_CATEGORY_MESH_ACTION &&
@@ -1892,6 +1897,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1892 1897
1893 hdr = (struct ieee80211_hdr *) skb->data; 1898 hdr = (struct ieee80211_hdr *) skb->data;
1894 hdrlen = ieee80211_hdrlen(hdr->frame_control); 1899 hdrlen = ieee80211_hdrlen(hdr->frame_control);
1900
1901 /* make sure fixed part of mesh header is there, also checks skb len */
1902 if (!pskb_may_pull(rx->skb, hdrlen + 6))
1903 return RX_DROP_MONITOR;
1904
1905 mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
1906
1907 /* make sure full mesh header is there, also checks skb len */
1908 if (!pskb_may_pull(rx->skb,
1909 hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
1910 return RX_DROP_MONITOR;
1911
1912 /* reload pointers */
1913 hdr = (struct ieee80211_hdr *) skb->data;
1895 mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); 1914 mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
1896 1915
1897 /* frame is in RMC, don't forward */ 1916 /* frame is in RMC, don't forward */
@@ -1915,9 +1934,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1915 if (is_multicast_ether_addr(hdr->addr1)) { 1934 if (is_multicast_ether_addr(hdr->addr1)) {
1916 mpp_addr = hdr->addr3; 1935 mpp_addr = hdr->addr3;
1917 proxied_addr = mesh_hdr->eaddr1; 1936 proxied_addr = mesh_hdr->eaddr1;
1918 } else { 1937 } else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) {
1938 /* has_a4 already checked in ieee80211_rx_mesh_check */
1919 mpp_addr = hdr->addr4; 1939 mpp_addr = hdr->addr4;
1920 proxied_addr = mesh_hdr->eaddr2; 1940 proxied_addr = mesh_hdr->eaddr2;
1941 } else {
1942 return RX_DROP_MONITOR;
1921 } 1943 }
1922 1944
1923 rcu_read_lock(); 1945 rcu_read_lock();
@@ -2354,6 +2376,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2354 } 2376 }
2355 break; 2377 break;
2356 case WLAN_CATEGORY_SELF_PROTECTED: 2378 case WLAN_CATEGORY_SELF_PROTECTED:
2379 if (len < (IEEE80211_MIN_ACTION_SIZE +
2380 sizeof(mgmt->u.action.u.self_prot.action_code)))
2381 break;
2382
2357 switch (mgmt->u.action.u.self_prot.action_code) { 2383 switch (mgmt->u.action.u.self_prot.action_code) {
2358 case WLAN_SP_MESH_PEERING_OPEN: 2384 case WLAN_SP_MESH_PEERING_OPEN:
2359 case WLAN_SP_MESH_PEERING_CLOSE: 2385 case WLAN_SP_MESH_PEERING_CLOSE:
@@ -2372,6 +2398,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2372 } 2398 }
2373 break; 2399 break;
2374 case WLAN_CATEGORY_MESH_ACTION: 2400 case WLAN_CATEGORY_MESH_ACTION:
2401 if (len < (IEEE80211_MIN_ACTION_SIZE +
2402 sizeof(mgmt->u.action.u.mesh_action.action_code)))
2403 break;
2404
2375 if (!ieee80211_vif_is_mesh(&sdata->vif)) 2405 if (!ieee80211_vif_is_mesh(&sdata->vif))
2376 break; 2406 break;
2377 if (mesh_action_is_path_sel(mgmt) && 2407 if (mesh_action_is_path_sel(mgmt) &&
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 45a09de1ffe3..2762e8329986 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -309,7 +309,7 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
309} 309}
310EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); 310EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
311 311
312static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) 312unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
313{ 313{
314 int ae = meshhdr->flags & MESH_FLAGS_AE; 314 int ae = meshhdr->flags & MESH_FLAGS_AE;
315 /* 802.11-2012, 8.2.4.7.3 */ 315 /* 802.11-2012, 8.2.4.7.3 */
@@ -323,6 +323,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
323 return 18; 323 return 18;
324 } 324 }
325} 325}
326EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
326 327
327int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, 328int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
328 enum nl80211_iftype iftype) 329 enum nl80211_iftype iftype)