344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch 7.9 KB

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