mac80211: backport brcmfmac patchset with driver setting concept
[openwrt.git] / package / kernel / mac80211 / patches / 344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch
1 From: Hante Meuleman <meuleman@broadcom.com>
2 Date: Wed, 17 Feb 2016 11:26:54 +0100
3 Subject: [PATCH] brcmfmac: Add length checks on firmware events
4
5 Add additional length checks on firmware events to create more
6 robust code.
7
8 Reviewed-by: Arend Van Spriel <arend@broadcom.com>
9 Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
10 Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
11 Reviewed-by: Lei Zhang <leizh@broadcom.com>
12 Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
13 Signed-off-by: Arend van Spriel <arend@broadcom.com>
14 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
15 ---
16
17 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
18 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
19 @@ -3092,6 +3092,11 @@ brcmf_notify_sched_scan_results(struct b
20  
21         brcmf_dbg(SCAN, "Enter\n");
22  
23 +       if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
24 +               brcmf_dbg(SCAN, "Event data to small. Ignore\n");
25 +               return 0;
26 +       }
27 +
28         if (e->event_code == BRCMF_E_PFN_NET_LOST) {
29                 brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
30                 return 0;
31 @@ -3415,6 +3420,11 @@ brcmf_wowl_nd_results(struct brcmf_if *i
32  
33         brcmf_dbg(SCAN, "Enter\n");
34  
35 +       if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
36 +               brcmf_dbg(SCAN, "Event data to small. Ignore\n");
37 +               return 0;
38 +       }
39 +
40         pfn_result = (struct brcmf_pno_scanresults_le *)data;
41  
42         if (e->event_code == BRCMF_E_PFN_NET_LOST) {
43 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
44 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
45 @@ -26,50 +26,6 @@
46  #include "fwil.h"
47  
48  /**
49 - * struct brcm_ethhdr - broadcom specific ether header.
50 - *
51 - * @subtype: subtype for this packet.
52 - * @length: TODO: length of appended data.
53 - * @version: version indication.
54 - * @oui: OUI of this packet.
55 - * @usr_subtype: subtype for this OUI.
56 - */
57 -struct brcm_ethhdr {
58 -       __be16 subtype;
59 -       __be16 length;
60 -       u8 version;
61 -       u8 oui[3];
62 -       __be16 usr_subtype;
63 -} __packed;
64 -
65 -struct brcmf_event_msg_be {
66 -       __be16 version;
67 -       __be16 flags;
68 -       __be32 event_type;
69 -       __be32 status;
70 -       __be32 reason;
71 -       __be32 auth_type;
72 -       __be32 datalen;
73 -       u8 addr[ETH_ALEN];
74 -       char ifname[IFNAMSIZ];
75 -       u8 ifidx;
76 -       u8 bsscfgidx;
77 -} __packed;
78 -
79 -/**
80 - * struct brcmf_event - contents of broadcom event packet.
81 - *
82 - * @eth: standard ether header.
83 - * @hdr: broadcom specific ether header.
84 - * @msg: common part of the actual event message.
85 - */
86 -struct brcmf_event {
87 -       struct ethhdr eth;
88 -       struct brcm_ethhdr hdr;
89 -       struct brcmf_event_msg_be msg;
90 -} __packed;
91 -
92 -/**
93   * struct brcmf_fweh_queue_item - event item on event queue.
94   *
95   * @q: list element for queuing.
96 @@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item {
97         u8 ifidx;
98         u8 ifaddr[ETH_ALEN];
99         struct brcmf_event_msg_be emsg;
100 +       u32 datalen;
101         u8 data[0];
102  };
103  
104 @@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(stru
105                 brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
106                                    min_t(u32, emsg.datalen, 64),
107                                    "event payload, len=%d\n", emsg.datalen);
108 +               if (emsg.datalen > event->datalen) {
109 +                       brcmf_err("event invalid length header=%d, msg=%d\n",
110 +                                 event->datalen, emsg.datalen);
111 +                       goto event_free;
112 +               }
113  
114                 /* special handling of interface event */
115                 if (event->code == BRCMF_E_IF) {
116 @@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct br
117   * dispatch the event to a registered handler (using worker).
118   */
119  void brcmf_fweh_process_event(struct brcmf_pub *drvr,
120 -                             struct brcmf_event *event_packet)
121 +                             struct brcmf_event *event_packet,
122 +                             u32 packet_len)
123  {
124         enum brcmf_fweh_event_code code;
125         struct brcmf_fweh_info *fweh = &drvr->fweh;
126 @@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brc
127         if (code != BRCMF_E_IF && !fweh->evt_handler[code])
128                 return;
129  
130 +       if (datalen > BRCMF_DCMD_MAXLEN)
131 +               return;
132 +
133         if (in_interrupt())
134                 alloc_flag = GFP_ATOMIC;
135  
136 @@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brc
137         /* use memcpy to get aligned event message */
138         memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
139         memcpy(event->data, data, datalen);
140 +       event->datalen = datalen;
141         memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
142  
143         brcmf_fweh_queue_event(fweh, event);
144 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
145 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
146 @@ -27,7 +27,6 @@
147  struct brcmf_pub;
148  struct brcmf_if;
149  struct brcmf_cfg80211_info;
150 -struct brcmf_event;
151  
152  /* list of firmware events */
153  #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
154 @@ -180,13 +179,55 @@ enum brcmf_fweh_event_code {
155  /**
156   * definitions for event packet validation.
157   */
158 -#define BRCMF_EVENT_OUI_OFFSET         19
159 -#define BRCM_OUI                       "\x00\x10\x18"
160 -#define DOT11_OUI_LEN                  3
161 -#define BCMILCP_BCM_SUBTYPE_EVENT      1
162 +#define BRCM_OUI                               "\x00\x10\x18"
163 +#define BCMILCP_BCM_SUBTYPE_EVENT              1
164  
165  
166  /**
167 + * struct brcm_ethhdr - broadcom specific ether header.
168 + *
169 + * @subtype: subtype for this packet.
170 + * @length: TODO: length of appended data.
171 + * @version: version indication.
172 + * @oui: OUI of this packet.
173 + * @usr_subtype: subtype for this OUI.
174 + */
175 +struct brcm_ethhdr {
176 +       __be16 subtype;
177 +       __be16 length;
178 +       u8 version;
179 +       u8 oui[3];
180 +       __be16 usr_subtype;
181 +} __packed;
182 +
183 +struct brcmf_event_msg_be {
184 +       __be16 version;
185 +       __be16 flags;
186 +       __be32 event_type;
187 +       __be32 status;
188 +       __be32 reason;
189 +       __be32 auth_type;
190 +       __be32 datalen;
191 +       u8 addr[ETH_ALEN];
192 +       char ifname[IFNAMSIZ];
193 +       u8 ifidx;
194 +       u8 bsscfgidx;
195 +} __packed;
196 +
197 +/**
198 + * struct brcmf_event - contents of broadcom event packet.
199 + *
200 + * @eth: standard ether header.
201 + * @hdr: broadcom specific ether header.
202 + * @msg: common part of the actual event message.
203 + */
204 +struct brcmf_event {
205 +       struct ethhdr eth;
206 +       struct brcm_ethhdr hdr;
207 +       struct brcmf_event_msg_be msg;
208 +} __packed;
209 +
210 +/**
211   * struct brcmf_event_msg - firmware event message.
212   *
213   * @version: version information.
214 @@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_
215                            enum brcmf_fweh_event_code code);
216  int brcmf_fweh_activate_events(struct brcmf_if *ifp);
217  void brcmf_fweh_process_event(struct brcmf_pub *drvr,
218 -                             struct brcmf_event *event_packet);
219 +                             struct brcmf_event *event_packet,
220 +                             u32 packet_len);
221  void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
222  
223  static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
224                                           struct sk_buff *skb)
225  {
226         struct brcmf_event *event_packet;
227 -       u8 *data;
228         u16 usr_stype;
229  
230         /* only process events when protocol matches */
231         if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
232                 return;
233  
234 +       if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
235 +               return;
236 +
237         /* check for BRCM oui match */
238         event_packet = (struct brcmf_event *)skb_mac_header(skb);
239 -       data = (u8 *)event_packet;
240 -       data += BRCMF_EVENT_OUI_OFFSET;
241 -       if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
242 +       if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
243 +                  sizeof(event_packet->hdr.oui)))
244                 return;
245  
246         /* final match on usr_subtype */
247 -       data += DOT11_OUI_LEN;
248 -       usr_stype = get_unaligned_be16(data);
249 +       usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
250         if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
251                 return;
252  
253 -       brcmf_fweh_process_event(drvr, event_packet);
254 +       brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
255  }
256  
257  #endif /* FWEH_H_ */
258 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
259 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
260 @@ -1361,6 +1361,11 @@ int brcmf_p2p_notify_action_frame_rx(str
261         u16 mgmt_type;
262         u8 action;
263  
264 +       if (e->datalen < sizeof(*rxframe)) {
265 +               brcmf_dbg(SCAN, "Event data to small. Ignore\n");
266 +               return 0;
267 +       }
268 +
269         ch.chspec = be16_to_cpu(rxframe->chanspec);
270         cfg->d11inf.decchspec(&ch);
271         /* Check if wpa_supplicant has registered for this frame */
272 @@ -1858,6 +1863,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere
273         brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
274                   e->reason);
275  
276 +       if (e->datalen < sizeof(*rxframe)) {
277 +               brcmf_dbg(SCAN, "Event data to small. Ignore\n");
278 +               return 0;
279 +       }
280 +
281         ch.chspec = be16_to_cpu(rxframe->chanspec);
282         cfg->d11inf.decchspec(&ch);
283