From patchwork Tue Nov 6 13:45:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10670513 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E5C0C13BF for ; Tue, 6 Nov 2018 13:53:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D3DA829BAC for ; Tue, 6 Nov 2018 13:53:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C83C829BDB; Tue, 6 Nov 2018 13:53:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 48C9C29BAC for ; Tue, 6 Nov 2018 13:53:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388427AbeKFXSa (ORCPT ); Tue, 6 Nov 2018 18:18:30 -0500 Received: from mga17.intel.com ([192.55.52.151]:16367 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388048AbeKFXSa (ORCPT ); Tue, 6 Nov 2018 18:18:30 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 06 Nov 2018 05:53:10 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,472,1534834800"; d="scan'208";a="247411306" Received: from fhoeg-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.66]) by orsmga004.jf.intel.com with ESMTP; 06 Nov 2018 05:53:03 -0800 From: Jarkko Sakkinen To: x86@kernel.org, platform-driver-x86@vger.kernel.org, linux-sgx@vger.kernel.org Cc: dave.hansen@intel.com, sean.j.christopherson@intel.com, nhorman@redhat.com, npmccallum@redhat.com, serge.ayoun@intel.com, shay.katz-zamir@intel.com, haitao.huang@intel.com, andriy.shevchenko@linux.intel.com, tglx@linutronix.de, kai.svahn@intel.com, Jarkko Sakkinen , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Suresh Siddha , linux-kernel@vger.kernel.org (open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)) Subject: [PATCH v16 17/22] x86/sgx: Add sgx_einit() for initializing enclaves Date: Tue, 6 Nov 2018 15:45:56 +0200 Message-Id: <20181106134758.10572-18-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181106134758.10572-1-jarkko.sakkinen@linux.intel.com> References: <20181106134758.10572-1-jarkko.sakkinen@linux.intel.com> MIME-Version: 1.0 Sender: linux-sgx-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sgx@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sean Christopherson Add a helper function to perform ENCLS(EINIT) with the correct LE hash MSR values. ENCLS[EINIT] initializes an enclave, verifying the enclave's measurement and preparing it for execution, i.e. the enclave cannot be run until it has been initialized. The measurement aspect of EINIT references the MSR_IA32_SGXLEPUBKEYHASH* MSRs, with the CPU comparing CPU compares the key (technically its hash) used to sign the enclave[1] with the key hash stored in the MSRs, and will reject EINIT if the keys do not match. A per-cpu cache is used to avoid writing the MSRs as writing the MSRs is extraordinarily expensive, e.g. 300-400 cycles per MSR. Because the cache may become stale, force update the MSRs and retry EINIT if the first EINIT fails due to an "invalid token". An invalid token error does not necessarily mean the MSRs need to be updated, but the cost of an unnecessary write is minimal relative to the cost of EINIT itself. [1] For EINIT's purposes, the effective signer of the enclave may be the enclave's owner, or a separate Launch Enclave that has created an EINIT token for the target enclave. When using an EINIT token, the key used to sign the token must match the MSRs in order for EINIT to succeed. Signed-off-by: Sean Christopherson Co-developed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- arch/x86/include/asm/sgx.h | 2 ++ arch/x86/kernel/cpu/intel_sgx.c | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h index 372fc378018b..4cdfa1d22c6e 100644 --- a/arch/x86/include/asm/sgx.h +++ b/arch/x86/include/asm/sgx.h @@ -310,5 +310,7 @@ static inline int __emodt(struct sgx_secinfo *secinfo, void *addr) struct sgx_epc_page *sgx_alloc_page(void); int __sgx_free_page(struct sgx_epc_page *page); void sgx_free_page(struct sgx_epc_page *page); +int sgx_einit(struct sgx_sigstruct *sigstruct, struct sgx_einittoken *token, + struct sgx_epc_page *secs, u64 *lepubkeyhash); #endif /* _ASM_X86_SGX_H */ diff --git a/arch/x86/kernel/cpu/intel_sgx.c b/arch/x86/kernel/cpu/intel_sgx.c index e9a225fa14b7..ec3d5de6b037 100644 --- a/arch/x86/kernel/cpu/intel_sgx.c +++ b/arch/x86/kernel/cpu/intel_sgx.c @@ -15,6 +15,9 @@ EXPORT_SYMBOL_GPL(sgx_epc_sections); static int sgx_nr_epc_sections; +/* A per-cpu cache for the last known values of IA32_SGXLEPUBKEYHASHx MSRs. */ +static DEFINE_PER_CPU(u64 [4], sgx_lepubkeyhash_cache); + /** * sgx_alloc_page - Allocate an EPC page * @@ -91,6 +94,53 @@ void sgx_free_page(struct sgx_epc_page *page) } EXPORT_SYMBOL_GPL(sgx_free_page); +static void sgx_update_lepubkeyhash_msrs(u64 *lepubkeyhash, bool enforce) +{ + u64 __percpu *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; +} +EXPORT_SYMBOL(sgx_einit); static __init void sgx_free_epc_section(struct sgx_epc_section *section) {