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 | ||||
| 	  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 a new issue
	
	 Peter Zijlstra
						Peter Zijlstra