#include <linux/sizes.h>
 #include <linux/syscalls.h>
 #include <linux/mm_types.h>
+#include <linux/kasan.h>
 
 #include <asm/atomic.h>
 #include <asm/bug.h>
        .fn = bug_handler,
 };
 
+#ifdef CONFIG_KASAN_SW_TAGS
+
+#define KASAN_ESR_RECOVER      0x20
+#define KASAN_ESR_WRITE        0x10
+#define KASAN_ESR_SIZE_MASK    0x0f
+#define KASAN_ESR_SIZE(esr)    (1 << ((esr) & KASAN_ESR_SIZE_MASK))
+
+static int kasan_handler(struct pt_regs *regs, unsigned int esr)
+{
+       bool recover = esr & KASAN_ESR_RECOVER;
+       bool write = esr & KASAN_ESR_WRITE;
+       size_t size = KASAN_ESR_SIZE(esr);
+       u64 addr = regs->regs[0];
+       u64 pc = regs->pc;
+
+       if (user_mode(regs))
+               return DBG_HOOK_ERROR;
+
+       kasan_report(addr, size, write, pc);
+
+       /*
+        * The instrumentation allows to control whether we can proceed after
+        * a crash was detected. This is done by passing the -recover flag to
+        * the compiler. Disabling recovery allows to generate more compact
+        * code.
+        *
+        * Unfortunately disabling recovery doesn't work for the kernel right
+        * now. KASAN reporting is disabled in some contexts (for example when
+        * the allocator accesses slab object metadata; this is controlled by
+        * current->kasan_depth). All these accesses are detected by the tool,
+        * even though the reports for them are not printed.
+        *
+        * This is something that might be fixed at some point in the future.
+        */
+       if (!recover)
+               die("Oops - KASAN", regs, 0);
+
+       /* If thread survives, skip over the brk instruction and continue: */
+       arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
+       return DBG_HOOK_HANDLED;
+}
+
+#define KASAN_ESR_VAL (0xf2000000 | KASAN_BRK_IMM)
+#define KASAN_ESR_MASK 0xffffff00
+
+static struct break_hook kasan_break_hook = {
+       .esr_val = KASAN_ESR_VAL,
+       .esr_mask = KASAN_ESR_MASK,
+       .fn = kasan_handler,
+};
+#endif
+
 /*
  * Initial handler for AArch64 BRK exceptions
  * This handler only used until debug_traps_init().
 int __init early_brk64(unsigned long addr, unsigned int esr,
                struct pt_regs *regs)
 {
+#ifdef CONFIG_KASAN_SW_TAGS
+       if ((esr & KASAN_ESR_MASK) == KASAN_ESR_VAL)
+               return kasan_handler(regs, esr) != DBG_HOOK_HANDLED;
+#endif
        return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
 }
 
 void __init trap_init(void)
 {
        register_break_hook(&bug_break_hook);
+#ifdef CONFIG_KASAN_SW_TAGS
+       register_break_hook(&kasan_break_hook);
+#endif
 }