diff mbox series

[v22,04/24] x86/cpu/intel: Detect SGX supprt

Message ID 20190903142655.21943-5-jarkko.sakkinen@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series Intel SGX foundations | expand

Commit Message

Jarkko Sakkinen Sept. 3, 2019, 2:26 p.m. UTC
From: Sean Christopherson <sean.j.christopherson@intel.com>

When the CPU supports SGX, check that the BIOS has enabled SGX and SGX1
opcodes are available. Otherwise, all the SGX related capabilities.

In addition, clear X86_FEATURE_SGX_LC also in the case when the launch
enclave are read-only. This way the feature bit reflects the level that
Linux supports the launch control.

Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Co-developed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 arch/x86/kernel/cpu/intel.c | 39 +++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

Comments

Borislav Petkov Sept. 24, 2019, 4:13 p.m. UTC | #1
On Tue, Sep 03, 2019 at 05:26:35PM +0300, Jarkko Sakkinen wrote:
> From: Sean Christopherson <sean.j.christopherson@intel.com>
> 
> When the CPU supports SGX, check that the BIOS has enabled SGX and SGX1
> opcodes are available. Otherwise, all the SGX related capabilities.
> 
> In addition, clear X86_FEATURE_SGX_LC also in the case when the launch
> enclave are read-only. This way the feature bit reflects the level that
> Linux supports the launch control.
> 
> Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
> Co-developed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>  arch/x86/kernel/cpu/intel.c | 39 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 39 insertions(+)
> 
> diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
> index 8d6d92ebeb54..777ea63b4f85 100644
> --- a/arch/x86/kernel/cpu/intel.c
> +++ b/arch/x86/kernel/cpu/intel.c
> @@ -623,6 +623,42 @@ static void detect_tme(struct cpuinfo_x86 *c)
>  	c->x86_phys_bits -= keyid_bits;
>  }
>  
> +static void __maybe_unused detect_sgx(struct cpuinfo_x86 *c)
> +{
> +	unsigned long long fc;
> +
> +	rdmsrl(MSR_IA32_FEATURE_CONTROL, fc);
> +	if (!(fc & FEATURE_CONTROL_LOCKED)) {
> +		pr_err_once("sgx: The feature control MSR is not locked\n");
> +		goto err_unsupported;
> +	}
> +
> +	if (!(fc & FEATURE_CONTROL_SGX_ENABLE)) {
> +		pr_err_once("sgx: SGX is not enabled in IA32_FEATURE_CONTROL MSR\n");
> +		goto err_unsupported;
> +	}
> +
> +	if (!cpu_has(c, X86_FEATURE_SGX1)) {
> +		pr_err_once("sgx: SGX1 instruction set is not supported\n");
> +		goto err_unsupported;
> +	}
> +
> +	if (!(fc & FEATURE_CONTROL_SGX_LE_WR)) {
> +		pr_info_once("sgx: The launch control MSRs are not writable\n");
> +		goto err_msrs_rdonly;
> +	}
> +
> +	return;
> +
> +err_unsupported:
> +	setup_clear_cpu_cap(X86_FEATURE_SGX);
> +	setup_clear_cpu_cap(X86_FEATURE_SGX1);
> +	setup_clear_cpu_cap(X86_FEATURE_SGX2);
> +
> +err_msrs_rdonly:
> +	setup_clear_cpu_cap(X86_FEATURE_SGX_LC);
> +}
> +
>  static void init_cpuid_fault(struct cpuinfo_x86 *c)
>  {
>  	u64 msr;
> @@ -760,6 +796,9 @@ static void init_intel(struct cpuinfo_x86 *c)
>  	if (cpu_has(c, X86_FEATURE_TME))
>  		detect_tme(c);
>  
> +	if (IS_ENABLED(CONFIG_INTEL_SGX) && cpu_has(c, X86_FEATURE_SGX))
> +		detect_sgx(c);

Looks to me like this should run only once on the BSP instead of on
every CPU. The pr_*_once things above are a good sign for that, I'd say.

If so, define your own ->c_bsp_init function and run that from there
instead.
Sean Christopherson Sept. 24, 2019, 5:43 p.m. UTC | #2
On Tue, Sep 24, 2019 at 06:13:01PM +0200, Borislav Petkov wrote:
> On Tue, Sep 03, 2019 at 05:26:35PM +0300, Jarkko Sakkinen wrote:
> > +static void __maybe_unused detect_sgx(struct cpuinfo_x86 *c)
> > +{
> > +	unsigned long long fc;
> > +
> > +	rdmsrl(MSR_IA32_FEATURE_CONTROL, fc);
> > +	if (!(fc & FEATURE_CONTROL_LOCKED)) {
> > +		pr_err_once("sgx: The feature control MSR is not locked\n");
> > +		goto err_unsupported;
> > +	}
> > +
> > +	if (!(fc & FEATURE_CONTROL_SGX_ENABLE)) {
> > +		pr_err_once("sgx: SGX is not enabled in IA32_FEATURE_CONTROL MSR\n");
> > +		goto err_unsupported;
> > +	}
> > +
> > +	if (!cpu_has(c, X86_FEATURE_SGX1)) {
> > +		pr_err_once("sgx: SGX1 instruction set is not supported\n");
> > +		goto err_unsupported;
> > +	}
> > +
> > +	if (!(fc & FEATURE_CONTROL_SGX_LE_WR)) {
> > +		pr_info_once("sgx: The launch control MSRs are not writable\n");

This should be pr_err_once.

> > +		goto err_msrs_rdonly;
> > +	}
> > +
> > +	return;
> > +
> > +err_unsupported:
> > +	setup_clear_cpu_cap(X86_FEATURE_SGX);
> > +	setup_clear_cpu_cap(X86_FEATURE_SGX1);
> > +	setup_clear_cpu_cap(X86_FEATURE_SGX2);
> > +
> > +err_msrs_rdonly:
> > +	setup_clear_cpu_cap(X86_FEATURE_SGX_LC);
> > +}
> > +
> >  static void init_cpuid_fault(struct cpuinfo_x86 *c)
> >  {
> >  	u64 msr;
> > @@ -760,6 +796,9 @@ static void init_intel(struct cpuinfo_x86 *c)
> >  	if (cpu_has(c, X86_FEATURE_TME))
> >  		detect_tme(c);
> >  
> > +	if (IS_ENABLED(CONFIG_INTEL_SGX) && cpu_has(c, X86_FEATURE_SGX))
> > +		detect_sgx(c);
> 
> Looks to me like this should run only once on the BSP instead of on
> every CPU. The pr_*_once things above are a good sign for that, I'd say.
> 
> If so, define your own ->c_bsp_init function and run that from there
> instead.

The intent of running on every CPU is to verify MSR_IA32_FEATURE_CONTROL
is correctly configured on all CPUs.  It's extremely unlikely that
firmware would misconfigure or fail to write the MSR on only APs, but if
that does happen we'll spam dmesg and possibly panic or hang the kernel.

The severity of the fallout is why we're being paranoid.  KVM is similarly
paranoid about VMX enabling since it'll BUG() on an unexpected fault due
to a misconfigured FEATURE_CONTROL.
Borislav Petkov Sept. 24, 2019, 6:21 p.m. UTC | #3
On Tue, Sep 24, 2019 at 10:43:11AM -0700, Sean Christopherson wrote:
> The intent of running on every CPU is to verify MSR_IA32_FEATURE_CONTROL
> is correctly configured on all CPUs.  It's extremely unlikely that
> firmware would misconfigure or fail to write the MSR on only APs, but if
> that does happen we'll spam dmesg and possibly panic or hang the kernel.
> 
> The severity of the fallout is why we're being paranoid.  KVM is similarly
> paranoid about VMX enabling since it'll BUG() on an unexpected fault due
> to a misconfigured FEATURE_CONTROL.

None of that is in the commit message or written anywhere AFAICT. And my
crystal ball doesn't show it either so please write down properly why
this is needed. Better over the function as a comment I'd say.

Thx.
Jarkko Sakkinen Sept. 25, 2019, 2:46 p.m. UTC | #4
On Tue, Sep 24, 2019 at 08:21:19PM +0200, Borislav Petkov wrote:
> On Tue, Sep 24, 2019 at 10:43:11AM -0700, Sean Christopherson wrote:
> > The intent of running on every CPU is to verify MSR_IA32_FEATURE_CONTROL
> > is correctly configured on all CPUs.  It's extremely unlikely that
> > firmware would misconfigure or fail to write the MSR on only APs, but if
> > that does happen we'll spam dmesg and possibly panic or hang the kernel.
> > 
> > The severity of the fallout is why we're being paranoid.  KVM is similarly
> > paranoid about VMX enabling since it'll BUG() on an unexpected fault due
> > to a misconfigured FEATURE_CONTROL.
> 
> None of that is in the commit message or written anywhere AFAICT. And my
> crystal ball doesn't show it either so please write down properly why
> this is needed. Better over the function as a comment I'd say.

Added a remark:

    The check is done for every CPU, not just BSP, in order to verify that
    MSR_IA32_FEATURE_CONTROL is correctly configured on all CPUs. The other
    parts of the kernel, like the enclave driver, expect the same
    configuration from all CPUs.

I think here is not necessary to go into KVM implementation details to
make a case for this one. This is just a sane contract/expectation for
anything using SGX and thus it is better to validate it before anything
gets to use it.

/Jarkko
diff mbox series

Patch

diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 8d6d92ebeb54..777ea63b4f85 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -623,6 +623,42 @@  static void detect_tme(struct cpuinfo_x86 *c)
 	c->x86_phys_bits -= keyid_bits;
 }
 
+static void __maybe_unused detect_sgx(struct cpuinfo_x86 *c)
+{
+	unsigned long long fc;
+
+	rdmsrl(MSR_IA32_FEATURE_CONTROL, fc);
+	if (!(fc & FEATURE_CONTROL_LOCKED)) {
+		pr_err_once("sgx: The feature control MSR is not locked\n");
+		goto err_unsupported;
+	}
+
+	if (!(fc & FEATURE_CONTROL_SGX_ENABLE)) {
+		pr_err_once("sgx: SGX is not enabled in IA32_FEATURE_CONTROL MSR\n");
+		goto err_unsupported;
+	}
+
+	if (!cpu_has(c, X86_FEATURE_SGX1)) {
+		pr_err_once("sgx: SGX1 instruction set is not supported\n");
+		goto err_unsupported;
+	}
+
+	if (!(fc & FEATURE_CONTROL_SGX_LE_WR)) {
+		pr_info_once("sgx: The launch control MSRs are not writable\n");
+		goto err_msrs_rdonly;
+	}
+
+	return;
+
+err_unsupported:
+	setup_clear_cpu_cap(X86_FEATURE_SGX);
+	setup_clear_cpu_cap(X86_FEATURE_SGX1);
+	setup_clear_cpu_cap(X86_FEATURE_SGX2);
+
+err_msrs_rdonly:
+	setup_clear_cpu_cap(X86_FEATURE_SGX_LC);
+}
+
 static void init_cpuid_fault(struct cpuinfo_x86 *c)
 {
 	u64 msr;
@@ -760,6 +796,9 @@  static void init_intel(struct cpuinfo_x86 *c)
 	if (cpu_has(c, X86_FEATURE_TME))
 		detect_tme(c);
 
+	if (IS_ENABLED(CONFIG_INTEL_SGX) && cpu_has(c, X86_FEATURE_SGX))
+		detect_sgx(c);
+
 	init_intel_misc_features(c);
 }