Commit 931ab636 authored by Peter Zijlstra's avatar Peter Zijlstra
Browse files

x86/ibt: Implement FineIBT



Implement an alternative CFI scheme that merges both the fine-grained
nature of kCFI but also takes full advantage of the coarse grained
hardware CFI as provided by IBT.

To contrast:

  kCFI is a pure software CFI scheme and relies on being able to read
text -- specifically the instruction *before* the target symbol, and
does the hash validation *before* doing the call (otherwise control
flow is compromised already).

  FineIBT is a software and hardware hybrid scheme; by ensuring every
branch target starts with a hash validation it is possible to place
the hash validation after the branch. This has several advantages:

   o the (hash) load is avoided; no memop; no RX requirement.

   o IBT WAIT-FOR-ENDBR state is a speculation stop; by placing
     the hash validation in the immediate instruction after
     the branch target there is a minimal speculation window
     and the whole is a viable defence against SpectreBHB.

   o Kees feels obliged to mention it is slightly more vulnerable
     when the attacker can write code.

Obviously this patch relies on kCFI, but additionally it also relies
on the padding from the call-depth-tracking patches. It uses this
padding to place the hash-validation while the call-sites are
re-written to modify the indirect target to be 16 bytes in front of
the original target, thus hitting this new preamble.

Notably, there is no hardware that needs call-depth-tracking (Skylake)
and supports IBT (Tigerlake and onwards).

Suggested-by: default avatarJoao Moreira (Intel) <joao@overdrivepizza.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20221027092842.634714496@infradead.org
parent 9a479f76
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -444,6 +444,11 @@ void apply_returns(s32 *start, s32 *end)
{
}

void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
		   s32 *start_cfi, s32 *end_cfi)
{
}

void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
{
}
+12 −2
Original line number Diff line number Diff line
@@ -2463,17 +2463,27 @@ config FUNCTION_PADDING_BYTES
	default FUNCTION_PADDING_CFI if CFI_CLANG
	default FUNCTION_ALIGNMENT

config CALL_PADDING
	def_bool n
	depends on CC_HAS_ENTRY_PADDING && OBJTOOL
	select FUNCTION_ALIGNMENT_16B

config FINEIBT
	def_bool y
	depends on X86_KERNEL_IBT && CFI_CLANG && RETPOLINE
	select CALL_PADDING

config HAVE_CALL_THUNKS
	def_bool y
	depends on CC_HAS_ENTRY_PADDING && RETHUNK && OBJTOOL

config CALL_THUNKS
	def_bool n
	select FUNCTION_ALIGNMENT_16B
	select CALL_PADDING

config PREFIX_SYMBOLS
	def_bool y
	depends on CALL_THUNKS && !CFI_CLANG
	depends on CALL_PADDING && !CFI_CLANG

menuconfig SPECULATION_MITIGATIONS
	bool "Mitigations for speculative execution vulnerabilities"
+1 −1
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ ifdef CONFIG_SLS
  KBUILD_CFLAGS += -mharden-sls=all
endif

ifdef CONFIG_CALL_THUNKS
ifdef CONFIG_CALL_PADDING
PADDING_CFLAGS := -fpatchable-function-entry=$(CONFIG_FUNCTION_PADDING_BYTES),$(CONFIG_FUNCTION_PADDING_BYTES)
KBUILD_CFLAGS += $(PADDING_CFLAGS)
export PADDING_CFLAGS
+2 −0
Original line number Diff line number Diff line
@@ -78,6 +78,8 @@ extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
extern void apply_retpolines(s32 *start, s32 *end);
extern void apply_returns(s32 *start, s32 *end);
extern void apply_ibt_endbr(s32 *start, s32 *end);
extern void apply_fineibt(s32 *start_retpoline, s32 *end_retpoine,
			  s32 *start_cfi, s32 *end_cfi);

struct module;
struct paravirt_patch_site;
+3 −3
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
#define __ALIGN		.balign CONFIG_FUNCTION_ALIGNMENT, 0x90;
#define __ALIGN_STR	__stringify(__ALIGN)

#if defined(CONFIG_CALL_THUNKS) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
#if defined(CONFIG_CALL_PADDING) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
#define FUNCTION_PADDING	.skip CONFIG_FUNCTION_ALIGNMENT, 0x90;
#else
#define FUNCTION_PADDING
@@ -57,7 +57,7 @@
#endif /* __ASSEMBLY__ */

/*
 * Depending on -fpatchable-function-entry=N,N usage (CONFIG_CALL_THUNKS) the
 * Depending on -fpatchable-function-entry=N,N usage (CONFIG_CALL_PADDING) the
 * CFI symbol layout changes.
 *
 * Without CALL_THUNKS:
@@ -81,7 +81,7 @@
 * In both cases the whole thing is FUNCTION_ALIGNMENT aligned and sized.
 */

#ifdef CONFIG_CALL_THUNKS
#ifdef CONFIG_CALL_PADDING
#define CFI_PRE_PADDING
#define CFI_POST_PADDING	.skip	CONFIG_FUNCTION_PADDING_BYTES, 0x90;
#else
Loading