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>
This commit is contained in:
parent
73345fd212
commit
0aedbcaf6f
|
@ -3092,6 +3092,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;
|
||||||
|
@ -3415,6 +3420,11 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
pfn_result = (struct brcmf_pno_scanresults_le *)data;
|
pfn_result = (struct brcmf_pno_scanresults_le *)data;
|
||||||
|
|
||||||
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
|
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
|
||||||
|
|
|
@ -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 {
|
||||||
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)
|
||||||
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)
|
||||||
* 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,
|
||||||
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,
|
||||||
/* 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 @@
|
||||||
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 {
|
||||||
/**
|
/**
|
||||||
* 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,
|
||||||
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_ */
|
||||||
|
|
|
@ -1361,6 +1361,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 */
|
||||||
|
@ -1858,6 +1863,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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue