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