|
35 | 35 | #include <linux/sizes.h>
|
36 | 36 | #include <linux/syscalls.h>
|
37 | 37 | #include <linux/mm_types.h>
|
| 38 | +#include <linux/kasan.h> |
38 | 39 |
|
39 | 40 | #include <asm/atomic.h>
|
40 | 41 | #include <asm/bug.h>
|
@@ -969,18 +970,77 @@ static struct break_hook bug_break_hook = {
|
969 | 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 | + |
| 980 | +static 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 | + |
| 1018 | +static 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 | 1026 | * Initial handler for AArch64 BRK exceptions
|
974 | 1027 | * This handler only used until debug_traps_init().
|
975 | 1028 | */
|
976 | 1029 | int __init early_brk64(unsigned long addr, unsigned int esr,
|
977 | 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 | 1036 | return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
|
980 | 1037 | }
|
981 | 1038 |
|
982 | 1039 | /* This registration must happen early, before debug_traps_init(). */
|
983 | 1040 | void __init trap_init(void)
|
984 | 1041 | {
|
985 | 1042 | register_break_hook(&bug_break_hook);
|
| 1043 | +#ifdef CONFIG_KASAN_SW_TAGS |
| 1044 | + register_break_hook(&kasan_break_hook); |
| 1045 | +#endif |
986 | 1046 | }
|
0 commit comments