From: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> Enclaves are SGX hosted measured and signed software entities. ENCLS[EINIT] leaf function checks that the enclave has a legit signed measurement and transforms the enclave to the state ready for execution. The signed measurement is provided by the caller in the form of SIGSTRUCT data structure [1]. Wrap ENCLS[EINIT] into sgx_einit(). Set MSR_IA32_SGXLEPUBKEYHASH* MSRs to match the public key contained in the SIGSTRUCT [2]. This sets Linux to enforce a policy where the provided public key is as long as the signed measurement matches the enclave contents in memory. Add a per-cpu cache to avoid unnecessary reads and write to the MSRs as they are expensive operations. [1] Intel SDM: 37.1.3 ENCLAVE SIGNATURE STRUCTURE (SIGSTRUCT) [2] Intel SDM: 38.1.4 Intel SGX Launch Control Configuration Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> Co-developed-by: Jarkko Sakkinen <jarkko.sakkinen@xxxxxxxxxxxxxxx> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@xxxxxxxxxxxxxxx> --- arch/x86/kernel/cpu/sgx/Makefile | 1 + arch/x86/kernel/cpu/sgx/encls.c | 57 ++++++++++++++++++++++++++++++++ arch/x86/kernel/cpu/sgx/encls.h | 3 ++ 3 files changed, 61 insertions(+) create mode 100644 arch/x86/kernel/cpu/sgx/encls.c diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makefile index 2dec75916a5e..874492d9e3bd 100644 --- a/arch/x86/kernel/cpu/sgx/Makefile +++ b/arch/x86/kernel/cpu/sgx/Makefile @@ -1,3 +1,4 @@ obj-y += \ + encls.o \ main.o \ reclaim.o diff --git a/arch/x86/kernel/cpu/sgx/encls.c b/arch/x86/kernel/cpu/sgx/encls.c new file mode 100644 index 000000000000..44291062967a --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/encls.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-19 Intel Corporation. + +#include <asm/cpufeature.h> +#include <asm/traps.h> +#include "encls.h" +#include "sgx.h" + +/* A per-cpu cache for the last known values of IA32_SGXLEPUBKEYHASHx MSRs. */ +static DEFINE_PER_CPU(u64 [4], sgx_lepubkeyhash_cache); + +static void sgx_update_lepubkeyhash_msrs(u64 *lepubkeyhash, bool enforce) +{ + u64 *cache; + int i; + + cache = per_cpu(sgx_lepubkeyhash_cache, smp_processor_id()); + for (i = 0; i < 4; i++) { + if (enforce || (lepubkeyhash[i] != cache[i])) { + wrmsrl(MSR_IA32_SGXLEPUBKEYHASH0 + i, lepubkeyhash[i]); + cache[i] = lepubkeyhash[i]; + } + } +} + +/** + * sgx_einit - initialize an enclave + * @sigstruct: a pointer a SIGSTRUCT + * @token: a pointer an EINITTOKEN (optional) + * @secs: a pointer a SECS + * @lepubkeyhash: the desired value for IA32_SGXLEPUBKEYHASHx MSRs + * + * Execute ENCLS[EINIT], writing the IA32_SGXLEPUBKEYHASHx MSRs according + * to @lepubkeyhash (if possible and necessary). + * + * Return: + * 0 on success, + * -errno or SGX error on failure + */ +int sgx_einit(struct sgx_sigstruct *sigstruct, struct sgx_einittoken *token, + struct sgx_epc_page *secs, u64 *lepubkeyhash) +{ + int ret; + + if (!boot_cpu_has(X86_FEATURE_SGX_LC)) + return __einit(sigstruct, token, sgx_epc_addr(secs)); + + preempt_disable(); + sgx_update_lepubkeyhash_msrs(lepubkeyhash, false); + ret = __einit(sigstruct, token, sgx_epc_addr(secs)); + if (ret == SGX_INVALID_EINITTOKEN) { + sgx_update_lepubkeyhash_msrs(lepubkeyhash, true); + ret = __einit(sigstruct, token, sgx_epc_addr(secs)); + } + preempt_enable(); + return ret; +} diff --git a/arch/x86/kernel/cpu/sgx/encls.h b/arch/x86/kernel/cpu/sgx/encls.h index d6381e4f6eb2..af94bbfe4cf6 100644 --- a/arch/x86/kernel/cpu/sgx/encls.h +++ b/arch/x86/kernel/cpu/sgx/encls.h @@ -248,4 +248,7 @@ static inline int __ewb(struct sgx_pageinfo *pginfo, void *addr, return __encls_ret_3(EWB, pginfo, addr, va); } +int sgx_einit(struct sgx_sigstruct *sigstruct, struct sgx_einittoken *token, + struct sgx_epc_page *secs, u64 *lepubkeyhash); + #endif /* _X86_ENCLS_H */ -- 2.20.1