diff mbox series

[v17,04/26] x86/cpufeatures: Introduce X86_FEATURE_CET and setup functions

Message ID 20201229213053.16395-5-yu-cheng.yu@intel.com (mailing list archive)
State New, archived
Headers show
Series Control-flow Enforcement: Shadow Stack | expand

Commit Message

Yu-cheng Yu Dec. 29, 2020, 9:30 p.m. UTC
Introduce a software-defined X86_FEATURE_CET, which indicates either Shadow
Stack or Indirect Branch Tracking (or both) is present.  Also introduce
related cpu init/setup functions.

Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com>
---
 arch/x86/include/asm/cpufeatures.h          |  2 +-
 arch/x86/include/asm/disabled-features.h    |  5 ++-
 arch/x86/include/uapi/asm/processor-flags.h |  2 ++
 arch/x86/kernel/cpu/common.c                | 40 ++++++++++++++++++++-
 4 files changed, 46 insertions(+), 3 deletions(-)

Comments

Borislav Petkov Jan. 11, 2021, 5:56 p.m. UTC | #1
On Tue, Dec 29, 2020 at 01:30:31PM -0800, Yu-cheng Yu wrote:
> @@ -895,6 +903,12 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
>  	}
>  }
>  
> +static void init_cet_features(struct cpuinfo_x86 *c)
> +{
> +	if (cpu_has(c, X86_FEATURE_SHSTK) || cpu_has(c, X86_FEATURE_IBT))
> +		set_cpu_cap(c, X86_FEATURE_CET);
> +}

No need for that function - just add this two-liner to bsp_init_intel()
and not in get_cpu_cap().

> +static void adjust_combined_cpu_features(void)
> +{
> +#ifdef CONFIG_X86_CET_USER
> +	if (test_bit(X86_FEATURE_SHSTK, (unsigned long *)cpu_caps_cleared) &&
> +	    test_bit(X86_FEATURE_IBT, (unsigned long *)cpu_caps_cleared))
> +		setup_clear_cpu_cap(X86_FEATURE_CET);
> +#endif

There's no need for this function...

> +}
> +
>  /*
>   * We parse cpu parameters early because fpu__init_system() is executed
>   * before parse_early_param().
> @@ -1252,9 +1276,19 @@ static void __init cpu_parse_early_param(void)
>  	if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
>  		setup_clear_cpu_cap(X86_FEATURE_XSAVES);
>  
> +	/*
> +	 * CET states are XSAVES states and options must be parsed early.
> +	 */
> +#ifdef CONFIG_X86_CET_USER
> +	if (cmdline_find_option_bool(boot_command_line, "no_user_shstk"))
> +		setup_clear_cpu_cap(X86_FEATURE_SHSTK);

... when you can do

	setup_clear_cpu_cap(X86_FEATURE_CET);

here and...

> +	if (cmdline_find_option_bool(boot_command_line, "no_user_ibt"))
> +		setup_clear_cpu_cap(X86_FEATURE_IBT);

... here.

Thx.
Yu-cheng Yu Jan. 11, 2021, 8:25 p.m. UTC | #2
On 1/11/2021 9:56 AM, Borislav Petkov wrote:
> On Tue, Dec 29, 2020 at 01:30:31PM -0800, Yu-cheng Yu wrote:
>> @@ -895,6 +903,12 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
>>   	}
>>   }
>>   
>> +static void init_cet_features(struct cpuinfo_x86 *c)
>> +{
>> +	if (cpu_has(c, X86_FEATURE_SHSTK) || cpu_has(c, X86_FEATURE_IBT))
>> +		set_cpu_cap(c, X86_FEATURE_CET);
>> +}
> 
> No need for that function - just add this two-liner to bsp_init_intel()
> and not in get_cpu_cap().
> 

I will move these to bsp_init_intel(), and change to:

if (cpu_has(c, X86_FEATURE_SHSTK) || cpu_has(c, X86_FEATURE_IBT))
	setup_force_cpu_cap(X86_FEATURE_CET);

>> +static void adjust_combined_cpu_features(void)
>> +{
>> +#ifdef CONFIG_X86_CET_USER
>> +	if (test_bit(X86_FEATURE_SHSTK, (unsigned long *)cpu_caps_cleared) &&
>> +	    test_bit(X86_FEATURE_IBT, (unsigned long *)cpu_caps_cleared))
>> +		setup_clear_cpu_cap(X86_FEATURE_CET);
>> +#endif
> 
> There's no need for this function...
> 
>> +}
>> +
>>   /*
>>    * We parse cpu parameters early because fpu__init_system() is executed
>>    * before parse_early_param().
>> @@ -1252,9 +1276,19 @@ static void __init cpu_parse_early_param(void)
>>   	if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
>>   		setup_clear_cpu_cap(X86_FEATURE_XSAVES);
>>   
>> +	/*
>> +	 * CET states are XSAVES states and options must be parsed early.
>> +	 */
>> +#ifdef CONFIG_X86_CET_USER
>> +	if (cmdline_find_option_bool(boot_command_line, "no_user_shstk"))
>> +		setup_clear_cpu_cap(X86_FEATURE_SHSTK);
> 
> ... when you can do
> 
> 	setup_clear_cpu_cap(X86_FEATURE_CET);
> 
> here and...
> 
>> +	if (cmdline_find_option_bool(boot_command_line, "no_user_ibt"))
>> +		setup_clear_cpu_cap(X86_FEATURE_IBT);
> 
> ... here.
>

Two problems here.  X86_FEATURE_CET indicates either CET features is 
enabled, not both.  Also, "clearcpuid" can has CET features.  However, 
since X86_FEATURE_CET is now set in bsp_init_intel() (after 
cpu_parse_early_params()), I think, adjust_combined_cpu_features() can 
be removed.  I will test it.

--
Thanks,
Yu-cheng
diff mbox series

Patch

diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 292fe87b26b3..d1866659edbd 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -108,7 +108,7 @@ 
 #define X86_FEATURE_EXTD_APICID		( 3*32+26) /* Extended APICID (8 bits) */
 #define X86_FEATURE_AMD_DCM		( 3*32+27) /* AMD multi-node processor */
 #define X86_FEATURE_APERFMPERF		( 3*32+28) /* P-State hardware coordination feedback capability (APERF/MPERF MSRs) */
-/* free					( 3*32+29) */
+#define X86_FEATURE_CET			( 3*32+29) /* Control-flow enforcement */
 #define X86_FEATURE_NONSTOP_TSC_S3	( 3*32+30) /* TSC doesn't stop in S3 state */
 #define X86_FEATURE_TSC_KNOWN_FREQ	( 3*32+31) /* TSC has known frequency */
 
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
index 4d3b7ce509e5..86ac4a1c6d81 100644
--- a/arch/x86/include/asm/disabled-features.h
+++ b/arch/x86/include/asm/disabled-features.h
@@ -71,9 +71,11 @@ 
 #ifdef CONFIG_X86_CET_USER
 #define DISABLE_SHSTK	0
 #define DISABLE_IBT	0
+#define DISABLE_CET	0
 #else
 #define DISABLE_SHSTK	(1 << (X86_FEATURE_SHSTK & 31))
 #define DISABLE_IBT	(1 << (X86_FEATURE_IBT & 31))
+#define DISABLE_CET	(1 << (X86_FEATURE_CET & 31))
 #endif
 
 /*
@@ -82,7 +84,8 @@ 
 #define DISABLED_MASK0	(DISABLE_VME)
 #define DISABLED_MASK1	0
 #define DISABLED_MASK2	0
-#define DISABLED_MASK3	(DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR)
+#define DISABLED_MASK3	(DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR| \
+			 DISABLE_CET)
 #define DISABLED_MASK4	(DISABLE_PCID)
 #define DISABLED_MASK5	0
 #define DISABLED_MASK6	0
diff --git a/arch/x86/include/uapi/asm/processor-flags.h b/arch/x86/include/uapi/asm/processor-flags.h
index bcba3c643e63..a8df907e8017 100644
--- a/arch/x86/include/uapi/asm/processor-flags.h
+++ b/arch/x86/include/uapi/asm/processor-flags.h
@@ -130,6 +130,8 @@ 
 #define X86_CR4_SMAP		_BITUL(X86_CR4_SMAP_BIT)
 #define X86_CR4_PKE_BIT		22 /* enable Protection Keys support */
 #define X86_CR4_PKE		_BITUL(X86_CR4_PKE_BIT)
+#define X86_CR4_CET_BIT		23 /* enable Control-flow Enforcement */
+#define X86_CR4_CET		_BITUL(X86_CR4_CET_BIT)
 
 /*
  * x86-64 Task Priority Register, CR8
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 35ad8480c464..03c367f79adc 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -510,6 +510,14 @@  static __init int setup_disable_pku(char *arg)
 __setup("nopku", setup_disable_pku);
 #endif /* CONFIG_X86_64 */
 
+static __always_inline void setup_cet(struct cpuinfo_x86 *c)
+{
+	if (!cpu_feature_enabled(X86_FEATURE_CET))
+		return;
+
+	cr4_set_bits(X86_CR4_CET);
+}
+
 /*
  * Some CPU features depend on higher CPUID levels, which may not always
  * be available due to CPUID level capping or broken virtualization
@@ -895,6 +903,12 @@  static void init_speculation_control(struct cpuinfo_x86 *c)
 	}
 }
 
+static void init_cet_features(struct cpuinfo_x86 *c)
+{
+	if (cpu_has(c, X86_FEATURE_SHSTK) || cpu_has(c, X86_FEATURE_IBT))
+		set_cpu_cap(c, X86_FEATURE_CET);
+}
+
 void get_cpu_cap(struct cpuinfo_x86 *c)
 {
 	u32 eax, ebx, ecx, edx;
@@ -960,6 +974,7 @@  void get_cpu_cap(struct cpuinfo_x86 *c)
 	if (c->extended_cpuid_level >= 0x8000000a)
 		c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
 
+	init_cet_features(c);
 	init_scattered_cpuid_features(c);
 	init_speculation_control(c);
 
@@ -1221,6 +1236,15 @@  static void detect_nopl(void)
 #endif
 }
 
+static void adjust_combined_cpu_features(void)
+{
+#ifdef CONFIG_X86_CET_USER
+	if (test_bit(X86_FEATURE_SHSTK, (unsigned long *)cpu_caps_cleared) &&
+	    test_bit(X86_FEATURE_IBT, (unsigned long *)cpu_caps_cleared))
+		setup_clear_cpu_cap(X86_FEATURE_CET);
+#endif
+}
+
 /*
  * We parse cpu parameters early because fpu__init_system() is executed
  * before parse_early_param().
@@ -1252,9 +1276,19 @@  static void __init cpu_parse_early_param(void)
 	if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
 		setup_clear_cpu_cap(X86_FEATURE_XSAVES);
 
+	/*
+	 * CET states are XSAVES states and options must be parsed early.
+	 */
+#ifdef CONFIG_X86_CET_USER
+	if (cmdline_find_option_bool(boot_command_line, "no_user_shstk"))
+		setup_clear_cpu_cap(X86_FEATURE_SHSTK);
+	if (cmdline_find_option_bool(boot_command_line, "no_user_ibt"))
+		setup_clear_cpu_cap(X86_FEATURE_IBT);
+#endif
+
 	arglen = cmdline_find_option(boot_command_line, "clearcpuid", arg, sizeof(arg));
 	if (arglen <= 0)
-		return;
+		goto done;
 
 	pr_info("Clearing CPUID bits:");
 	do {
@@ -1272,6 +1306,9 @@  static void __init cpu_parse_early_param(void)
 		}
 	} while (res == 2);
 	pr_cont("\n");
+
+done:
+	adjust_combined_cpu_features();
 }
 
 /*
@@ -1591,6 +1628,7 @@  static void identify_cpu(struct cpuinfo_x86 *c)
 
 	x86_init_rdrand(c);
 	setup_pku(c);
+	setup_cet(c);
 
 	/*
 	 * Clear/Set all flags overridden by options, need do it