diff options
Diffstat (limited to 'arch/x86/kernel/alternative.c')
| -rw-r--r-- | arch/x86/kernel/alternative.c | 71 | 
1 files changed, 67 insertions, 4 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 72646d75b6ff..2dcf3a06af09 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -778,6 +778,8 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }  #ifdef CONFIG_X86_KERNEL_IBT +static void poison_cfi(void *addr); +  static void __init_or_module poison_endbr(void *addr, bool warn)  {  	u32 endbr, poison = gen_endbr_poison(); @@ -802,8 +804,11 @@ static void __init_or_module poison_endbr(void *addr, bool warn)  /*   * Generated by: objtool --ibt + * + * Seal the functions for indirect calls by clobbering the ENDBR instructions + * and the kCFI hash value.   */ -void __init_or_module noinline apply_ibt_endbr(s32 *start, s32 *end) +void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end)  {  	s32 *s; @@ -812,13 +817,13 @@ void __init_or_module noinline apply_ibt_endbr(s32 *start, s32 *end)  		poison_endbr(addr, true);  		if (IS_ENABLED(CONFIG_FINEIBT)) -			poison_endbr(addr - 16, false); +			poison_cfi(addr - 16);  	}  }  #else -void __init_or_module apply_ibt_endbr(s32 *start, s32 *end) { } +void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }  #endif /* CONFIG_X86_KERNEL_IBT */ @@ -1063,6 +1068,17 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)  	return 0;  } +static void cfi_rewrite_endbr(s32 *start, s32 *end) +{ +	s32 *s; + +	for (s = start; s < end; s++) { +		void *addr = (void *)s + *s; + +		poison_endbr(addr+16, false); +	} +} +  /* .retpoline_sites */  static int cfi_rand_callers(s32 *start, s32 *end)  { @@ -1157,14 +1173,19 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,  		return;  	case CFI_FINEIBT: +		/* place the FineIBT preamble at func()-16 */  		ret = cfi_rewrite_preamble(start_cfi, end_cfi);  		if (ret)  			goto err; +		/* rewrite the callers to target func()-16 */  		ret = cfi_rewrite_callers(start_retpoline, end_retpoline);  		if (ret)  			goto err; +		/* now that nobody targets func()+0, remove ENDBR there */ +		cfi_rewrite_endbr(start_cfi, end_cfi); +  		if (builtin)  			pr_info("Using FineIBT CFI\n");  		return; @@ -1177,6 +1198,41 @@ err:  	pr_err("Something went horribly wrong trying to rewrite the CFI implementation.\n");  } +static inline void poison_hash(void *addr) +{ +	*(u32 *)addr = 0; +} + +static void poison_cfi(void *addr) +{ +	switch (cfi_mode) { +	case CFI_FINEIBT: +		/* +		 * __cfi_\func: +		 *	osp nopl (%rax) +		 *	subl	$0, %r10d +		 *	jz	1f +		 *	ud2 +		 * 1:	nop +		 */ +		poison_endbr(addr, false); +		poison_hash(addr + fineibt_preamble_hash); +		break; + +	case CFI_KCFI: +		/* +		 * __cfi_\func: +		 *	movl	$0, %eax +		 *	.skip	11, 0x90 +		 */ +		poison_hash(addr + 1); +		break; + +	default: +		break; +	} +} +  #else  static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, @@ -1184,6 +1240,10 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,  {  } +#ifdef CONFIG_X86_KERNEL_IBT +static void poison_cfi(void *addr) { } +#endif +  #endif  void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, @@ -1565,7 +1625,10 @@ void __init alternative_instructions(void)  	 */  	callthunks_patch_builtin_calls(); -	apply_ibt_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end); +	/* +	 * Seal all functions that do not have their address taken. +	 */ +	apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end);  #ifdef CONFIG_SMP  	/* Patch to UP if other cpus not imminent. */  |