aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/cfg80211.h9
-rw-r--r--net/mac80211/rx.c32
-rw-r--r--net/wireless/util.c3
3 files changed, 42 insertions, 2 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f8cd4cf3fad8..7d5b6000378b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2652,6 +2652,15 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
2652unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc); 2652unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc);
2653 2653
2654/** 2654/**
2655 * ieee80211_get_mesh_hdrlen - get mesh extension header length
2656 * @meshhdr: the mesh extension header, only the flags field
2657 * (first byte) will be accessed
2658 * Returns the length of the extension header, which is always at
2659 * least 6 bytes and at most 18 if address 5 and 6 are present.
2660 */
2661unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
2662
2663/**
2655 * DOC: Data path helpers 2664 * DOC: Data path helpers
2656 * 2665 *
2657 * In addition to generic utilities, cfg80211 also offers 2666 * In addition to generic utilities, cfg80211 also offers
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)