mac80211: use wiphy_read_of_freq_limits in brcmfmac
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 343-cfg80211-limit-scan-results-cache-size.patch
1 From: Johannes Berg <johannes.berg@intel.com>
2 Date: Tue, 15 Nov 2016 12:05:11 +0100
3 Subject: [PATCH] cfg80211: limit scan results cache size
4
5 It's possible to make scanning consume almost arbitrary amounts
6 of memory, e.g. by sending beacon frames with random BSSIDs at
7 high rates while somebody is scanning.
8
9 Limit the number of BSS table entries we're willing to cache to
10 1000, limiting maximum memory usage to maybe 4-5MB, but lower
11 in practice - that would be the case for having both full-sized
12 beacon and probe response frames for each entry; this seems not
13 possible in practice, so a limit of 1000 entries will likely be
14 closer to 0.5 MB.
15
16 Cc: stable@vger.kernel.org
17 Signed-off-by: Johannes Berg <johannes.berg@intel.com>
18 ---
19
20 --- a/net/wireless/core.h
21 +++ b/net/wireless/core.h
22 @@ -71,6 +71,7 @@ struct cfg80211_registered_device {
23 struct list_head bss_list;
24 struct rb_root bss_tree;
25 u32 bss_generation;
26 + u32 bss_entries;
27 struct cfg80211_scan_request *scan_req; /* protected by RTNL */
28 struct sk_buff *scan_msg;
29 struct cfg80211_sched_scan_request __rcu *sched_scan_req;
30 --- a/net/wireless/scan.c
31 +++ b/net/wireless/scan.c
32 @@ -57,6 +57,19 @@
33 * also linked into the probe response struct.
34 */
35
36 +/*
37 + * Limit the number of BSS entries stored in mac80211. Each one is
38 + * a bit over 4k at most, so this limits to roughly 4-5M of memory.
39 + * If somebody wants to really attack this though, they'd likely
40 + * use small beacons, and only one type of frame, limiting each of
41 + * the entries to a much smaller size (in order to generate more
42 + * entries in total, so overhead is bigger.)
43 + */
44 +static int bss_entries_limit = 1000;
45 +module_param(bss_entries_limit, int, 0644);
46 +MODULE_PARM_DESC(bss_entries_limit,
47 + "limit to number of scan BSS entries (per wiphy, default 1000)");
48 +
49 #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
50
51 static void bss_free(struct cfg80211_internal_bss *bss)
52 @@ -137,6 +150,10 @@ static bool __cfg80211_unlink_bss(struct
53
54 list_del_init(&bss->list);
55 rb_erase(&bss->rbn, &rdev->bss_tree);
56 + rdev->bss_entries--;
57 + WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
58 + "rdev bss entries[%d]/list[empty:%d] corruption\n",
59 + rdev->bss_entries, list_empty(&rdev->bss_list));
60 bss_ref_put(rdev, bss);
61 return true;
62 }
63 @@ -163,6 +180,40 @@ static void __cfg80211_bss_expire(struct
64 rdev->bss_generation++;
65 }
66
67 +static bool cfg80211_bss_expire_oldest(struct cfg80211_registered_device *rdev)
68 +{
69 + struct cfg80211_internal_bss *bss, *oldest = NULL;
70 + bool ret;
71 +
72 + lockdep_assert_held(&rdev->bss_lock);
73 +
74 + list_for_each_entry(bss, &rdev->bss_list, list) {
75 + if (atomic_read(&bss->hold))
76 + continue;
77 +
78 + if (!list_empty(&bss->hidden_list) &&
79 + !bss->pub.hidden_beacon_bss)
80 + continue;
81 +
82 + if (oldest && time_before(oldest->ts, bss->ts))
83 + continue;
84 + oldest = bss;
85 + }
86 +
87 + if (WARN_ON(!oldest))
88 + return false;
89 +
90 + /*
91 + * The callers make sure to increase rdev->bss_generation if anything
92 + * gets removed (and a new entry added), so there's no need to also do
93 + * it here.
94 + */
95 +
96 + ret = __cfg80211_unlink_bss(rdev, oldest);
97 + WARN_ON(!ret);
98 + return ret;
99 +}
100 +
101 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
102 bool send_message)
103 {
104 @@ -689,6 +740,7 @@ static bool cfg80211_combine_bsses(struc
105 const u8 *ie;
106 int i, ssidlen;
107 u8 fold = 0;
108 + u32 n_entries = 0;
109
110 ies = rcu_access_pointer(new->pub.beacon_ies);
111 if (WARN_ON(!ies))
112 @@ -712,6 +764,12 @@ static bool cfg80211_combine_bsses(struc
113 /* This is the bad part ... */
114
115 list_for_each_entry(bss, &rdev->bss_list, list) {
116 + /*
117 + * we're iterating all the entries anyway, so take the
118 + * opportunity to validate the list length accounting
119 + */
120 + n_entries++;
121 +
122 if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
123 continue;
124 if (bss->pub.channel != new->pub.channel)
125 @@ -740,6 +798,10 @@ static bool cfg80211_combine_bsses(struc
126 new->pub.beacon_ies);
127 }
128
129 + WARN_ONCE(n_entries != rdev->bss_entries,
130 + "rdev bss entries[%d]/list[len:%d] corruption\n",
131 + rdev->bss_entries, n_entries);
132 +
133 return true;
134 }
135
136 @@ -894,7 +956,14 @@ cfg80211_bss_update(struct cfg80211_regi
137 }
138 }
139
140 + if (rdev->bss_entries >= bss_entries_limit &&
141 + !cfg80211_bss_expire_oldest(rdev)) {
142 + kfree(new);
143 + goto drop;
144 + }
145 +
146 list_add_tail(&new->list, &rdev->bss_list);
147 + rdev->bss_entries++;
148 rb_insert_bss(rdev, new);
149 found = new;
150 }