summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/brk-imm.h2
-rw-r--r--arch/arm64/kernel/traps.c60
-rw-r--r--include/linux/kasan.h3
3 files changed, 65 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/brk-imm.h b/arch/arm64/include/asm/brk-imm.h
index ed693c5bcec0..2945fe6cd863 100644
--- a/arch/arm64/include/asm/brk-imm.h
+++ b/arch/arm64/include/asm/brk-imm.h
@@ -16,10 +16,12 @@
16 * 0x400: for dynamic BRK instruction 16 * 0x400: for dynamic BRK instruction
17 * 0x401: for compile time BRK instruction 17 * 0x401: for compile time BRK instruction
18 * 0x800: kernel-mode BUG() and WARN() traps 18 * 0x800: kernel-mode BUG() and WARN() traps
19 * 0x9xx: tag-based KASAN trap (allowed values 0x900 - 0x9ff)
19 */ 20 */
20#define FAULT_BRK_IMM 0x100 21#define FAULT_BRK_IMM 0x100
21#define KGDB_DYN_DBG_BRK_IMM 0x400 22#define KGDB_DYN_DBG_BRK_IMM 0x400
22#define KGDB_COMPILED_DBG_BRK_IMM 0x401 23#define KGDB_COMPILED_DBG_BRK_IMM 0x401
23#define BUG_BRK_IMM 0x800 24#define BUG_BRK_IMM 0x800
25#define KASAN_BRK_IMM 0x900
24 26
25#endif 27#endif
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 5f4d9acb32f5..cdc71cf70aad 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -35,6 +35,7 @@
35#include <linux/sizes.h> 35#include <linux/sizes.h>
36#include <linux/syscalls.h> 36#include <linux/syscalls.h>
37#include <linux/mm_types.h> 37#include <linux/mm_types.h>
38#include <linux/kasan.h>
38 39
39#include <asm/atomic.h> 40#include <asm/atomic.h>
40#include <asm/bug.h> 41#include <asm/bug.h>
@@ -969,6 +970,58 @@ static struct break_hook bug_break_hook = {
969 .fn = bug_handler, 970 .fn = bug_handler,
970}; 971};
971 972
973#ifdef CONFIG_KASAN_SW_TAGS
974
975#define KASAN_ESR_RECOVER 0x20
976#define KASAN_ESR_WRITE 0x10
977#define KASAN_ESR_SIZE_MASK 0x0f
978#define KASAN_ESR_SIZE(esr) (1 << ((esr) & KASAN_ESR_SIZE_MASK))
979
980static int kasan_handler(struct pt_regs *regs, unsigned int esr)
981{
982 bool recover = esr & KASAN_ESR_RECOVER;
983 bool write = esr & KASAN_ESR_WRITE;
984 size_t size = KASAN_ESR_SIZE(esr);
985 u64 addr = regs->regs[0];
986 u64 pc = regs->pc;
987
988 if (user_mode(regs))
989 return DBG_HOOK_ERROR;
990
991 kasan_report(addr, size, write, pc);
992
993 /*
994 * The instrumentation allows to control whether we can proceed after
995 * a crash was detected. This is done by passing the -recover flag to
996 * the compiler. Disabling recovery allows to generate more compact
997 * code.
998 *
999 * Unfortunately disabling recovery doesn't work for the kernel right
1000 * now. KASAN reporting is disabled in some contexts (for example when
1001 * the allocator accesses slab object metadata; this is controlled by
1002 * current->kasan_depth). All these accesses are detected by the tool,
1003 * even though the reports for them are not printed.
1004 *
1005 * This is something that might be fixed at some point in the future.
1006 */
1007 if (!recover)
1008 die("Oops - KASAN", regs, 0);
1009
1010 /* If thread survives, skip over the brk instruction and continue: */
1011 arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
1012 return DBG_HOOK_HANDLED;
1013}
1014
1015#define KASAN_ESR_VAL (0xf2000000 | KASAN_BRK_IMM)
1016#define KASAN_ESR_MASK 0xffffff00
1017
1018static struct break_hook kasan_break_hook = {
1019 .esr_val = KASAN_ESR_VAL,
1020 .esr_mask = KASAN_ESR_MASK,
1021 .fn = kasan_handler,
1022};
1023#endif
1024
972/* 1025/*
973 * Initial handler for AArch64 BRK exceptions 1026 * Initial handler for AArch64 BRK exceptions
974 * This handler only used until debug_traps_init(). 1027 * This handler only used until debug_traps_init().
@@ -976,6 +1029,10 @@ static struct break_hook bug_break_hook = {
976int __init early_brk64(unsigned long addr, unsigned int esr, 1029int __init early_brk64(unsigned long addr, unsigned int esr,
977 struct pt_regs *regs) 1030 struct pt_regs *regs)
978{ 1031{
1032#ifdef CONFIG_KASAN_SW_TAGS
1033 if ((esr & KASAN_ESR_MASK) == KASAN_ESR_VAL)
1034 return kasan_handler(regs, esr) != DBG_HOOK_HANDLED;
1035#endif
979 return bug_handler(regs, esr) != DBG_HOOK_HANDLED; 1036 return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
980} 1037}
981 1038
@@ -983,4 +1040,7 @@ int __init early_brk64(unsigned long addr, unsigned int esr,
983void __init trap_init(void) 1040void __init trap_init(void)
984{ 1041{
985 register_break_hook(&bug_break_hook); 1042 register_break_hook(&bug_break_hook);
1043#ifdef CONFIG_KASAN_SW_TAGS
1044 register_break_hook(&kasan_break_hook);
1045#endif
986} 1046}
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index a477ce2abdc9..8da7b7a4397a 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -173,6 +173,9 @@ void kasan_init_tags(void);
173 173
174void *kasan_reset_tag(const void *addr); 174void *kasan_reset_tag(const void *addr);
175 175
176void kasan_report(unsigned long addr, size_t size,
177 bool is_write, unsigned long ip);
178
176#else /* CONFIG_KASAN_SW_TAGS */ 179#else /* CONFIG_KASAN_SW_TAGS */
177 180
178static inline void kasan_init_tags(void) { } 181static inline void kasan_init_tags(void) { }