Received: by 2002:a05:6a10:22f:0:0:0:0 with SMTP id 15csp432213pxk; Fri, 11 Sep 2020 10:42:26 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwyrSiqdoCIsMVmpI62p+SBYrW+I+gJ5/+BSj/jGxi+8jfGDp3G6O9M9NQNiyUOZt5L6iBG X-Received: by 2002:a50:8306:: with SMTP id 6mr3251797edh.340.1599846146262; Fri, 11 Sep 2020 10:42:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1599846146; cv=none; d=google.com; s=arc-20160816; b=iomSjSBwYMMrQcOVMYPEMU3rzeL+M72rJjKYtkYgno4riymQEJjS5r4j8nCeZREZay dRgYfXgx/RvfAty/CzRsmG++IKMrbFUhXGEdwIMufAsrFp1cqmsDRMUc4/4t5fC1J49e a76hh1eSsnP+oDhx2FeLflThWlxFnQH5nAt1Gs4S9k0tmPtY7OjMgr9sh4kIL/XBMaJQ th3Z0BRKc5R0zmgPJERu5e7HQNugJ9jBG4VVceYim4IR+reOOlKTVbk3SHX8euDlJije iyTk8U0e66W3c0gxTVxIqlZZjfaCu+JMkKa7mQmzOtBNki4X3F2ZrFgAE2YRzfAbHoab yFUg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :ironport-sdr:ironport-sdr; bh=VVu3Cg2DTbGlJjPOeJygu4CDNbg0a61QcQhRFKBl51c=; b=FWOI13L4fmIfQGxhcfx48Ur5dlokwZrmS5qhULV0mkhzA7ex/3UaFpXKCR4Vsc0QHj 3VkojkSNaAL2xr+KJOumi43UIEPMnkDj3VILNpELDt5OBSm7SHkVChhlUpdSqYwAVRiw MA3sCm+D4ywrsGn+ALuosmaPzc0ArPGUZHbSWwBzjIVPShZczMgrQslMeOLvWdEctEZT rA51DcQrv0xTjCGZttZOVIp9QIOrTOB88GWOSlLSB0otdkb0QIaA517qZkDkHDXYmikd 33SMx9tXmvDsUF6AAb+c+Prr2MEpcADbSfkfvJE0sniUgnJiGLjRftasfAyIyGIwppDm TyBA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id q19si1879405edv.61.2020.09.11.10.42.03; Fri, 11 Sep 2020 10:42:26 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725961AbgIKRkX (ORCPT + 99 others); Fri, 11 Sep 2020 13:40:23 -0400 Received: from mga05.intel.com ([192.55.52.43]:37746 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726002AbgIKMpF (ORCPT ); Fri, 11 Sep 2020 08:45:05 -0400 IronPort-SDR: QyQ4N5L8I4WtroFMdWQp++ugouxFgGfV75XVoKhTbqGKhVPEd49pstKTe0g9eZPQZ1R6cVFSld LKE1l6NgCMUw== X-IronPort-AV: E=McAfee;i="6000,8403,9740"; a="243569756" X-IronPort-AV: E=Sophos;i="5.76,415,1592895600"; d="scan'208";a="243569756" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 Sep 2020 05:44:14 -0700 IronPort-SDR: dAmzpIyvHNVIxiNU4bZQN9lE532h+JMheMbQoLDmixDFzqUgsPLlzRindjgd9T14kGdeARx1pd /UunRiYOHBfA== X-IronPort-AV: E=Sophos;i="5.76,415,1592895600"; d="scan'208";a="342288154" Received: from amaksymi-mobl.ger.corp.intel.com (HELO localhost) ([10.252.60.247]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 Sep 2020 05:44:01 -0700 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Jarkko Sakkinen , Jethro Beekman , Haitao Huang , Chunyang Hui , Jordan Hand , Nathaniel McCallum , Seth Moore , Darren Kenny , Sean Christopherson , Suresh Siddha , akpm@linux-foundation.org, andriy.shevchenko@linux.intel.com, asapek@google.com, bp@alien8.de, cedric.xing@intel.com, chenalexchen@google.com, conradparker@google.com, cyhanish@google.com, dave.hansen@intel.com, haitao.huang@intel.com, josh@joshtriplett.org, kai.huang@intel.com, kai.svahn@intel.com, kmoy@google.com, ludloff@google.com, luto@kernel.org, nhorman@redhat.com, puiterwijk@redhat.com, rientjes@google.com, tglx@linutronix.de, yaozhangx@google.com Subject: [PATCH v37 14/24] x86/sgx: Add SGX_IOC_ENCLAVE_INIT Date: Fri, 11 Sep 2020 15:40:09 +0300 Message-Id: <20200911124019.42178-15-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200911124019.42178-1-jarkko.sakkinen@linux.intel.com> References: <20200911124019.42178-1-jarkko.sakkinen@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add an ioctl that performs ENCLS[EINIT], which locks down the measurement and initializes the enclave for entrance. After this, new pages can no longer be added. Acked-by: Jethro Beekman Tested-by: Jethro Beekman Tested-by: Haitao Huang Tested-by: Chunyang Hui Tested-by: Jordan Hand Tested-by: Nathaniel McCallum Tested-by: Seth Moore Tested-by: Darren Kenny Reviewed-by: Darren Kenny Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Co-developed-by: Suresh Siddha Signed-off-by: Suresh Siddha Signed-off-by: Jarkko Sakkinen --- arch/x86/include/uapi/asm/sgx.h | 11 ++ arch/x86/kernel/cpu/sgx/encl.h | 2 + arch/x86/kernel/cpu/sgx/ioctl.c | 195 ++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h index c42a2ad3ca0b..7729730d8580 100644 --- a/arch/x86/include/uapi/asm/sgx.h +++ b/arch/x86/include/uapi/asm/sgx.h @@ -23,6 +23,8 @@ enum sgx_page_flags { _IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create) #define SGX_IOC_ENCLAVE_ADD_PAGES \ _IOWR(SGX_MAGIC, 0x01, struct sgx_enclave_add_pages) +#define SGX_IOC_ENCLAVE_INIT \ + _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) /** * struct sgx_enclave_create - parameter structure for the @@ -50,4 +52,13 @@ struct sgx_enclave_add_pages { __u64 flags; }; +/** + * struct sgx_enclave_init - parameter structure for the + * %SGX_IOC_ENCLAVE_INIT ioctl + * @sigstruct: address for the SIGSTRUCT data + */ +struct sgx_enclave_init { + __u64 sigstruct; +}; + #endif /* _UAPI_ASM_X86_SGX_H */ diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h index 8ff445476657..0448d22d3010 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -70,6 +70,8 @@ struct sgx_encl { struct xarray page_array; struct sgx_encl_page secs; cpumask_t cpumask; + unsigned long attributes; + unsigned long attributes_mask; }; extern const struct vm_operations_struct sgx_vm_ops; diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c index 5dcced1df259..51d9b24379ff 100644 --- a/arch/x86/kernel/cpu/sgx/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/ioctl.c @@ -16,6 +16,9 @@ #include "encl.h" #include "encls.h" +/* A per-cpu cache for the last known values of IA32_SGXLEPUBKEYHASHx MSRs. */ +static DEFINE_PER_CPU(u64 [4], sgx_lepubkeyhash_cache); + static u32 sgx_calc_ssa_frame_size(u32 miscselect, u64 xfrm) { u32 size_max = PAGE_SIZE; @@ -127,6 +130,9 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs) encl->base = secs->base; encl->size = secs->size; encl->ssaframesize = secs->ssa_frame_size; + encl->attributes = secs->attributes; + encl->attributes_mask = SGX_ATTR_DEBUG | SGX_ATTR_MODE64BIT | + SGX_ATTR_KSS; /* * Set SGX_ENCL_CREATED only after the enclave is fully prepped. This @@ -477,6 +483,192 @@ static long sgx_ioc_enclave_add_pages(struct sgx_encl *encl, void __user *arg) return c; } +static int __sgx_get_key_hash(struct crypto_shash *tfm, const void *modulus, + void *hash) +{ + SHASH_DESC_ON_STACK(shash, tfm); + + shash->tfm = tfm; + + return crypto_shash_digest(shash, modulus, SGX_MODULUS_SIZE, hash); +} + +static int sgx_get_key_hash(const void *modulus, void *hash) +{ + struct crypto_shash *tfm; + int ret; + + tfm = crypto_alloc_shash("sha256", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + ret = __sgx_get_key_hash(tfm, modulus, hash); + + crypto_free_shash(tfm); + return ret; +} + +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]; + } + } +} + +static int sgx_einit(struct sgx_sigstruct *sigstruct, void *token, + struct sgx_epc_page *secs, u64 *lepubkeyhash) +{ + int ret; + + preempt_disable(); + sgx_update_lepubkeyhash_msrs(lepubkeyhash, false); + ret = __einit(sigstruct, token, sgx_get_epc_addr(secs)); + if (ret == SGX_INVALID_EINITTOKEN) { + sgx_update_lepubkeyhash_msrs(lepubkeyhash, true); + ret = __einit(sigstruct, token, sgx_get_epc_addr(secs)); + } + preempt_enable(); + return ret; +} + +static int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, + void *token) +{ + u64 mrsigner[4]; + int ret; + int i; + int j; + + /* Deny initializing enclaves with attributes (namely provisioning) + * that have not been explicitly allowed. + */ + if (encl->attributes & ~encl->attributes_mask) + return -EACCES; + + ret = sgx_get_key_hash(sigstruct->modulus, mrsigner); + if (ret) + return ret; + + mutex_lock(&encl->lock); + + /* + * ENCLS[EINIT] is interruptible because it has such a high latency, + * e.g. 50k+ cycles on success. If an IRQ/NMI/SMI becomes pending, + * EINIT may fail with SGX_UNMASKED_EVENT so that the event can be + * serviced. + */ + for (i = 0; i < SGX_EINIT_SLEEP_COUNT; i++) { + for (j = 0; j < SGX_EINIT_SPIN_COUNT; j++) { + ret = sgx_einit(sigstruct, token, encl->secs.epc_page, + mrsigner); + if (ret == SGX_UNMASKED_EVENT) + continue; + else + break; + } + + if (ret != SGX_UNMASKED_EVENT) + break; + + msleep_interruptible(SGX_EINIT_SLEEP_TIME); + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto err_out; + } + } + + if (ret & ENCLS_FAULT_FLAG) { + if (encls_failed(ret)) + ENCLS_WARN(ret, "EINIT"); + + sgx_encl_destroy(encl); + ret = -EFAULT; + } else if (ret) { + pr_debug("EINIT returned %d\n", ret); + ret = -EPERM; + } else { + atomic_or(SGX_ENCL_INITIALIZED, &encl->flags); + } + +err_out: + mutex_unlock(&encl->lock); + return ret; +} + +/** + * sgx_ioc_enclave_init - handler for %SGX_IOC_ENCLAVE_INIT + * + * @filep: open file to /dev/sgx + * @arg: userspace pointer to a struct sgx_enclave_init instance + * + * Flush any outstanding enqueued EADD operations and perform EINIT. The + * Launch Enclave Public Key Hash MSRs are rewritten as necessary to match + * the enclave's MRSIGNER, which is caculated from the provided sigstruct. + * + * Return: + * 0 on success, + * SGX error code on EINIT failure, + * -errno otherwise + */ +static long sgx_ioc_enclave_init(struct sgx_encl *encl, void __user *arg) +{ + struct sgx_sigstruct *sigstruct; + struct sgx_enclave_init einit; + struct page *initp_page; + void *token; + int ret; + + if ((atomic_read(&encl->flags) & SGX_ENCL_INITIALIZED) || + !(atomic_read(&encl->flags) & SGX_ENCL_CREATED)) + return -EINVAL; + + if (copy_from_user(&einit, arg, sizeof(einit))) + return -EFAULT; + + initp_page = alloc_page(GFP_KERNEL); + if (!initp_page) + return -ENOMEM; + + sigstruct = kmap(initp_page); + token = (void *)((unsigned long)sigstruct + PAGE_SIZE / 2); + memset(token, 0, SGX_LAUNCH_TOKEN_SIZE); + + if (copy_from_user(sigstruct, (void __user *)einit.sigstruct, + sizeof(*sigstruct))) { + ret = -EFAULT; + goto out; + } + + /* + * A legacy field used with Intel signed enclaves. These used to mean + * regular and architectural enclaves. The CPU only accepts these values + * but they do not have any other meaning. + * + * Thus, reject any other values. + */ + if (sigstruct->header.vendor != 0x0000 && + sigstruct->header.vendor != 0x8086) { + ret = -EINVAL; + goto out; + } + + ret = sgx_encl_init(encl, sigstruct, token); + +out: + kunmap(initp_page); + __free_page(initp_page); + return ret; +} + + long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct sgx_encl *encl = filep->private_data; @@ -498,6 +690,9 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) case SGX_IOC_ENCLAVE_ADD_PAGES: ret = sgx_ioc_enclave_add_pages(encl, (void __user *)arg); break; + case SGX_IOC_ENCLAVE_INIT: + ret = sgx_ioc_enclave_init(encl, (void __user *)arg); + break; default: ret = -ENOIOCTLCMD; break; -- 2.25.1