1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/ptrace.h> 4 #include <asm/bugs.h> 5 #include <asm/traps.h> 6 7 static __ro_after_init bool ibt_fatal = true; 8 9 extern void ibt_selftest_ip(void); /* code label defined in asm below */ 10 11 enum cp_error_code { 12 CP_EC = (1 << 15) - 1, 13 14 CP_RET = 1, 15 CP_IRET = 2, 16 CP_ENDBR = 3, 17 CP_RSTRORSSP = 4, 18 CP_SETSSBSY = 5, 19 20 CP_ENCL = 1 << 15, 21 }; 22 23 DEFINE_IDTENTRY_ERRORCODE(exc_control_protection) 24 { 25 if (!cpu_feature_enabled(X86_FEATURE_IBT)) { 26 pr_err("Unexpected #CP\n"); 27 BUG(); 28 } 29 30 if (WARN_ON_ONCE(user_mode(regs) || (error_code & CP_EC) != CP_ENDBR)) 31 return; 32 33 if (unlikely(regs->ip == (unsigned long)&ibt_selftest_ip)) { 34 regs->ax = 0; 35 return; 36 } 37 38 pr_err("Missing ENDBR: %pS\n", (void *)instruction_pointer(regs)); 39 if (!ibt_fatal) { 40 printk(KERN_DEFAULT CUT_HERE); 41 __warn(__FILE__, __LINE__, (void *)regs->ip, TAINT_WARN, regs, NULL); 42 return; 43 } 44 BUG(); 45 } 46 47 /* Must be noinline to ensure uniqueness of ibt_selftest_ip. */ 48 noinline bool ibt_selftest(void) 49 { 50 unsigned long ret; 51 52 asm (" lea ibt_selftest_ip(%%rip), %%rax\n\t" 53 ANNOTATE_RETPOLINE_SAFE 54 " jmp *%%rax\n\t" 55 "ibt_selftest_ip:\n\t" 56 UNWIND_HINT_FUNC 57 ANNOTATE_NOENDBR 58 " nop\n\t" 59 60 : "=a" (ret) : : "memory"); 61 62 return !ret; 63 } 64 65 static int __init ibt_setup(char *str) 66 { 67 if (!strcmp(str, "off")) 68 setup_clear_cpu_cap(X86_FEATURE_IBT); 69 70 if (!strcmp(str, "warn")) 71 ibt_fatal = false; 72 73 return 1; 74 } 75 76 __setup("ibt=", ibt_setup); 77