Commit 521dcf79 authored by Hante Meuleman's avatar Hante Meuleman Committed by Kleber Sacilotto de Souza

brcmfmac: Add length checks on firmware events

BugLink: https://bugs.launchpad.net/bugs/1832661

commit 0aedbcaf upstream.

Add additional length checks on firmware events to create more
robust code.
Reviewed-by: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarLei Zhang <leizh@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
[bwh: Backported to 4.4:
 - Drop changes to brcmf_wowl_nd_results()
 - Adjust filenames]
Signed-off-by: default avatarBen Hutchings <ben.hutchings@codethink.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 41380d81
...@@ -3331,6 +3331,11 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, ...@@ -3331,6 +3331,11 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
brcmf_dbg(SCAN, "Enter\n"); 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) { if (e->event_code == BRCMF_E_PFN_NET_LOST) {
brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n"); brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
return 0; return 0;
......
...@@ -25,50 +25,6 @@ ...@@ -25,50 +25,6 @@
#include "fweh.h" #include "fweh.h"
#include "fwil.h" #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. * struct brcmf_fweh_queue_item - event item on event queue.
* *
...@@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item { ...@@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item {
u8 ifidx; u8 ifidx;
u8 ifaddr[ETH_ALEN]; u8 ifaddr[ETH_ALEN];
struct brcmf_event_msg_be emsg; struct brcmf_event_msg_be emsg;
u32 datalen;
u8 data[0]; u8 data[0];
}; };
...@@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(struct work_struct *work) ...@@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
min_t(u32, emsg.datalen, 64), min_t(u32, emsg.datalen, 64),
"event payload, len=%d\n", emsg.datalen); "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 */ /* special handling of interface event */
if (event->code == BRCMF_E_IF) { if (event->code == BRCMF_E_IF) {
...@@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp) ...@@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp)
* dispatch the event to a registered handler (using worker). * dispatch the event to a registered handler (using worker).
*/ */
void brcmf_fweh_process_event(struct brcmf_pub *drvr, 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; enum brcmf_fweh_event_code code;
struct brcmf_fweh_info *fweh = &drvr->fweh; struct brcmf_fweh_info *fweh = &drvr->fweh;
...@@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, ...@@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
if (code != BRCMF_E_IF && !fweh->evt_handler[code]) if (code != BRCMF_E_IF && !fweh->evt_handler[code])
return; return;
if (datalen > BRCMF_DCMD_MAXLEN)
return;
if (in_interrupt()) if (in_interrupt())
alloc_flag = GFP_ATOMIC; alloc_flag = GFP_ATOMIC;
...@@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, ...@@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
/* use memcpy to get aligned event message */ /* use memcpy to get aligned event message */
memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
memcpy(event->data, data, datalen); memcpy(event->data, data, datalen);
event->datalen = datalen;
memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
brcmf_fweh_queue_event(fweh, event); brcmf_fweh_queue_event(fweh, event);
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
struct brcmf_pub; struct brcmf_pub;
struct brcmf_if; struct brcmf_if;
struct brcmf_cfg80211_info; struct brcmf_cfg80211_info;
struct brcmf_event;
/* list of firmware events */ /* list of firmware events */
#define BRCMF_FWEH_EVENT_ENUM_DEFLIST \ #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
...@@ -180,12 +179,54 @@ enum brcmf_fweh_event_code { ...@@ -180,12 +179,54 @@ enum brcmf_fweh_event_code {
/** /**
* definitions for event packet validation. * definitions for event packet validation.
*/ */
#define BRCMF_EVENT_OUI_OFFSET 19 #define BRCM_OUI "\x00\x10\x18"
#define BRCM_OUI "\x00\x10\x18" #define BCMILCP_BCM_SUBTYPE_EVENT 1
#define DOT11_OUI_LEN 3
#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. * struct brcmf_event_msg - firmware event message.
* *
...@@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr, ...@@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr,
enum brcmf_fweh_event_code code); enum brcmf_fweh_event_code code);
int brcmf_fweh_activate_events(struct brcmf_if *ifp); int brcmf_fweh_activate_events(struct brcmf_if *ifp);
void brcmf_fweh_process_event(struct brcmf_pub *drvr, 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); void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr, static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct brcmf_event *event_packet; struct brcmf_event *event_packet;
u8 *data;
u16 usr_stype; u16 usr_stype;
/* only process events when protocol matches */ /* only process events when protocol matches */
if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL)) if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
return; return;
if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
return;
/* check for BRCM oui match */ /* check for BRCM oui match */
event_packet = (struct brcmf_event *)skb_mac_header(skb); event_packet = (struct brcmf_event *)skb_mac_header(skb);
data = (u8 *)event_packet; if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
data += BRCMF_EVENT_OUI_OFFSET; sizeof(event_packet->hdr.oui)))
if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
return; return;
/* final match on usr_subtype */ /* final match on usr_subtype */
data += DOT11_OUI_LEN; usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
usr_stype = get_unaligned_be16(data);
if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT) if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
return; return;
brcmf_fweh_process_event(drvr, event_packet); brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
} }
#endif /* FWEH_H_ */ #endif /* FWEH_H_ */
...@@ -1365,6 +1365,11 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, ...@@ -1365,6 +1365,11 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
u16 mgmt_type; u16 mgmt_type;
u8 action; 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); ch.chspec = be16_to_cpu(rxframe->chanspec);
cfg->d11inf.decchspec(&ch); cfg->d11inf.decchspec(&ch);
/* Check if wpa_supplicant has registered for this frame */ /* Check if wpa_supplicant has registered for this frame */
...@@ -1862,6 +1867,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, ...@@ -1862,6 +1867,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code, brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
e->reason); 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); ch.chspec = be16_to_cpu(rxframe->chanspec);
cfg->d11inf.decchspec(&ch); cfg->d11inf.decchspec(&ch);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment