* 0x401: for compile time BRK instruction
  * 0x800: kernel-mode BUG() and WARN() traps
  * 0x9xx: tag-based KASAN trap (allowed values 0x900 - 0x9ff)
+ * 0x8xxx: Control-Flow Integrity traps
  */
 #define KPROBES_BRK_IMM                        0x004
 #define UPROBES_BRK_IMM                        0x005
 #define KASAN_BRK_IMM                  0x900
 #define KASAN_BRK_MASK                 0x0ff
 
+#define CFI_BRK_IMM_TARGET             GENMASK(4, 0)
+#define CFI_BRK_IMM_TYPE               GENMASK(9, 5)
+#define CFI_BRK_IMM_BASE               0x8000
+#define CFI_BRK_IMM_MASK               (CFI_BRK_IMM_TARGET | CFI_BRK_IMM_TYPE)
+
 #endif
 
 #include <linux/syscalls.h>
 #include <linux/mm_types.h>
 #include <linux/kasan.h>
+#include <linux/cfi.h>
 
 #include <asm/atomic.h>
 #include <asm/bug.h>
        .imm = BUG_BRK_IMM,
 };
 
+#ifdef CONFIG_CFI_CLANG
+static int cfi_handler(struct pt_regs *regs, unsigned long esr)
+{
+       unsigned long target;
+       u32 type;
+
+       target = pt_regs_read_reg(regs, FIELD_GET(CFI_BRK_IMM_TARGET, esr));
+       type = (u32)pt_regs_read_reg(regs, FIELD_GET(CFI_BRK_IMM_TYPE, esr));
+
+       switch (report_cfi_failure(regs, regs->pc, &target, type)) {
+       case BUG_TRAP_TYPE_BUG:
+               die("Oops - CFI", regs, 0);
+               break;
+
+       case BUG_TRAP_TYPE_WARN:
+               break;
+
+       default:
+               return DBG_HOOK_ERROR;
+       }
+
+       arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
+       return DBG_HOOK_HANDLED;
+}
+
+static struct break_hook cfi_break_hook = {
+       .fn = cfi_handler,
+       .imm = CFI_BRK_IMM_BASE,
+       .mask = CFI_BRK_IMM_MASK,
+};
+#endif /* CONFIG_CFI_CLANG */
+
 static int reserved_fault_handler(struct pt_regs *regs, unsigned long esr)
 {
        pr_err("%s generated an invalid instruction at %pS!\n",
 };
 #endif
 
+
+#define esr_comment(esr) ((esr) & ESR_ELx_BRK64_ISS_COMMENT_MASK)
+
 /*
  * Initial handler for AArch64 BRK exceptions
  * This handler only used until debug_traps_init().
 int __init early_brk64(unsigned long addr, unsigned long esr,
                struct pt_regs *regs)
 {
+#ifdef CONFIG_CFI_CLANG
+       if ((esr_comment(esr) & ~CFI_BRK_IMM_MASK) == CFI_BRK_IMM_BASE)
+               return cfi_handler(regs, esr) != DBG_HOOK_HANDLED;
+#endif
 #ifdef CONFIG_KASAN_SW_TAGS
-       unsigned long comment = esr & ESR_ELx_BRK64_ISS_COMMENT_MASK;
-
-       if ((comment & ~KASAN_BRK_MASK) == KASAN_BRK_IMM)
+       if ((esr_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM)
                return kasan_handler(regs, esr) != DBG_HOOK_HANDLED;
 #endif
        return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
 void __init trap_init(void)
 {
        register_kernel_break_hook(&bug_break_hook);
+#ifdef CONFIG_CFI_CLANG
+       register_kernel_break_hook(&cfi_break_hook);
+#endif
        register_kernel_break_hook(&fault_break_hook);
 #ifdef CONFIG_KASAN_SW_TAGS
        register_kernel_break_hook(&kasan_break_hook);