dbd9ea74890987c345f800db84141474466608d1
[oweals/openwrt.git] /
1 From 1259055170287a350cad453e9eac139c81609860 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
3 Date: Thu, 15 Mar 2018 08:29:09 +0100
4 Subject: [PATCH] brcmfmac: drop Inter-Access Point Protocol packets by default
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 Testing brcmfmac with more recent firmwares resulted in AP interfaces
10 not working in some specific setups. Debugging resulted in discovering
11 support for IAPP in Broadcom's firmwares.
12
13 Older firmwares were only generating 802.11f frames. Newer ones like:
14 1) 10.10 (TOB) (r663589)
15 2) 10.10.122.20 (r683106)
16 for 4366b1 and 4366c0 respectively seem to also /respect/ 802.11f frames
17 in the Tx path by performing a STA disassociation.
18
19 This obsoleted standard and its implementation is something that:
20 1) Most people don't need / want to use
21 2) Can allow local DoS attacks
22 3) Breaks AP interfaces in some specific bridge setups
23
24 To solve issues it can cause this commit modifies brcmfmac to drop IAPP
25 packets. If affects:
26 1) Rx path: driver won't be sending these unwanted packets up.
27 2) Tx path: driver will reject packets that would trigger STA
28    disassociation perfromed by a firmware (possible local DoS attack).
29
30 It appears there are some Broadcom's clients/users who care about this
31 feature despite the drawbacks. They can switch it on using a new module
32 param.
33
34 This change results in only two more comparisons (check for module param
35 and check for Ethernet packet length) for 99.9% of packets. Its overhead
36 should be very minimal.
37
38 Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
39 Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
40 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
41 ---
42  .../wireless/broadcom/brcm80211/brcmfmac/common.c  |  5 ++
43  .../wireless/broadcom/brcm80211/brcmfmac/common.h  |  1 +
44  .../wireless/broadcom/brcm80211/brcmfmac/core.c    | 57 ++++++++++++++++++++++
45  3 files changed, 63 insertions(+)
46
47 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
48 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
49 @@ -73,6 +73,10 @@ static int brcmf_roamoff;
50  module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
51  MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
52  
53 +static int brcmf_iapp_enable;
54 +module_param_named(iapp, brcmf_iapp_enable, int, 0);
55 +MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
56 +
57  #ifdef DEBUG
58  /* always succeed brcmf_bus_started() */
59  static int brcmf_ignore_probe_fail;
60 @@ -287,6 +291,7 @@ struct brcmf_mp_device *brcmf_get_module
61         settings->feature_disable = brcmf_feature_disable;
62         settings->fcmode = brcmf_fcmode;
63         settings->roamoff = !!brcmf_roamoff;
64 +       settings->iapp = !!brcmf_iapp_enable;
65  #ifdef DEBUG
66         settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
67  #endif
68 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
69 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
70 @@ -58,6 +58,7 @@ struct brcmf_mp_device {
71         unsigned int    feature_disable;
72         int             fcmode;
73         bool            roamoff;
74 +       bool            iapp;
75         bool            ignore_probe_fail;
76         struct brcmfmac_pd_cc *country_codes;
77         union {
78 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
79 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
80 @@ -192,6 +192,37 @@ static void brcmf_netdev_set_multicast_l
81         schedule_work(&ifp->multicast_work);
82  }
83  
84 +/**
85 + * brcmf_skb_is_iapp - checks if skb is an IAPP packet
86 + *
87 + * @skb: skb to check
88 + */
89 +static bool brcmf_skb_is_iapp(struct sk_buff *skb)
90 +{
91 +       static const u8 iapp_l2_update_packet[6] __aligned(2) = {
92 +               0x00, 0x01, 0xaf, 0x81, 0x01, 0x00,
93 +       };
94 +       unsigned char *eth_data;
95 +#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
96 +       const u16 *a, *b;
97 +#endif
98 +
99 +       if (skb->len - skb->mac_len != 6 ||
100 +           !is_multicast_ether_addr(eth_hdr(skb)->h_dest))
101 +               return false;
102 +
103 +       eth_data = skb_mac_header(skb) + ETH_HLEN;
104 +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
105 +       return !(((*(const u32 *)eth_data) ^ (*(const u32 *)iapp_l2_update_packet)) |
106 +                ((*(const u16 *)(eth_data + 4)) ^ (*(const u16 *)(iapp_l2_update_packet + 4))));
107 +#else
108 +       a = (const u16 *)eth_data;
109 +       b = (const u16 *)iapp_l2_update_packet;
110 +
111 +       return !((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]));
112 +#endif
113 +}
114 +
115  static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
116                                            struct net_device *ndev)
117  {
118 @@ -211,6 +242,23 @@ static netdev_tx_t brcmf_netdev_start_xm
119                 goto done;
120         }
121  
122 +       /* Some recent Broadcom's firmwares disassociate STA when they receive
123 +        * an 802.11f ADD frame. This behavior can lead to a local DoS security
124 +        * issue. Attacker may trigger disassociation of any STA by sending a
125 +        * proper Ethernet frame to the wireless interface.
126 +        *
127 +        * Moreover this feature may break AP interfaces in some specific
128 +        * setups. This applies e.g. to the bridge with hairpin mode enabled and
129 +        * IFLA_BRPORT_MCAST_TO_UCAST set. IAPP packet generated by a firmware
130 +        * will get passed back to the wireless interface and cause immediate
131 +        * disassociation of a just-connected STA.
132 +        */
133 +       if (!drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
134 +               dev_kfree_skb(skb);
135 +               ret = -EINVAL;
136 +               goto done;
137 +       }
138 +
139         /* Make sure there's enough room for any header */
140         if (skb_headroom(skb) < drvr->hdrlen) {
141                 struct sk_buff *skb2;
142 @@ -295,6 +343,15 @@ void brcmf_txflowblock(struct device *de
143  
144  void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
145  {
146 +       /* Most of Broadcom's firmwares send 802.11f ADD frame every time a new
147 +        * STA connects to the AP interface. This is an obsoleted standard most
148 +        * users don't use, so don't pass these frames up unless requested.
149 +        */
150 +       if (!ifp->drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
151 +               brcmu_pkt_buf_free_skb(skb);
152 +               return;
153 +       }
154 +
155         if (skb->pkt_type == PACKET_MULTICAST)
156                 ifp->stats.multicast++;
157