123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- From: Hante Meuleman <meuleman@broadcom.com>
- Date: Wed, 17 Feb 2016 11:26:54 +0100
- Subject: [PATCH] brcmfmac: Add length checks on firmware events
- Add additional length checks on firmware events to create more
- robust code.
- Reviewed-by: Arend Van Spriel <arend@broadcom.com>
- Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
- Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
- Reviewed-by: Lei Zhang <leizh@broadcom.com>
- Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
- Signed-off-by: Arend van Spriel <arend@broadcom.com>
- Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
- ---
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
- @@ -3092,6 +3092,11 @@ brcmf_notify_sched_scan_results(struct b
-
- brcmf_dbg(SCAN, "Enter\n");
-
- + if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
- + brcmf_dbg(SCAN, "Event data to small. Ignore\n");
- + return 0;
- + }
- +
- if (e->event_code == BRCMF_E_PFN_NET_LOST) {
- brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
- return 0;
- @@ -3415,6 +3420,11 @@ brcmf_wowl_nd_results(struct brcmf_if *i
-
- brcmf_dbg(SCAN, "Enter\n");
-
- + if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
- + brcmf_dbg(SCAN, "Event data to small. Ignore\n");
- + return 0;
- + }
- +
- pfn_result = (struct brcmf_pno_scanresults_le *)data;
-
- if (e->event_code == BRCMF_E_PFN_NET_LOST) {
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
- @@ -26,50 +26,6 @@
- #include "fwil.h"
-
- /**
- - * struct brcm_ethhdr - broadcom specific ether header.
- - *
- - * @subtype: subtype for this packet.
- - * @length: TODO: length of appended data.
- - * @version: version indication.
- - * @oui: OUI of this packet.
- - * @usr_subtype: subtype for this OUI.
- - */
- -struct brcm_ethhdr {
- - __be16 subtype;
- - __be16 length;
- - u8 version;
- - u8 oui[3];
- - __be16 usr_subtype;
- -} __packed;
- -
- -struct brcmf_event_msg_be {
- - __be16 version;
- - __be16 flags;
- - __be32 event_type;
- - __be32 status;
- - __be32 reason;
- - __be32 auth_type;
- - __be32 datalen;
- - u8 addr[ETH_ALEN];
- - char ifname[IFNAMSIZ];
- - u8 ifidx;
- - u8 bsscfgidx;
- -} __packed;
- -
- -/**
- - * struct brcmf_event - contents of broadcom event packet.
- - *
- - * @eth: standard ether header.
- - * @hdr: broadcom specific ether header.
- - * @msg: common part of the actual event message.
- - */
- -struct brcmf_event {
- - struct ethhdr eth;
- - struct brcm_ethhdr hdr;
- - struct brcmf_event_msg_be msg;
- -} __packed;
- -
- -/**
- * struct brcmf_fweh_queue_item - event item on event queue.
- *
- * @q: list element for queuing.
- @@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item {
- u8 ifidx;
- u8 ifaddr[ETH_ALEN];
- struct brcmf_event_msg_be emsg;
- + u32 datalen;
- u8 data[0];
- };
-
- @@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(stru
- brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
- min_t(u32, emsg.datalen, 64),
- "event payload, len=%d\n", emsg.datalen);
- + if (emsg.datalen > event->datalen) {
- + brcmf_err("event invalid length header=%d, msg=%d\n",
- + event->datalen, emsg.datalen);
- + goto event_free;
- + }
-
- /* special handling of interface event */
- if (event->code == BRCMF_E_IF) {
- @@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct br
- * dispatch the event to a registered handler (using worker).
- */
- void brcmf_fweh_process_event(struct brcmf_pub *drvr,
- - struct brcmf_event *event_packet)
- + struct brcmf_event *event_packet,
- + u32 packet_len)
- {
- enum brcmf_fweh_event_code code;
- struct brcmf_fweh_info *fweh = &drvr->fweh;
- @@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brc
- if (code != BRCMF_E_IF && !fweh->evt_handler[code])
- return;
-
- + if (datalen > BRCMF_DCMD_MAXLEN)
- + return;
- +
- if (in_interrupt())
- alloc_flag = GFP_ATOMIC;
-
- @@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brc
- /* use memcpy to get aligned event message */
- memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
- memcpy(event->data, data, datalen);
- + event->datalen = datalen;
- memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
-
- brcmf_fweh_queue_event(fweh, event);
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
- @@ -27,7 +27,6 @@
- struct brcmf_pub;
- struct brcmf_if;
- struct brcmf_cfg80211_info;
- -struct brcmf_event;
-
- /* list of firmware events */
- #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
- @@ -180,13 +179,55 @@ enum brcmf_fweh_event_code {
- /**
- * definitions for event packet validation.
- */
- -#define BRCMF_EVENT_OUI_OFFSET 19
- -#define BRCM_OUI "\x00\x10\x18"
- -#define DOT11_OUI_LEN 3
- -#define BCMILCP_BCM_SUBTYPE_EVENT 1
- +#define BRCM_OUI "\x00\x10\x18"
- +#define BCMILCP_BCM_SUBTYPE_EVENT 1
-
-
- /**
- + * struct brcm_ethhdr - broadcom specific ether header.
- + *
- + * @subtype: subtype for this packet.
- + * @length: TODO: length of appended data.
- + * @version: version indication.
- + * @oui: OUI of this packet.
- + * @usr_subtype: subtype for this OUI.
- + */
- +struct brcm_ethhdr {
- + __be16 subtype;
- + __be16 length;
- + u8 version;
- + u8 oui[3];
- + __be16 usr_subtype;
- +} __packed;
- +
- +struct brcmf_event_msg_be {
- + __be16 version;
- + __be16 flags;
- + __be32 event_type;
- + __be32 status;
- + __be32 reason;
- + __be32 auth_type;
- + __be32 datalen;
- + u8 addr[ETH_ALEN];
- + char ifname[IFNAMSIZ];
- + u8 ifidx;
- + u8 bsscfgidx;
- +} __packed;
- +
- +/**
- + * struct brcmf_event - contents of broadcom event packet.
- + *
- + * @eth: standard ether header.
- + * @hdr: broadcom specific ether header.
- + * @msg: common part of the actual event message.
- + */
- +struct brcmf_event {
- + struct ethhdr eth;
- + struct brcm_ethhdr hdr;
- + struct brcmf_event_msg_be msg;
- +} __packed;
- +
- +/**
- * struct brcmf_event_msg - firmware event message.
- *
- * @version: version information.
- @@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_
- enum brcmf_fweh_event_code code);
- int brcmf_fweh_activate_events(struct brcmf_if *ifp);
- void brcmf_fweh_process_event(struct brcmf_pub *drvr,
- - struct brcmf_event *event_packet);
- + struct brcmf_event *event_packet,
- + u32 packet_len);
- void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
-
- static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
- struct sk_buff *skb)
- {
- struct brcmf_event *event_packet;
- - u8 *data;
- u16 usr_stype;
-
- /* only process events when protocol matches */
- if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
- return;
-
- + if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
- + return;
- +
- /* check for BRCM oui match */
- event_packet = (struct brcmf_event *)skb_mac_header(skb);
- - data = (u8 *)event_packet;
- - data += BRCMF_EVENT_OUI_OFFSET;
- - if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
- + if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
- + sizeof(event_packet->hdr.oui)))
- return;
-
- /* final match on usr_subtype */
- - data += DOT11_OUI_LEN;
- - usr_stype = get_unaligned_be16(data);
- + usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
- if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
- return;
-
- - brcmf_fweh_process_event(drvr, event_packet);
- + brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
- }
-
- #endif /* FWEH_H_ */
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
- @@ -1361,6 +1361,11 @@ int brcmf_p2p_notify_action_frame_rx(str
- u16 mgmt_type;
- u8 action;
-
- + if (e->datalen < sizeof(*rxframe)) {
- + brcmf_dbg(SCAN, "Event data to small. Ignore\n");
- + return 0;
- + }
- +
- ch.chspec = be16_to_cpu(rxframe->chanspec);
- cfg->d11inf.decchspec(&ch);
- /* Check if wpa_supplicant has registered for this frame */
- @@ -1858,6 +1863,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere
- brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
- e->reason);
-
- + if (e->datalen < sizeof(*rxframe)) {
- + brcmf_dbg(SCAN, "Event data to small. Ignore\n");
- + return 0;
- + }
- +
- ch.chspec = be16_to_cpu(rxframe->chanspec);
- cfg->d11inf.decchspec(&ch);
-
|