Skip to content

Commit

Permalink
Merge remote-tracking branch 'tip/x86/sgx' into kvm-next
Browse files Browse the repository at this point in the history
Pull generic x86 SGX changes needed to support SGX in virtual machines.
  • Loading branch information
bonzini committed Apr 17, 2021
2 parents 387cb8e + 523caed commit d9bd008
Show file tree
Hide file tree
Showing 21 changed files with 861 additions and 224 deletions.
41 changes: 41 additions & 0 deletions Documentation/x86/sgx.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,44 @@ An application may be loaded into a container enclave which is specially
configured with a library OS and run-time which permits the application to run.
The enclave run-time and library OS work together to execute the application
when a thread enters the enclave.

Impact of Potential Kernel SGX Bugs
===================================

EPC leaks
---------

When EPC page leaks happen, a WARNING like this is shown in dmesg:

"EREMOVE returned ... and an EPC page was leaked. SGX may become unusable..."

This is effectively a kernel use-after-free of an EPC page, and due
to the way SGX works, the bug is detected at freeing. Rather than
adding the page back to the pool of available EPC pages, the kernel
intentionally leaks the page to avoid additional errors in the future.

When this happens, the kernel will likely soon leak more EPC pages, and
SGX will likely become unusable because the memory available to SGX is
limited. However, while this may be fatal to SGX, the rest of the kernel
is unlikely to be impacted and should continue to work.

As a result, when this happpens, user should stop running any new
SGX workloads, (or just any new workloads), and migrate all valuable
workloads. Although a machine reboot can recover all EPC memory, the bug
should be reported to Linux developers.


Virtual EPC
===========

The implementation has also a virtual EPC driver to support SGX enclaves
in guests. Unlike the SGX driver, an EPC page allocated by the virtual
EPC driver doesn't have a specific enclave associated with it. This is
because KVM doesn't track how a guest uses EPC pages.

As a result, the SGX core page reclaimer doesn't support reclaiming EPC
pages allocated to KVM guests through the virtual EPC driver. If the
user wants to deploy SGX applications both on the host and in guests
on the same machine, the user should reserve enough EPC (by taking out
total virtual EPC size of all SGX VMs from the physical EPC size) for
host SGX applications so they can run with acceptable performance.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -9274,6 +9274,7 @@ Q: https://patchwork.kernel.org/project/intel-sgx/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/sgx
F: Documentation/x86/sgx.rst
F: arch/x86/entry/vdso/vsgx.S
F: arch/x86/include/asm/sgx.h
F: arch/x86/include/uapi/asm/sgx.h
F: arch/x86/kernel/cpu/sgx/*
F: tools/testing/selftests/sgx/*
Expand Down
1 change: 1 addition & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1931,6 +1931,7 @@ config X86_SGX
depends on CRYPTO_SHA256=y
select SRCU
select MMU_NOTIFIER
select NUMA_KEEP_MEMINFO if NUMA
help
Intel(R) Software Guard eXtensions (SGX) is a set of CPU instructions
that can be used by applications to set aside private regions of code
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/cpufeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@
#define X86_FEATURE_FENCE_SWAPGS_KERNEL (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
#define X86_FEATURE_SPLIT_LOCK_DETECT (11*32+ 6) /* #AC for split lock */
#define X86_FEATURE_PER_THREAD_MBA (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
#define X86_FEATURE_SGX1 (11*32+ 8) /* "" Basic SGX */
#define X86_FEATURE_SGX2 (11*32+ 9) /* "" SGX Enclave Dynamic Memory Management (EDMM) */

/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */
Expand Down
50 changes: 45 additions & 5 deletions arch/x86/kernel/cpu/sgx/arch.h → arch/x86/include/asm/sgx.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@
/**
* Copyright(c) 2016-20 Intel Corporation.
*
* Contains data structures defined by the SGX architecture. Data structures
* defined by the Linux software stack should not be placed here.
* Intel Software Guard Extensions (SGX) support.
*/
#ifndef _ASM_X86_SGX_ARCH_H
#define _ASM_X86_SGX_ARCH_H
#ifndef _ASM_X86_SGX_H
#define _ASM_X86_SGX_H

#include <linux/bits.h>
#include <linux/types.h>

/*
* This file contains both data structures defined by SGX architecture and Linux
* defined software data structures and functions. The two should not be mixed
* together for better readibility. The architectural definitions come first.
*/

/* The SGX specific CPUID function. */
#define SGX_CPUID 0x12
/* EPC enumeration. */
Expand All @@ -22,16 +27,36 @@
/* The bitmask for the EPC section type. */
#define SGX_CPUID_EPC_MASK GENMASK(3, 0)

enum sgx_encls_function {
ECREATE = 0x00,
EADD = 0x01,
EINIT = 0x02,
EREMOVE = 0x03,
EDGBRD = 0x04,
EDGBWR = 0x05,
EEXTEND = 0x06,
ELDU = 0x08,
EBLOCK = 0x09,
EPA = 0x0A,
EWB = 0x0B,
ETRACK = 0x0C,
EAUG = 0x0D,
EMODPR = 0x0E,
EMODT = 0x0F,
};

/**
* enum sgx_return_code - The return code type for ENCLS, ENCLU and ENCLV
* %SGX_NOT_TRACKED: Previous ETRACK's shootdown sequence has not
* been completed yet.
* %SGX_CHILD_PRESENT SECS has child pages present in the EPC.
* %SGX_INVALID_EINITTOKEN: EINITTOKEN is invalid and enclave signer's
* public key does not match IA32_SGXLEPUBKEYHASH.
* %SGX_UNMASKED_EVENT: An unmasked event, e.g. INTR, was received
*/
enum sgx_return_code {
SGX_NOT_TRACKED = 11,
SGX_CHILD_PRESENT = 13,
SGX_INVALID_EINITTOKEN = 16,
SGX_UNMASKED_EVENT = 128,
};
Expand Down Expand Up @@ -335,4 +360,19 @@ struct sgx_sigstruct {

#define SGX_LAUNCH_TOKEN_SIZE 304

#endif /* _ASM_X86_SGX_ARCH_H */
/*
* Do not put any hardware-defined SGX structure representations below this
* comment!
*/

#ifdef CONFIG_X86_SGX_KVM
int sgx_virt_ecreate(struct sgx_pageinfo *pageinfo, void __user *secs,
int *trapnr);
int sgx_virt_einit(void __user *sigstruct, void __user *token,
void __user *secs, u64 *lepubkeyhash, int *trapnr);
#endif

int sgx_set_attribute(unsigned long *allowed_attributes,
unsigned int attribute_fd);

#endif /* _ASM_X86_SGX_H */
3 changes: 3 additions & 0 deletions arch/x86/kernel/cpu/cpuid-deps.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ static const struct cpuid_dep cpuid_deps[] = {
{ X86_FEATURE_AVX512_FP16, X86_FEATURE_AVX512BW },
{ X86_FEATURE_ENQCMD, X86_FEATURE_XSAVES },
{ X86_FEATURE_PER_THREAD_MBA, X86_FEATURE_MBA },
{ X86_FEATURE_SGX_LC, X86_FEATURE_SGX },
{ X86_FEATURE_SGX1, X86_FEATURE_SGX },
{ X86_FEATURE_SGX2, X86_FEATURE_SGX1 },
{}
};

Expand Down
71 changes: 47 additions & 24 deletions arch/x86/kernel/cpu/feat_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,9 @@ static void init_vmx_capabilities(struct cpuinfo_x86 *c)
}
#endif /* CONFIG_X86_VMX_FEATURE_NAMES */

static void clear_sgx_caps(void)
{
setup_clear_cpu_cap(X86_FEATURE_SGX);
setup_clear_cpu_cap(X86_FEATURE_SGX_LC);
}

static int __init nosgx(char *str)
{
clear_sgx_caps();
setup_clear_cpu_cap(X86_FEATURE_SGX);

return 0;
}
Expand All @@ -110,23 +104,30 @@ early_param("nosgx", nosgx);

void init_ia32_feat_ctl(struct cpuinfo_x86 *c)
{
bool enable_sgx_kvm = false, enable_sgx_driver = false;
bool tboot = tboot_enabled();
bool enable_sgx;
bool enable_vmx;
u64 msr;

if (rdmsrl_safe(MSR_IA32_FEAT_CTL, &msr)) {
clear_cpu_cap(c, X86_FEATURE_VMX);
clear_sgx_caps();
clear_cpu_cap(c, X86_FEATURE_SGX);
return;
}

/*
* Enable SGX if and only if the kernel supports SGX and Launch Control
* is supported, i.e. disable SGX if the LE hash MSRs can't be written.
*/
enable_sgx = cpu_has(c, X86_FEATURE_SGX) &&
cpu_has(c, X86_FEATURE_SGX_LC) &&
IS_ENABLED(CONFIG_X86_SGX);
enable_vmx = cpu_has(c, X86_FEATURE_VMX) &&
IS_ENABLED(CONFIG_KVM_INTEL);

if (cpu_has(c, X86_FEATURE_SGX) && IS_ENABLED(CONFIG_X86_SGX)) {
/*
* Separate out SGX driver enabling from KVM. This allows KVM
* guests to use SGX even if the kernel SGX driver refuses to
* use it. This happens if flexible Launch Control is not
* available.
*/
enable_sgx_driver = cpu_has(c, X86_FEATURE_SGX_LC);
enable_sgx_kvm = enable_vmx && IS_ENABLED(CONFIG_X86_SGX_KVM);
}

if (msr & FEAT_CTL_LOCKED)
goto update_caps;
Expand All @@ -142,15 +143,18 @@ void init_ia32_feat_ctl(struct cpuinfo_x86 *c)
* i.e. KVM is enabled, to avoid unnecessarily adding an attack vector
* for the kernel, e.g. using VMX to hide malicious code.
*/
if (cpu_has(c, X86_FEATURE_VMX) && IS_ENABLED(CONFIG_KVM_INTEL)) {
if (enable_vmx) {
msr |= FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX;

if (tboot)
msr |= FEAT_CTL_VMX_ENABLED_INSIDE_SMX;
}

if (enable_sgx)
msr |= FEAT_CTL_SGX_ENABLED | FEAT_CTL_SGX_LC_ENABLED;
if (enable_sgx_kvm || enable_sgx_driver) {
msr |= FEAT_CTL_SGX_ENABLED;
if (enable_sgx_driver)
msr |= FEAT_CTL_SGX_LC_ENABLED;
}

wrmsrl(MSR_IA32_FEAT_CTL, msr);

Expand All @@ -173,10 +177,29 @@ void init_ia32_feat_ctl(struct cpuinfo_x86 *c)
}

update_sgx:
if (!(msr & FEAT_CTL_SGX_ENABLED) ||
!(msr & FEAT_CTL_SGX_LC_ENABLED) || !enable_sgx) {
if (enable_sgx)
pr_err_once("SGX disabled by BIOS\n");
clear_sgx_caps();
if (!(msr & FEAT_CTL_SGX_ENABLED)) {
if (enable_sgx_kvm || enable_sgx_driver)
pr_err_once("SGX disabled by BIOS.\n");
clear_cpu_cap(c, X86_FEATURE_SGX);
return;
}

/*
* VMX feature bit may be cleared due to being disabled in BIOS,
* in which case SGX virtualization cannot be supported either.
*/
if (!cpu_has(c, X86_FEATURE_VMX) && enable_sgx_kvm) {
pr_err_once("SGX virtualization disabled due to lack of VMX.\n");
enable_sgx_kvm = 0;
}

if (!(msr & FEAT_CTL_SGX_LC_ENABLED) && enable_sgx_driver) {
if (!enable_sgx_kvm) {
pr_err_once("SGX Launch Control is locked. Disable SGX.\n");
clear_cpu_cap(c, X86_FEATURE_SGX);
} else {
pr_err_once("SGX Launch Control is locked. Support SGX virtualization only.\n");
clear_cpu_cap(c, X86_FEATURE_SGX_LC);
}
}
}
2 changes: 2 additions & 0 deletions arch/x86/kernel/cpu/scattered.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_CDP_L2, CPUID_ECX, 2, 0x00000010, 2 },
{ X86_FEATURE_MBA, CPUID_EBX, 3, 0x00000010, 0 },
{ X86_FEATURE_PER_THREAD_MBA, CPUID_ECX, 0, 0x00000010, 3 },
{ X86_FEATURE_SGX1, CPUID_EAX, 0, 0x00000012, 0 },
{ X86_FEATURE_SGX2, CPUID_EAX, 1, 0x00000012, 0 },
{ X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 },
{ X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 },
{ X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 },
Expand Down
1 change: 1 addition & 0 deletions arch/x86/kernel/cpu/sgx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ obj-y += \
encl.o \
ioctl.o \
main.o
obj-$(CONFIG_X86_SGX_KVM) += virt.o
17 changes: 0 additions & 17 deletions arch/x86/kernel/cpu/sgx/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,24 +136,13 @@ static const struct file_operations sgx_encl_fops = {
.get_unmapped_area = sgx_get_unmapped_area,
};

const struct file_operations sgx_provision_fops = {
.owner = THIS_MODULE,
};

static struct miscdevice sgx_dev_enclave = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sgx_enclave",
.nodename = "sgx_enclave",
.fops = &sgx_encl_fops,
};

static struct miscdevice sgx_dev_provision = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sgx_provision",
.nodename = "sgx_provision",
.fops = &sgx_provision_fops,
};

int __init sgx_drv_init(void)
{
unsigned int eax, ebx, ecx, edx;
Expand Down Expand Up @@ -187,11 +176,5 @@ int __init sgx_drv_init(void)
if (ret)
return ret;

ret = misc_register(&sgx_dev_provision);
if (ret) {
misc_deregister(&sgx_dev_enclave);
return ret;
}

return 0;
}
Loading

0 comments on commit d9bd008

Please sign in to comment.