diff mbox series

x86/kcfi: Require FRED for FineIBT

Message ID 20250214192210.work.253-kees@kernel.org (mailing list archive)
State New
Headers show
Series x86/kcfi: Require FRED for FineIBT | expand

Commit Message

Kees Cook Feb. 14, 2025, 7:22 p.m. UTC
With what appears to be an unavoidable pivot gadget always present in
the kernel (the entry code), FineIBT's lack of caller-side CFI hash
validation leaves it critically flawed[1]. Require FRED for FineIBT[2]
(and probably should also require eXecute-Only memory too), and default
to kCFI when CFI is built in.

Link: https://lore.kernel.org/linux-hardening/Z60NwR4w%2F28Z7XUa@ubun/ [1]
Link: https://lore.kernel.org/linux-hardening/c46f5614-a82e-42fc-91eb-05e483a7df9c@citrix.com/ [2]
Signed-off-by: Kees Cook <kees@kernel.org>
---
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Jennifer Miller <jmill@asu.edu>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: Sami Tolvanen <samitolvanen@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
---
 arch/x86/Kconfig              | 9 +++++----
 arch/x86/include/asm/cfi.h    | 2 +-
 arch/x86/kernel/alternative.c | 4 +++-
 3 files changed, 9 insertions(+), 6 deletions(-)

Comments

Andrew Cooper Feb. 14, 2025, 7:39 p.m. UTC | #1
On 14/02/2025 7:22 pm, Kees Cook wrote:
> diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
> index ef5e0a698253..dfa2ba4cceca 100644
> --- a/arch/x86/include/asm/cfi.h
> +++ b/arch/x86/include/asm/cfi.h
> @@ -93,7 +93,7 @@
>   *
>   */
>  enum cfi_mode {
> -	CFI_AUTO,	/* FineIBT if hardware has IBT, otherwise kCFI */
> +	CFI_AUTO,	/* FineIBT if hardware has IBT, FRED, and XOM */

You discuss XOM in the commit message, but there's no check ...

>  	CFI_OFF,	/* Taditional / IBT depending on .config */
>  	CFI_KCFI,	/* Optionally CALL_PADDING, IBT, RETPOLINE */
>  	CFI_FINEIBT,	/* see arch/x86/kernel/alternative.c */
> diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
> index 97422292b609..acc12a6efc18 100644
> --- a/arch/x86/kernel/alternative.c
> +++ b/arch/x86/kernel/alternative.c
> @@ -1323,7 +1323,9 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
>  
>  	if (cfi_mode == CFI_AUTO) {
>  		cfi_mode = CFI_KCFI;
> -		if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
> +		/* FineIBT requires IBT and will only be safe with FRED */
> +		if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT) &&
> +		    cpu_feature_enabled(X86_FEATURE_FRED))

... here.

Is this meant to be "/* TODO: wire up XOM */" or is that accounted for
somewhere else?


Also, while I hate to come back and contradict myself from earlier...

Architecturally, FineIBT without FRED seems to be no improvement over
simple IBT.  (I'd love to find some way of hardening the entrypoints,
but I can't see a robust way of doing so.)

However, micro-architecturally, FineIBT is still far better than simple
IBT for speculation issue, seeing as Intel keep on staunchly refusing to
turn off the indirect predictors by default like AMD do.

A security conscious user ought to be using FineIBT for this, given a
choice, even if it's not perfect in other regards.

~Andrew
Kees Cook Feb. 14, 2025, 9:54 p.m. UTC | #2
On Fri, Feb 14, 2025 at 07:39:20PM +0000, Andrew Cooper wrote:
> On 14/02/2025 7:22 pm, Kees Cook wrote:
> > diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
> > index ef5e0a698253..dfa2ba4cceca 100644
> > --- a/arch/x86/include/asm/cfi.h
> > +++ b/arch/x86/include/asm/cfi.h
> > @@ -93,7 +93,7 @@
> >   *
> >   */
> >  enum cfi_mode {
> > -	CFI_AUTO,	/* FineIBT if hardware has IBT, otherwise kCFI */
> > +	CFI_AUTO,	/* FineIBT if hardware has IBT, FRED, and XOM */
> 
> You discuss XOM in the commit message, but there's no check ...
> 
> >  	CFI_OFF,	/* Taditional / IBT depending on .config */
> >  	CFI_KCFI,	/* Optionally CALL_PADDING, IBT, RETPOLINE */
> >  	CFI_FINEIBT,	/* see arch/x86/kernel/alternative.c */
> > diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
> > index 97422292b609..acc12a6efc18 100644
> > --- a/arch/x86/kernel/alternative.c
> > +++ b/arch/x86/kernel/alternative.c
> > @@ -1323,7 +1323,9 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
> >  
> >  	if (cfi_mode == CFI_AUTO) {
> >  		cfi_mode = CFI_KCFI;
> > -		if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
> > +		/* FineIBT requires IBT and will only be safe with FRED */
> > +		if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT) &&
> > +		    cpu_feature_enabled(X86_FEATURE_FRED))
> 
> ... here.
> 
> Is this meant to be "/* TODO: wire up XOM */" or is that accounted for
> somewhere else?

Yeah, I wasn't sure how to best capture that in here. XOM doesn't exist
yet for x86... I could add a TODO like that?

> Also, while I hate to come back and contradict myself from earlier...
> 
> Architecturally, FineIBT without FRED seems to be no improvement over
> simple IBT.  (I'd love to find some way of hardening the entrypoints,
> but I can't see a robust way of doing so.)

If you're just looking at IBT, yes. But kCFI (with or without IBT,
but without FineIBT) will do hash checking at the call site, which
should make it impossible to reach the entrypoints from an indirect call
in the first place, as they have no hash preceding them.

> However, micro-architecturally, FineIBT is still far better than simple
> IBT for speculation issue, seeing as Intel keep on staunchly refusing to
> turn off the indirect predictors by default like AMD do.
> 
> A security conscious user ought to be using FineIBT for this, given a
> choice, even if it's not perfect in other regards.

A security conscious user should use kCFI without FineIBT. :) But I
think we might be thinking about different elements of security. I am
focusing on control flow, and I think you're considering speculation?

-Kees
Andrew Cooper Feb. 14, 2025, 10:40 p.m. UTC | #3
On 14/02/2025 9:54 pm, Kees Cook wrote:
> On Fri, Feb 14, 2025 at 07:39:20PM +0000, Andrew Cooper wrote:
>> On 14/02/2025 7:22 pm, Kees Cook wrote:
>>> diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
>>> index ef5e0a698253..dfa2ba4cceca 100644
>>> --- a/arch/x86/include/asm/cfi.h
>>> +++ b/arch/x86/include/asm/cfi.h
>>> @@ -93,7 +93,7 @@
>>>   *
>>>   */
>>>  enum cfi_mode {
>>> -	CFI_AUTO,	/* FineIBT if hardware has IBT, otherwise kCFI */
>>> +	CFI_AUTO,	/* FineIBT if hardware has IBT, FRED, and XOM */
>> You discuss XOM in the commit message, but there's no check ...
>>
>>>  	CFI_OFF,	/* Taditional / IBT depending on .config */
>>>  	CFI_KCFI,	/* Optionally CALL_PADDING, IBT, RETPOLINE */
>>>  	CFI_FINEIBT,	/* see arch/x86/kernel/alternative.c */
>>> diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
>>> index 97422292b609..acc12a6efc18 100644
>>> --- a/arch/x86/kernel/alternative.c
>>> +++ b/arch/x86/kernel/alternative.c
>>> @@ -1323,7 +1323,9 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
>>>  
>>>  	if (cfi_mode == CFI_AUTO) {
>>>  		cfi_mode = CFI_KCFI;
>>> -		if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
>>> +		/* FineIBT requires IBT and will only be safe with FRED */
>>> +		if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT) &&
>>> +		    cpu_feature_enabled(X86_FEATURE_FRED))
>> ... here.
>>
>> Is this meant to be "/* TODO: wire up XOM */" or is that accounted for
>> somewhere else?
> Yeah, I wasn't sure how to best capture that in here. XOM doesn't exist
> yet for x86... I could add a TODO like that?

I get the feeling that the PKS series would have an easier time starting
with XOM (even if it hard-codes pkey1=xom and avoids the allocator in
the short term, seeing as Linux does have a good grasp of where it's
executable pages are, and how they're accessed) rather than trying to do
general page hiding.  The capability is in 3 generations of Intel CPU now.

>
>> Also, while I hate to come back and contradict myself from earlier...
>>
>> Architecturally, FineIBT without FRED seems to be no improvement over
>> simple IBT.  (I'd love to find some way of hardening the entrypoints,
>> but I can't see a robust way of doing so.)
> If you're just looking at IBT, yes. But kCFI (with or without IBT,
> but without FineIBT) will do hash checking at the call site, which
> should make it impossible to reach the entrypoints from an indirect call
> in the first place, as they have no hash preceding them.
>
>> However, micro-architecturally, FineIBT is still far better than simple
>> IBT for speculation issue, seeing as Intel keep on staunchly refusing to
>> turn off the indirect predictors by default like AMD do.
>>
>> A security conscious user ought to be using FineIBT for this, given a
>> choice, even if it's not perfect in other regards.
> A security conscious user should use kCFI without FineIBT. :) But I
> think we might be thinking about different elements of security. I am
> focusing on control flow, and I think you're considering speculation?

True.  The security realist knows they're dammed either way, and gets a
stiff drink instead.

~Andrew
Kees Cook Feb. 16, 2025, 11:52 p.m. UTC | #4
On Fri, Feb 14, 2025 at 10:40:28PM +0000, Andrew Cooper wrote:
> On 14/02/2025 9:54 pm, Kees Cook wrote:
> > On Fri, Feb 14, 2025 at 07:39:20PM +0000, Andrew Cooper wrote:
> >> Architecturally, FineIBT without FRED seems to be no improvement over
> >> simple IBT.  (I'd love to find some way of hardening the entrypoints,
> >> but I can't see a robust way of doing so.)
> > If you're just looking at IBT, yes. But kCFI (with or without IBT,
> > but without FineIBT) will do hash checking at the call site, which
> > should make it impossible to reach the entrypoints from an indirect call
> > in the first place, as they have no hash preceding them.
> >
> >> However, micro-architecturally, FineIBT is still far better than simple
> >> IBT for speculation issue, seeing as Intel keep on staunchly refusing to
> >> turn off the indirect predictors by default like AMD do.
> >>
> >> A security conscious user ought to be using FineIBT for this, given a
> >> choice, even if it's not perfect in other regards.
> > A security conscious user should use kCFI without FineIBT. :) But I
> > think we might be thinking about different elements of security. I am
> > focusing on control flow, and I think you're considering speculation?
> 
> True.  The security realist knows they're dammed either way, and gets a
> stiff drink instead.

I don't know how any of our livers survive. :)
diff mbox series

Patch

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c94dae634176..47aec3a497f6 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2432,12 +2432,13 @@  config STRICT_SIGALTSTACK_SIZE
 
 config CFI_AUTO_DEFAULT
 	bool "Attempt to use FineIBT by default at boot time"
-	depends on FINEIBT
+	depends on FINEIBT && X86_FRED
 	default y
 	help
-	  Attempt to use FineIBT by default at boot time. If enabled,
-	  this is the same as booting with "cfi=auto". If disabled,
-	  this is the same as booting with "cfi=kcfi".
+	  Attempt to use FineIBT by default at boot time if supported
+	  and sensible for the hardware. If enabled, this is the same
+	  as booting with "cfi=auto". If disabled, this is the same as
+	  booting with "cfi=kcfi".
 
 source "kernel/livepatch/Kconfig"
 
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
index ef5e0a698253..dfa2ba4cceca 100644
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -93,7 +93,7 @@ 
  *
  */
 enum cfi_mode {
-	CFI_AUTO,	/* FineIBT if hardware has IBT, otherwise kCFI */
+	CFI_AUTO,	/* FineIBT if hardware has IBT, FRED, and XOM */
 	CFI_OFF,	/* Taditional / IBT depending on .config */
 	CFI_KCFI,	/* Optionally CALL_PADDING, IBT, RETPOLINE */
 	CFI_FINEIBT,	/* see arch/x86/kernel/alternative.c */
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 97422292b609..acc12a6efc18 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1323,7 +1323,9 @@  static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
 
 	if (cfi_mode == CFI_AUTO) {
 		cfi_mode = CFI_KCFI;
-		if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
+		/* FineIBT requires IBT and will only be safe with FRED */
+		if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT) &&
+		    cpu_feature_enabled(X86_FEATURE_FRED))
 			cfi_mode = CFI_FINEIBT;
 	}