aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-03-27 07:40:28 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:54:27 -0400
commitf4a11bb0c2d5968ea35f95bdbabdd453862f202a (patch)
treeef0277c3e333ea3a402dbfbd6c13fa60a4b9702b /net/wireless/nl80211.c
parentb0741a1a2b00d9b4d88ba60016c88e42f176e4d6 (diff)
nl80211: validate some input better
This patch changes nl80211 to: * validate that any IE input is a valid IE (stream) * move some validation code before locking * require that a reason code is given for both deauth/disassoc Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c114
1 files changed, 77 insertions, 37 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2456e4ee445e..2f449ddcbc72 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -118,6 +118,36 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
118 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, 118 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
119}; 119};
120 120
121/* IE validation */
122static bool is_valid_ie_attr(const struct nlattr *attr)
123{
124 const u8 *pos;
125 int len;
126
127 if (!attr)
128 return true;
129
130 pos = nla_data(attr);
131 len = nla_len(attr);
132
133 while (len) {
134 u8 elemlen;
135
136 if (len < 2)
137 return false;
138 len -= 2;
139
140 elemlen = pos[1];
141 if (elemlen > len)
142 return false;
143
144 len -= elemlen;
145 pos += 2 + elemlen;
146 }
147
148 return true;
149}
150
121/* message building helper */ 151/* message building helper */
122static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, 152static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
123 int flags, u8 cmd) 153 int flags, u8 cmd)
@@ -1069,6 +1099,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
1069 struct beacon_parameters params; 1099 struct beacon_parameters params;
1070 int haveinfo = 0; 1100 int haveinfo = 0;
1071 1101
1102 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
1103 return -EINVAL;
1104
1072 rtnl_lock(); 1105 rtnl_lock();
1073 1106
1074 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1107 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2442,6 +2475,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2442 enum ieee80211_band band; 2475 enum ieee80211_band band;
2443 size_t ie_len; 2476 size_t ie_len;
2444 2477
2478 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
2479 return -EINVAL;
2480
2445 rtnl_lock(); 2481 rtnl_lock();
2446 2482
2447 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 2483 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2710,6 +2746,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
2710 struct wiphy *wiphy; 2746 struct wiphy *wiphy;
2711 int err; 2747 int err;
2712 2748
2749 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
2750 return -EINVAL;
2751
2752 if (!info->attrs[NL80211_ATTR_MAC])
2753 return -EINVAL;
2754
2713 rtnl_lock(); 2755 rtnl_lock();
2714 2756
2715 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 2757 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2731,11 +2773,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
2731 goto out; 2773 goto out;
2732 } 2774 }
2733 2775
2734 if (!info->attrs[NL80211_ATTR_MAC]) {
2735 err = -EINVAL;
2736 goto out;
2737 }
2738
2739 wiphy = &drv->wiphy; 2776 wiphy = &drv->wiphy;
2740 memset(&req, 0, sizeof(req)); 2777 memset(&req, 0, sizeof(req));
2741 2778
@@ -2788,6 +2825,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
2788 struct wiphy *wiphy; 2825 struct wiphy *wiphy;
2789 int err; 2826 int err;
2790 2827
2828 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
2829 return -EINVAL;
2830
2831 if (!info->attrs[NL80211_ATTR_MAC] ||
2832 !info->attrs[NL80211_ATTR_SSID])
2833 return -EINVAL;
2834
2791 rtnl_lock(); 2835 rtnl_lock();
2792 2836
2793 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 2837 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2809,12 +2853,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
2809 goto out; 2853 goto out;
2810 } 2854 }
2811 2855
2812 if (!info->attrs[NL80211_ATTR_MAC] ||
2813 !info->attrs[NL80211_ATTR_SSID]) {
2814 err = -EINVAL;
2815 goto out;
2816 }
2817
2818 wiphy = &drv->wiphy; 2856 wiphy = &drv->wiphy;
2819 memset(&req, 0, sizeof(req)); 2857 memset(&req, 0, sizeof(req));
2820 2858
@@ -2856,6 +2894,15 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
2856 struct wiphy *wiphy; 2894 struct wiphy *wiphy;
2857 int err; 2895 int err;
2858 2896
2897 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
2898 return -EINVAL;
2899
2900 if (!info->attrs[NL80211_ATTR_MAC])
2901 return -EINVAL;
2902
2903 if (!info->attrs[NL80211_ATTR_REASON_CODE])
2904 return -EINVAL;
2905
2859 rtnl_lock(); 2906 rtnl_lock();
2860 2907
2861 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 2908 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2877,24 +2924,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
2877 goto out; 2924 goto out;
2878 } 2925 }
2879 2926
2880 if (!info->attrs[NL80211_ATTR_MAC]) {
2881 err = -EINVAL;
2882 goto out;
2883 }
2884
2885 wiphy = &drv->wiphy; 2927 wiphy = &drv->wiphy;
2886 memset(&req, 0, sizeof(req)); 2928 memset(&req, 0, sizeof(req));
2887 2929
2888 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 2930 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2889 2931
2890 if (info->attrs[NL80211_ATTR_REASON_CODE]) { 2932 req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
2891 req.reason_code = 2933 if (req.reason_code == 0) {
2892 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); 2934 /* Reason Code 0 is reserved */
2893 if (req.reason_code == 0) { 2935 err = -EINVAL;
2894 /* Reason Code 0 is reserved */ 2936 goto out;
2895 err = -EINVAL;
2896 goto out;
2897 }
2898 } 2937 }
2899 2938
2900 if (info->attrs[NL80211_ATTR_IE]) { 2939 if (info->attrs[NL80211_ATTR_IE]) {
@@ -2920,6 +2959,15 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
2920 struct wiphy *wiphy; 2959 struct wiphy *wiphy;
2921 int err; 2960 int err;
2922 2961
2962 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
2963 return -EINVAL;
2964
2965 if (!info->attrs[NL80211_ATTR_MAC])
2966 return -EINVAL;
2967
2968 if (!info->attrs[NL80211_ATTR_REASON_CODE])
2969 return -EINVAL;
2970
2923 rtnl_lock(); 2971 rtnl_lock();
2924 2972
2925 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 2973 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2941,24 +2989,16 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
2941 goto out; 2989 goto out;
2942 } 2990 }
2943 2991
2944 if (!info->attrs[NL80211_ATTR_MAC]) {
2945 err = -EINVAL;
2946 goto out;
2947 }
2948
2949 wiphy = &drv->wiphy; 2992 wiphy = &drv->wiphy;
2950 memset(&req, 0, sizeof(req)); 2993 memset(&req, 0, sizeof(req));
2951 2994
2952 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 2995 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2953 2996
2954 if (info->attrs[NL80211_ATTR_REASON_CODE]) { 2997 req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
2955 req.reason_code = 2998 if (req.reason_code == 0) {
2956 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); 2999 /* Reason Code 0 is reserved */
2957 if (req.reason_code == 0) { 3000 err = -EINVAL;
2958 /* Reason Code 0 is reserved */ 3001 goto out;
2959 err = -EINVAL;
2960 goto out;
2961 }
2962 } 3002 }
2963 3003
2964 if (info->attrs[NL80211_ATTR_IE]) { 3004 if (info->attrs[NL80211_ATTR_IE]) {