x86/ibt: Base IBT bits
Add Kconfig, Makefile and basic instruction support for x86 IBT. (Ab)use __DISABLE_EXPORTS to disable IBT since it's already employed to mark compressed and purgatory. Additionally mark realmode with it as well to avoid inserting ENDBR instructions there. While ENDBR is technically a NOP, inserting them was causing some grief due to code growth. There's also a problem with using __noendbr in code compiled without -fcf-protection=branch. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Link: https://lore.kernel.org/r/20220308154317.519875203@infradead.org
This commit is contained in:
parent
5cff2086b0
commit
156ff4a544
@ -1861,6 +1861,26 @@ config X86_UMIP
|
||||
specific cases in protected and virtual-8086 modes. Emulated
|
||||
results are dummy.
|
||||
|
||||
config CC_HAS_IBT
|
||||
# GCC >= 9 and binutils >= 2.29
|
||||
# Retpoline check to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93654
|
||||
# Clang/LLVM >= 14
|
||||
# fentry check to work around https://reviews.llvm.org/D111108
|
||||
def_bool ((CC_IS_GCC && $(cc-option, -fcf-protection=branch -mindirect-branch-register)) || \
|
||||
(CC_IS_CLANG && $(success,echo "void a(void) {}" | $(CC) -Werror $(CLANG_FLAGS) -fcf-protection=branch -mfentry -pg -x c - -c -o /dev/null))) && \
|
||||
$(as-instr,endbr64)
|
||||
|
||||
config X86_KERNEL_IBT
|
||||
prompt "Indirect Branch Tracking"
|
||||
bool
|
||||
depends on X86_64 && CC_HAS_IBT
|
||||
help
|
||||
Build the kernel with support for Indirect Branch Tracking, a
|
||||
hardware support course-grain forward-edge Control Flow Integrity
|
||||
protection. It enforces that all indirect calls must land on
|
||||
an ENDBR instruction, as such, the compiler will instrument the
|
||||
code with them to make this happen.
|
||||
|
||||
config X86_INTEL_MEMORY_PROTECTION_KEYS
|
||||
prompt "Memory Protection Keys"
|
||||
def_bool y
|
||||
|
@ -36,7 +36,7 @@ endif
|
||||
|
||||
# How to compile the 16-bit code. Note we always compile for -march=i386;
|
||||
# that way we can complain to the user if the CPU is insufficient.
|
||||
REALMODE_CFLAGS := -m16 -g -Os -DDISABLE_BRANCH_PROFILING \
|
||||
REALMODE_CFLAGS := -m16 -g -Os -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \
|
||||
-Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
|
||||
-fno-strict-aliasing -fomit-frame-pointer -fno-pic \
|
||||
-mno-mmx -mno-sse $(call cc-option,-fcf-protection=none)
|
||||
@ -62,8 +62,20 @@ export BITS
|
||||
#
|
||||
KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx
|
||||
|
||||
# Intel CET isn't enabled in the kernel
|
||||
ifeq ($(CONFIG_X86_KERNEL_IBT),y)
|
||||
#
|
||||
# Kernel IBT has S_CET.NOTRACK_EN=0, as such the compilers must not generate
|
||||
# NOTRACK prefixes. Current generation compilers unconditionally employ NOTRACK
|
||||
# for jump-tables, as such, disable jump-tables for now.
|
||||
#
|
||||
# (jump-tables are implicitly disabled by RETPOLINE)
|
||||
#
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104816
|
||||
#
|
||||
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=branch -fno-jump-tables)
|
||||
else
|
||||
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
BITS := 32
|
||||
|
87
arch/x86/include/asm/ibt.h
Normal file
87
arch/x86/include/asm/ibt.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_IBT_H
|
||||
#define _ASM_X86_IBT_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* The rules for enabling IBT are:
|
||||
*
|
||||
* - CC_HAS_IBT: the toolchain supports it
|
||||
* - X86_KERNEL_IBT: it is selected in Kconfig
|
||||
* - !__DISABLE_EXPORTS: this is regular kernel code
|
||||
*
|
||||
* Esp. that latter one is a bit non-obvious, but some code like compressed,
|
||||
* purgatory, realmode etc.. is built with custom CFLAGS that do not include
|
||||
* -fcf-protection=branch and things will go *bang*.
|
||||
*
|
||||
* When all the above are satisfied, HAS_KERNEL_IBT will be 1, otherwise 0.
|
||||
*/
|
||||
#if defined(CONFIG_X86_KERNEL_IBT) && !defined(__DISABLE_EXPORTS)
|
||||
|
||||
#define HAS_KERNEL_IBT 1
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define ASM_ENDBR "endbr64\n\t"
|
||||
#else
|
||||
#define ASM_ENDBR "endbr32\n\t"
|
||||
#endif
|
||||
|
||||
#define __noendbr __attribute__((nocf_check))
|
||||
|
||||
static inline __attribute_const__ u32 gen_endbr(void)
|
||||
{
|
||||
u32 endbr;
|
||||
|
||||
/*
|
||||
* Generate ENDBR64 in a way that is sure to not result in
|
||||
* an ENDBR64 instruction as immediate.
|
||||
*/
|
||||
asm ( "mov $~0xfa1e0ff3, %[endbr]\n\t"
|
||||
"not %[endbr]\n\t"
|
||||
: [endbr] "=&r" (endbr) );
|
||||
|
||||
return endbr;
|
||||
}
|
||||
|
||||
static inline bool is_endbr(u32 val)
|
||||
{
|
||||
val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
|
||||
return val == gen_endbr();
|
||||
}
|
||||
|
||||
#else /* __ASSEMBLY__ */
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define ENDBR endbr64
|
||||
#else
|
||||
#define ENDBR endbr32
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#else /* !IBT */
|
||||
|
||||
#define HAS_KERNEL_IBT 0
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#define ASM_ENDBR
|
||||
|
||||
#define __noendbr
|
||||
|
||||
static inline bool is_endbr(u32 val) { return false; }
|
||||
|
||||
#else /* __ASSEMBLY__ */
|
||||
|
||||
#define ENDBR
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* CONFIG_X86_KERNEL_IBT */
|
||||
|
||||
#define ENDBR_INSN_SIZE (4*HAS_KERNEL_IBT)
|
||||
|
||||
#endif /* _ASM_X86_IBT_H */
|
Loading…
Reference in New Issue
Block a user