Skip to content

Commit c6cfcbd

Browse files
jpoimboePeter Zijlstra
authored andcommitted
x86/ibt: Convert IBT selftest to asm
The following warning is reported when frame pointers and kernel IBT are enabled: vmlinux.o: warning: objtool: ibt_selftest+0x11: sibling call from callable instruction with modified stack frame The problem is that objtool interprets the indirect branch in ibt_selftest() as a sibling call, and GCC inserts a (partial) frame pointer prologue before it: 0000 000000000003f550 <ibt_selftest>: 0000 3f550: f3 0f 1e fa endbr64 0004 3f554: e8 00 00 00 00 call 3f559 <ibt_selftest+0x9> 3f555: R_X86_64_PLT32 __fentry__-0x4 0009 3f559: 55 push %rbp 000a 3f55a: 48 8d 05 02 00 00 00 lea 0x2(%rip),%rax # 3f563 <ibt_selftest_ip> 0011 3f561: ff e0 jmp *%rax Note the inline asm is missing ASM_CALL_CONSTRAINT, so the 'push %rbp' happens before the indirect branch and the 'mov %rsp, %rbp' happens afterwards. Simplify the generated code and make it easier to understand for both tools and humans by moving the selftest to proper asm. Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/99a7e16b97bda97bf0a04aa141d6241cd8a839a2.1680912949.git.jpoimboe@kernel.org
1 parent c6b53dc commit c6cfcbd

File tree

5 files changed

+22
-24
lines changed

5 files changed

+22
-24
lines changed

arch/x86/include/asm/traps.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ void __init trap_init(void);
1818
asmlinkage __visible noinstr struct pt_regs *vc_switch_off_ist(struct pt_regs *eregs);
1919
#endif
2020

21-
extern bool ibt_selftest(void);
21+
extern int ibt_selftest(void);
22+
extern int ibt_selftest_noendbr(void);
2223

2324
#ifdef CONFIG_X86_F00F_BUG
2425
/* For handling the FOOF bug */

arch/x86/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ obj-y += process_$(BITS).o signal.o signal_$(BITS).o
4949
obj-y += traps.o idt.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
5050
obj-y += time.o ioport.o dumpstack.o nmi.o
5151
obj-$(CONFIG_MODIFY_LDT_SYSCALL) += ldt.o
52+
obj-$(CONFIG_X86_KERNEL_IBT) += ibt_selftest.o
5253
obj-y += setup.o x86_init.o i8259.o irqinit.o
5354
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
5455
obj-$(CONFIG_IRQ_WORK) += irq_work.o

arch/x86/kernel/cet.c

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,14 @@ static void do_user_cp_fault(struct pt_regs *regs, unsigned long error_code)
8181

8282
static __ro_after_init bool ibt_fatal = true;
8383

84-
/* code label defined in asm below */
85-
extern void ibt_selftest_ip(void);
86-
8784
static void do_kernel_cp_fault(struct pt_regs *regs, unsigned long error_code)
8885
{
8986
if ((error_code & CP_EC) != CP_ENDBR) {
9087
do_unexpected_cp(regs, error_code);
9188
return;
9289
}
9390

94-
if (unlikely(regs->ip == (unsigned long)&ibt_selftest_ip)) {
91+
if (unlikely(regs->ip == (unsigned long)&ibt_selftest_noendbr)) {
9592
regs->ax = 0;
9693
return;
9794
}
@@ -105,24 +102,6 @@ static void do_kernel_cp_fault(struct pt_regs *regs, unsigned long error_code)
105102
BUG();
106103
}
107104

108-
/* Must be noinline to ensure uniqueness of ibt_selftest_ip. */
109-
noinline bool ibt_selftest(void)
110-
{
111-
unsigned long ret;
112-
113-
asm (" lea ibt_selftest_ip(%%rip), %%rax\n\t"
114-
ANNOTATE_RETPOLINE_SAFE
115-
" jmp *%%rax\n\t"
116-
"ibt_selftest_ip:\n\t"
117-
UNWIND_HINT_FUNC
118-
ANNOTATE_NOENDBR
119-
" nop\n\t"
120-
121-
: "=a" (ret) : : "memory");
122-
123-
return !ret;
124-
}
125-
126105
static int __init ibt_setup(char *str)
127106
{
128107
if (!strcmp(str, "off"))

arch/x86/kernel/cpu/common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ static __always_inline void setup_cet(struct cpuinfo_x86 *c)
610610

611611
cr4_set_bits(X86_CR4_CET);
612612

613-
if (kernel_ibt && !ibt_selftest()) {
613+
if (kernel_ibt && ibt_selftest()) {
614614
pr_err("IBT selftest: Failed!\n");
615615
wrmsrl(MSR_IA32_S_CET, 0);
616616
setup_clear_cpu_cap(X86_FEATURE_IBT);

arch/x86/kernel/ibt_selftest.S

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#include <linux/linkage.h>
3+
#include <linux/objtool.h>
4+
#include <asm/nospec-branch.h>
5+
6+
SYM_CODE_START(ibt_selftest_noendbr)
7+
ANNOTATE_NOENDBR
8+
UNWIND_HINT_FUNC
9+
/* #CP handler sets %ax to 0 */
10+
RET
11+
SYM_CODE_END(ibt_selftest_noendbr)
12+
13+
SYM_FUNC_START(ibt_selftest)
14+
lea ibt_selftest_noendbr(%rip), %rax
15+
ANNOTATE_RETPOLINE_SAFE
16+
jmp *%rax
17+
SYM_FUNC_END(ibt_selftest)

0 commit comments

Comments
 (0)