forked from mirrors/linux
		
	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
					
				
					 3 changed files with 121 additions and 2 deletions
				
			
		|  | @ -1861,6 +1861,26 @@ config X86_UMIP | ||||||
| 	  specific cases in protected and virtual-8086 modes. Emulated | 	  specific cases in protected and virtual-8086 modes. Emulated | ||||||
| 	  results are dummy. | 	  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 | config X86_INTEL_MEMORY_PROTECTION_KEYS | ||||||
| 	prompt "Memory Protection Keys" | 	prompt "Memory Protection Keys" | ||||||
| 	def_bool y | 	def_bool y | ||||||
|  |  | ||||||
|  | @ -36,7 +36,7 @@ endif | ||||||
| 
 | 
 | ||||||
| # How to compile the 16-bit code.  Note we always compile for -march=i386;
 | # 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.
 | # 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 \
 | 		   -Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
 | ||||||
| 		   -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
 | 		   -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
 | ||||||
| 		   -mno-mmx -mno-sse $(call cc-option,-fcf-protection=none) | 		   -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 | 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) | KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none) | ||||||
|  | endif | ||||||
| 
 | 
 | ||||||
| ifeq ($(CONFIG_X86_32),y) | ifeq ($(CONFIG_X86_32),y) | ||||||
|         BITS := 32 |         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 a new issue
	
	 Peter Zijlstra
						Peter Zijlstra