Skip to content

Commit b0845ce

Browse files
mrutland-armtorvalds
authored andcommitted
kasan: report only the first error by default
Disable kasan after the first report. There are several reasons for this: - Single bug quite often has multiple invalid memory accesses causing storm in the dmesg. - Write OOB access might corrupt metadata so the next report will print bogus alloc/free stacktraces. - Reports after the first easily could be not bugs by itself but just side effects of the first one. Given that multiple reports usually only do harm, it makes sense to disable kasan after the first one. If user wants to see all the reports, the boot-time parameter kasan_multi_shot must be used. [aryabinin@virtuozzo.com: wrote changelog and doc, added missing include] Link: http://lkml.kernel.org/r/20170323154416.30257-1-aryabinin@virtuozzo.com Signed-off-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Andrey Konovalov <andreyknvl@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 4742a35 commit b0845ce

File tree

5 files changed

+55
-5
lines changed

5 files changed

+55
-5
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,12 @@
17251725
kernel and module base offset ASLR (Address Space
17261726
Layout Randomization).
17271727

1728+
kasan_multi_shot
1729+
[KNL] Enforce KASAN (Kernel Address Sanitizer) to print
1730+
report on every invalid memory access. Without this
1731+
parameter KASAN will print report only for the first
1732+
invalid access.
1733+
17281734
keepinitrd [HW,ARM]
17291735

17301736
kernelcore= [KNL,X86,IA-64,PPC]

include/linux/kasan.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ size_t ksize(const void *);
7676
static inline void kasan_unpoison_slab(const void *ptr) { ksize(ptr); }
7777
size_t kasan_metadata_size(struct kmem_cache *cache);
7878

79+
bool kasan_save_enable_multi_shot(void);
80+
void kasan_restore_multi_shot(bool enabled);
81+
7982
#else /* CONFIG_KASAN */
8083

8184
static inline void kasan_unpoison_shadow(const void *address, size_t size) {}

lib/test_kasan.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/string.h>
2121
#include <linux/uaccess.h>
2222
#include <linux/module.h>
23+
#include <linux/kasan.h>
2324

2425
/*
2526
* Note: test functions are marked noinline so that their names appear in
@@ -474,6 +475,12 @@ static noinline void __init use_after_scope_test(void)
474475

475476
static int __init kmalloc_tests_init(void)
476477
{
478+
/*
479+
* Temporarily enable multi-shot mode. Otherwise, we'd only get a
480+
* report for the first case.
481+
*/
482+
bool multishot = kasan_save_enable_multi_shot();
483+
477484
kmalloc_oob_right();
478485
kmalloc_oob_left();
479486
kmalloc_node_oob_right();
@@ -499,6 +506,9 @@ static int __init kmalloc_tests_init(void)
499506
ksize_unpoisons_memory();
500507
copy_user_test();
501508
use_after_scope_test();
509+
510+
kasan_restore_multi_shot(multishot);
511+
502512
return -EAGAIN;
503513
}
504514

mm/kasan/kasan.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,6 @@ static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
9696
<< KASAN_SHADOW_SCALE_SHIFT);
9797
}
9898

99-
static inline bool kasan_report_enabled(void)
100-
{
101-
return !current->kasan_depth;
102-
}
103-
10499
void kasan_report(unsigned long addr, size_t size,
105100
bool is_write, unsigned long ip);
106101
void kasan_report_double_free(struct kmem_cache *cache, void *object,

mm/kasan/report.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
*
1414
*/
1515

16+
#include <linux/bitops.h>
1617
#include <linux/ftrace.h>
18+
#include <linux/init.h>
1719
#include <linux/kernel.h>
1820
#include <linux/mm.h>
1921
#include <linux/printk.h>
@@ -293,6 +295,40 @@ static void kasan_report_error(struct kasan_access_info *info)
293295
kasan_end_report(&flags);
294296
}
295297

298+
static unsigned long kasan_flags;
299+
300+
#define KASAN_BIT_REPORTED 0
301+
#define KASAN_BIT_MULTI_SHOT 1
302+
303+
bool kasan_save_enable_multi_shot(void)
304+
{
305+
return test_and_set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
306+
}
307+
EXPORT_SYMBOL_GPL(kasan_save_enable_multi_shot);
308+
309+
void kasan_restore_multi_shot(bool enabled)
310+
{
311+
if (!enabled)
312+
clear_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
313+
}
314+
EXPORT_SYMBOL_GPL(kasan_restore_multi_shot);
315+
316+
static int __init kasan_set_multi_shot(char *str)
317+
{
318+
set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
319+
return 1;
320+
}
321+
__setup("kasan_multi_shot", kasan_set_multi_shot);
322+
323+
static inline bool kasan_report_enabled(void)
324+
{
325+
if (current->kasan_depth)
326+
return false;
327+
if (test_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags))
328+
return true;
329+
return !test_and_set_bit(KASAN_BIT_REPORTED, &kasan_flags);
330+
}
331+
296332
void kasan_report(unsigned long addr, size_t size,
297333
bool is_write, unsigned long ip)
298334
{

0 commit comments

Comments
 (0)