xref: /openbmc/linux/arch/x86/kernel/cet.c (revision 2da5b91f)
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