hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/mm/kasan/quarantine.c
....@@ -6,16 +6,6 @@
66 * Copyright (C) 2016 Google, Inc.
77 *
88 * Based on code by Dmitry Chernenkov.
9
- *
10
- * This program is free software; you can redistribute it and/or
11
- * modify it under the terms of the GNU General Public License
12
- * version 2 as published by the Free Software Foundation.
13
- *
14
- * This program is distributed in the hope that it will be useful, but
15
- * WITHOUT ANY WARRANTY; without even the implied warranty of
16
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
- * General Public License for more details.
18
- *
199 */
2010
2111 #include <linux/gfp.h>
....@@ -29,6 +19,7 @@
2919 #include <linux/srcu.h>
3020 #include <linux/string.h>
3121 #include <linux/types.h>
22
+#include <linux/cpuhotplug.h>
3223
3324 #include "../slab.h"
3425 #include "kasan.h"
....@@ -43,6 +34,7 @@
4334 struct qlist_node *head;
4435 struct qlist_node *tail;
4536 size_t bytes;
37
+ bool offline;
4638 };
4739
4840 #define QLIST_INIT { NULL, NULL, 0 }
....@@ -145,6 +137,12 @@
145137 if (IS_ENABLED(CONFIG_SLAB))
146138 local_irq_save(flags);
147139
140
+ /*
141
+ * As the object now gets freed from the quaratine, assume that its
142
+ * free track is no longer valid.
143
+ */
144
+ *(u8 *)kasan_mem_to_shadow(object) = KASAN_KMALLOC_FREE;
145
+
148146 ___cache_free(cache, object, _THIS_IP_);
149147
150148 if (IS_ENABLED(CONFIG_SLAB))
....@@ -170,24 +168,36 @@
170168 qlist_init(q);
171169 }
172170
173
-void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache)
171
+bool kasan_quarantine_put(struct kmem_cache *cache, void *object)
174172 {
175173 unsigned long flags;
176174 struct qlist_head *q;
177175 struct qlist_head temp = QLIST_INIT;
176
+ struct kasan_free_meta *meta = kasan_get_free_meta(cache, object);
177
+
178
+ /*
179
+ * If there's no metadata for this object, don't put it into
180
+ * quarantine.
181
+ */
182
+ if (!meta)
183
+ return false;
178184
179185 /*
180186 * Note: irq must be disabled until after we move the batch to the
181
- * global quarantine. Otherwise quarantine_remove_cache() can miss
182
- * some objects belonging to the cache if they are in our local temp
183
- * list. quarantine_remove_cache() executes on_each_cpu() at the
184
- * beginning which ensures that it either sees the objects in per-cpu
185
- * lists or in the global quarantine.
187
+ * global quarantine. Otherwise kasan_quarantine_remove_cache() can
188
+ * miss some objects belonging to the cache if they are in our local
189
+ * temp list. kasan_quarantine_remove_cache() executes on_each_cpu()
190
+ * at the beginning which ensures that it either sees the objects in
191
+ * per-cpu lists or in the global quarantine.
186192 */
187193 local_irq_save(flags);
188194
189195 q = this_cpu_ptr(&cpu_quarantine);
190
- qlist_put(q, &info->quarantine_link, cache->size);
196
+ if (q->offline) {
197
+ local_irq_restore(flags);
198
+ return false;
199
+ }
200
+ qlist_put(q, &meta->quarantine_link, cache->size);
191201 if (unlikely(q->bytes > QUARANTINE_PERCPU_SIZE)) {
192202 qlist_move_all(q, &temp);
193203
....@@ -208,9 +218,11 @@
208218 }
209219
210220 local_irq_restore(flags);
221
+
222
+ return true;
211223 }
212224
213
-void quarantine_reduce(void)
225
+void kasan_quarantine_reduce(void)
214226 {
215227 size_t total_size, new_quarantine_size, percpu_quarantines;
216228 unsigned long flags;
....@@ -222,7 +234,7 @@
222234 return;
223235
224236 /*
225
- * srcu critical section ensures that quarantine_remove_cache()
237
+ * srcu critical section ensures that kasan_quarantine_remove_cache()
226238 * will not miss objects belonging to the cache while they are in our
227239 * local to_free list. srcu is chosen because (1) it gives us private
228240 * grace period domain that does not interfere with anything else,
....@@ -237,7 +249,7 @@
237249 * Update quarantine size in case of hotplug. Allocate a fraction of
238250 * the installed memory to quarantine minus per-cpu queue limits.
239251 */
240
- total_size = (READ_ONCE(totalram_pages) << PAGE_SHIFT) /
252
+ total_size = (totalram_pages() << PAGE_SHIFT) /
241253 QUARANTINE_FRACTION;
242254 percpu_quarantines = QUARANTINE_PERCPU_SIZE * num_online_cpus();
243255 new_quarantine_size = (total_size < percpu_quarantines) ?
....@@ -292,20 +304,27 @@
292304 struct qlist_head *q;
293305
294306 q = this_cpu_ptr(&cpu_quarantine);
307
+ /*
308
+ * Ensure the ordering between the writing to q->offline and
309
+ * per_cpu_remove_cache. Prevent cpu_quarantine from being corrupted
310
+ * by interrupt.
311
+ */
312
+ if (READ_ONCE(q->offline))
313
+ return;
295314 qlist_move_cache(q, &to_free, cache);
296315 qlist_free_all(&to_free, cache);
297316 }
298317
299318 /* Free all quarantined objects belonging to cache. */
300
-void quarantine_remove_cache(struct kmem_cache *cache)
319
+void kasan_quarantine_remove_cache(struct kmem_cache *cache)
301320 {
302321 unsigned long flags, i;
303322 struct qlist_head to_free = QLIST_INIT;
304323
305324 /*
306325 * Must be careful to not miss any objects that are being moved from
307
- * per-cpu list to the global quarantine in quarantine_put(),
308
- * nor objects being freed in quarantine_reduce(). on_each_cpu()
326
+ * per-cpu list to the global quarantine in kasan_quarantine_put(),
327
+ * nor objects being freed in kasan_quarantine_reduce(). on_each_cpu()
309328 * achieves the first goal, while synchronize_srcu() achieves the
310329 * second.
311330 */
....@@ -327,3 +346,36 @@
327346
328347 synchronize_srcu(&remove_cache_srcu);
329348 }
349
+
350
+static int kasan_cpu_online(unsigned int cpu)
351
+{
352
+ this_cpu_ptr(&cpu_quarantine)->offline = false;
353
+ return 0;
354
+}
355
+
356
+static int kasan_cpu_offline(unsigned int cpu)
357
+{
358
+ struct qlist_head *q;
359
+
360
+ q = this_cpu_ptr(&cpu_quarantine);
361
+ /* Ensure the ordering between the writing to q->offline and
362
+ * qlist_free_all. Otherwise, cpu_quarantine may be corrupted
363
+ * by interrupt.
364
+ */
365
+ WRITE_ONCE(q->offline, true);
366
+ barrier();
367
+ qlist_free_all(q, NULL);
368
+ return 0;
369
+}
370
+
371
+static int __init kasan_cpu_quarantine_init(void)
372
+{
373
+ int ret = 0;
374
+
375
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mm/kasan:online",
376
+ kasan_cpu_online, kasan_cpu_offline);
377
+ if (ret < 0)
378
+ pr_err("kasan cpu quarantine register failed [%d]\n", ret);
379
+ return ret;
380
+}
381
+late_initcall(kasan_cpu_quarantine_init);