Skip to content

Commit

Permalink
kasan: report only the first error by default
Browse files Browse the repository at this point in the history
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.

[[email protected]: wrote changelog and doc, added missing include]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Mark Rutland <[email protected]>
Signed-off-by: Andrey Ryabinin <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Cc: Alexander Potapenko <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Mark Rutland authored and torvalds committed Apr 1, 2017
1 parent 4742a35 commit b0845ce
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 5 deletions.
6 changes: 6 additions & 0 deletions Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1725,6 +1725,12 @@
kernel and module base offset ASLR (Address Space
Layout Randomization).

kasan_multi_shot
[KNL] Enforce KASAN (Kernel Address Sanitizer) to print
report on every invalid memory access. Without this
parameter KASAN will print report only for the first
invalid access.

keepinitrd [HW,ARM]

kernelcore= [KNL,X86,IA-64,PPC]
Expand Down
3 changes: 3 additions & 0 deletions include/linux/kasan.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ size_t ksize(const void *);
static inline void kasan_unpoison_slab(const void *ptr) { ksize(ptr); }
size_t kasan_metadata_size(struct kmem_cache *cache);

bool kasan_save_enable_multi_shot(void);
void kasan_restore_multi_shot(bool enabled);

#else /* CONFIG_KASAN */

static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
Expand Down
10 changes: 10 additions & 0 deletions lib/test_kasan.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/kasan.h>

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

static int __init kmalloc_tests_init(void)
{
/*
* Temporarily enable multi-shot mode. Otherwise, we'd only get a
* report for the first case.
*/
bool multishot = kasan_save_enable_multi_shot();

kmalloc_oob_right();
kmalloc_oob_left();
kmalloc_node_oob_right();
Expand All @@ -499,6 +506,9 @@ static int __init kmalloc_tests_init(void)
ksize_unpoisons_memory();
copy_user_test();
use_after_scope_test();

kasan_restore_multi_shot(multishot);

return -EAGAIN;
}

Expand Down
5 changes: 0 additions & 5 deletions mm/kasan/kasan.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,6 @@ static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
<< KASAN_SHADOW_SCALE_SHIFT);
}

static inline bool kasan_report_enabled(void)
{
return !current->kasan_depth;
}

void kasan_report(unsigned long addr, size_t size,
bool is_write, unsigned long ip);
void kasan_report_double_free(struct kmem_cache *cache, void *object,
Expand Down
36 changes: 36 additions & 0 deletions mm/kasan/report.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
*
*/

#include <linux/bitops.h>
#include <linux/ftrace.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/printk.h>
Expand Down Expand Up @@ -293,6 +295,40 @@ static void kasan_report_error(struct kasan_access_info *info)
kasan_end_report(&flags);
}

static unsigned long kasan_flags;

#define KASAN_BIT_REPORTED 0
#define KASAN_BIT_MULTI_SHOT 1

bool kasan_save_enable_multi_shot(void)
{
return test_and_set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
}
EXPORT_SYMBOL_GPL(kasan_save_enable_multi_shot);

void kasan_restore_multi_shot(bool enabled)
{
if (!enabled)
clear_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
}
EXPORT_SYMBOL_GPL(kasan_restore_multi_shot);

static int __init kasan_set_multi_shot(char *str)
{
set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
return 1;
}
__setup("kasan_multi_shot", kasan_set_multi_shot);

static inline bool kasan_report_enabled(void)
{
if (current->kasan_depth)
return false;
if (test_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags))
return true;
return !test_and_set_bit(KASAN_BIT_REPORTED, &kasan_flags);
}

void kasan_report(unsigned long addr, size_t size,
bool is_write, unsigned long ip)
{
Expand Down

0 comments on commit b0845ce

Please sign in to comment.