diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-03-27 07:40:28 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-04-22 16:54:27 -0400 |
commit | f4a11bb0c2d5968ea35f95bdbabdd453862f202a (patch) | |
tree | ef0277c3e333ea3a402dbfbd6c13fa60a4b9702b /net/wireless | |
parent | b0741a1a2b00d9b4d88ba60016c88e42f176e4d6 (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')
-rw-r--r-- | net/wireless/nl80211.c | 114 |
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 */ | ||
122 | static 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 */ |
122 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, | 152 | static 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]) { |