From patchwork Fri Dec 21 23:11:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741083 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 86F10161F for ; Fri, 21 Dec 2018 23:12:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 766F028538 for ; Fri, 21 Dec 2018 23:12:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6A04A28618; Fri, 21 Dec 2018 23:12:13 +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 EB07F28538 for ; Fri, 21 Dec 2018 23:12:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387417AbeLUXMM (ORCPT ); Fri, 21 Dec 2018 18:12:12 -0500 Received: from mga18.intel.com ([134.134.136.126]:25740 "EHLO mga18.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731990AbeLUXMM (ORCPT ); Fri, 21 Dec 2018 18:12:12 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:12:12 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338156" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:12:04 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Kai Huang , Jarkko Sakkinen Subject: [PATCH v18 01/25] x86/cpufeatures: Add Intel-defined SGX feature bit Date: Sat, 22 Dec 2018 01:11:30 +0200 Message-Id: <20181221231154.6120-2-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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: Kai Huang X86_FEATURE_SGX reflects whether or not the CPU supports Intel's Software Guard eXtensions (SGX). Signed-off-by: Kai Huang Signed-off-by: Jarkko Sakkinen Reviewed-by: Borislav Petkov --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/disabled-features.h | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 28c4a502b419..da7fed4939a3 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -236,6 +236,7 @@ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ #define X86_FEATURE_TSC_ADJUST ( 9*32+ 1) /* TSC adjustment MSR 0x3B */ +#define X86_FEATURE_SGX ( 9*32+ 2) /* Software Guard Extensions */ #define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */ #define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */ #define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */ diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h index 33833d1909af..1e6da9b8c6f6 100644 --- a/arch/x86/include/asm/disabled-features.h +++ b/arch/x86/include/asm/disabled-features.h @@ -56,6 +56,12 @@ # define DISABLE_PTI (1 << (X86_FEATURE_PTI & 31)) #endif +#ifdef CONFIG_SGX_CORE +# define DISABLE_SGX_CORE 0 +#else +# define DISABLE_SGX_CORE (1 << (X86_FEATURE_SGX & 31)) +#endif + /* * Make sure to add features to the correct mask */ @@ -68,7 +74,7 @@ #define DISABLED_MASK6 0 #define DISABLED_MASK7 (DISABLE_PTI) #define DISABLED_MASK8 0 -#define DISABLED_MASK9 (DISABLE_MPX) +#define DISABLED_MASK9 (DISABLE_MPX|DISABLE_SGX_CORE) #define DISABLED_MASK10 0 #define DISABLED_MASK11 0 #define DISABLED_MASK12 0 From patchwork Fri Dec 21 23:11:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741085 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 8F61713B5 for ; Fri, 21 Dec 2018 23:12:22 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 78AB628538 for ; Fri, 21 Dec 2018 23:12:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6B0822861C; Fri, 21 Dec 2018 23:12:22 +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 EBBFA28538 for ; Fri, 21 Dec 2018 23:12:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388414AbeLUXMV (ORCPT ); Fri, 21 Dec 2018 18:12:21 -0500 Received: from mga05.intel.com ([192.55.52.43]:37718 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731990AbeLUXMV (ORCPT ); Fri, 21 Dec 2018 18:12:21 -0500 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/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:12:21 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338196" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:12:13 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 02/25] x86/cpufeatures: Add SGX sub-features (as Linux-defined bits) Date: Sat, 22 Dec 2018 01:11:31 +0200 Message-Id: <20181221231154.6120-3-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 CPUID_12_EAX is an Intel-defined feature bits leaf dedicated for SGX that enumerates the SGX instruction sets that are supported by the CPU, e.g. SGX1, SGX2, etc... Because Linux currently only cares about two bits (SGX1 and SGX2) and there are currently only four documented bits in total, relocate the bits to Linux-defined word 8 to conserve space. But, keep the bit positions identical between the Intel-defined value and the Linux-defined value, e.g. keep SGX1 at bit 0. This allows KVM to use its existing code for probing guest CPUID bits using Linux's X86_FEATURE_* definitions. To do so, shift around some existing bits to effectively reserve bits 0-7 of word 8 for SGX sub-features. Signed-off-by: Sean Christopherson Signed-off-by: Jarkko Sakkinen --- arch/x86/include/asm/cpufeatures.h | 22 ++++++++++++++++------ arch/x86/include/asm/disabled-features.h | 6 +++++- arch/x86/kernel/cpu/scattered.c | 2 ++ tools/arch/x86/include/asm/cpufeatures.h | 21 +++++++++++++++------ 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index da7fed4939a3..94d2b1cf8ee0 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -222,12 +222,22 @@ #define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ #define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */ -/* Virtualization flags: Linux defined, word 8 */ -#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ -#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ -#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */ -#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */ -#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */ +/* + * Scattered Intel features: Linux defined, word 8. + * + * Note that the bit location of the SGX features is meaningful as KVM expects + * the Linux defined bit to match the Intel defined bit, e.g. X86_FEATURE_SGX1 + * must remain at bit 0, SGX2 at bit 1, etc... + */ +#define X86_FEATURE_SGX1 ( 8*32+ 0) /* SGX1 leaf functions */ +#define X86_FEATURE_SGX2 ( 8*32+ 1) /* SGX2 leaf functions */ +/* Bits [0:7] are reserved for SGX */ + +#define X86_FEATURE_TPR_SHADOW ( 8*32+ 8) /* Intel TPR Shadow */ +#define X86_FEATURE_VNMI ( 8*32+ 9) /* Intel Virtual NMI */ +#define X86_FEATURE_FLEXPRIORITY ( 8*32+10) /* Intel FlexPriority */ +#define X86_FEATURE_EPT ( 8*32+11) /* Intel Extended Page Table */ +#define X86_FEATURE_VPID ( 8*32+12) /* Intel Virtual Processor ID */ #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ #define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h index 1e6da9b8c6f6..140d0c64456b 100644 --- a/arch/x86/include/asm/disabled-features.h +++ b/arch/x86/include/asm/disabled-features.h @@ -28,12 +28,16 @@ # define DISABLE_CYRIX_ARR (1<<(X86_FEATURE_CYRIX_ARR & 31)) # define DISABLE_CENTAUR_MCR (1<<(X86_FEATURE_CENTAUR_MCR & 31)) # define DISABLE_PCID 0 +# define DISABLE_SGX1 0 +# define DISABLE_SGX2 0 #else # define DISABLE_VME 0 # define DISABLE_K6_MTRR 0 # define DISABLE_CYRIX_ARR 0 # define DISABLE_CENTAUR_MCR 0 # define DISABLE_PCID (1<<(X86_FEATURE_PCID & 31)) +# define DISABLE_SGX1 (1<<(X86_FEATURE_SGX1 & 31)) +# define DISABLE_SGX2 (1<<(X86_FEATURE_SGX2 & 31)) #endif /* CONFIG_X86_64 */ #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS @@ -73,7 +77,7 @@ #define DISABLED_MASK5 0 #define DISABLED_MASK6 0 #define DISABLED_MASK7 (DISABLE_PTI) -#define DISABLED_MASK8 0 +#define DISABLED_MASK8 (DISABLE_SGX1|DISABLE_SGX2) #define DISABLED_MASK9 (DISABLE_MPX|DISABLE_SGX_CORE) #define DISABLED_MASK10 0 #define DISABLED_MASK11 0 diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 772c219b6889..f7f0970b8f89 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -26,6 +26,8 @@ static const struct cpuid_bit cpuid_bits[] = { { X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 }, { X86_FEATURE_CDP_L2, CPUID_ECX, 2, 0x00000010, 2 }, { X86_FEATURE_MBA, CPUID_EBX, 3, 0x00000010, 0 }, + { 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 }, diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 89a048c2faec..9cc7628b9845 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -222,12 +222,21 @@ #define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ #define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */ -/* Virtualization flags: Linux defined, word 8 */ -#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ -#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ -#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */ -#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */ -#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */ +/* + * Scattered Intel features: Linux defined, word 8. + * + * Note that the bit numbers of the SGX features are meaningful as KVM expects + * the Linux defined bit to match the Intel defined bit, e.g. X86_FEATURE_SGX1 + * must remain at bit 0, SGX2 at bit 1, etc... + */ +#define X86_FEATURE_SGX1 ( 8*32+ 0) /* SGX1 leaf functions */ +#define X86_FEATURE_SGX2 ( 8*32+ 1) /* SGX2 leaf functions */ + +#define X86_FEATURE_TPR_SHADOW ( 8*32+ 8) /* Intel TPR Shadow */ +#define X86_FEATURE_VNMI ( 8*32+ 9) /* Intel Virtual NMI */ +#define X86_FEATURE_FLEXPRIORITY ( 8*32+10) /* Intel FlexPriority */ +#define X86_FEATURE_EPT ( 8*32+11) /* Intel Extended Page Table */ +#define X86_FEATURE_VPID ( 8*32+12) /* Intel Virtual Processor ID */ #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ #define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ From patchwork Fri Dec 21 23:11:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741087 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 27C72161F for ; Fri, 21 Dec 2018 23:12:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1732E28538 for ; Fri, 21 Dec 2018 23:12:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0AB8C28558; Fri, 21 Dec 2018 23:12:32 +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 71CA728618 for ; Fri, 21 Dec 2018 23:12:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390848AbeLUXMb (ORCPT ); Fri, 21 Dec 2018 18:12:31 -0500 Received: from mga07.intel.com ([134.134.136.100]:34204 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731990AbeLUXMb (ORCPT ); Fri, 21 Dec 2018 18:12:31 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:12:30 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338220" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:12:23 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 03/25] x86/msr: Add IA32_FEATURE_CONTROL.SGX_ENABLE definition Date: Sat, 22 Dec 2018 01:11:32 +0200 Message-Id: <20181221231154.6120-4-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 new IA32_FEATURE_CONTROL bit, SGX_ENABLE, which must be set in order to execute SGX instructions, i.e. ENCL{S,U,V}. The existence of the bit is enumerated by CPUID as X86_FEATURE_SGX. Like all other flags in IA32_FEATURE_CONTROL, the MSR must be locked for SGX_ENABLE to take effect. Signed-off-by: Sean Christopherson Signed-off-by: Jarkko Sakkinen --- arch/x86/include/asm/msr-index.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 80f4a4f38c79..082890bff490 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -487,6 +487,7 @@ #define FEATURE_CONTROL_LOCKED (1<<0) #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2) +#define FEATURE_CONTROL_SGX_ENABLE (1<<18) #define FEATURE_CONTROL_LMCE (1<<20) #define MSR_IA32_APICBASE 0x0000001b From patchwork Fri Dec 21 23:11:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741089 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 396DC161F for ; Fri, 21 Dec 2018 23:12:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2845D28538 for ; Fri, 21 Dec 2018 23:12:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1BD3C28618; Fri, 21 Dec 2018 23:12:43 +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 96E2C28538 for ; Fri, 21 Dec 2018 23:12:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390880AbeLUXMm (ORCPT ); Fri, 21 Dec 2018 18:12:42 -0500 Received: from mga11.intel.com ([192.55.52.93]:21074 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731990AbeLUXMm (ORCPT ); Fri, 21 Dec 2018 18:12:42 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:12:42 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338242" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:12:32 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Kai Huang , Jarkko Sakkinen Subject: [PATCH v18 04/25] x86/cpufeatures: Add Intel-defined SGX_LC feature bit Date: Sat, 22 Dec 2018 01:11:33 +0200 Message-Id: <20181221231154.6120-5-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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: Kai Huang X86_FEATURE_SGX_LC reflects whether or not the CPU supports SGX Launch Control, i.e. enumerates the existence of IA32_FEATURE_CONTROL's SGX_LE_WR bit and the IA32_SGXLEPUBKEYHASH MSRs. Signed-off-by: Kai Huang Signed-off-by: Jarkko Sakkinen --- arch/x86/include/asm/cpufeatures.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 94d2b1cf8ee0..f55c7b596bd2 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -344,6 +344,7 @@ #define X86_FEATURE_CLDEMOTE (16*32+25) /* CLDEMOTE instruction */ #define X86_FEATURE_MOVDIRI (16*32+27) /* MOVDIRI instruction */ #define X86_FEATURE_MOVDIR64B (16*32+28) /* MOVDIR64B instruction */ +#define X86_FEATURE_SGX_LC (16*32+30) /* Software Guard Extensions Launch Control */ /* AMD-defined CPU features, CPUID level 0x80000007 (EBX), word 17 */ #define X86_FEATURE_OVERFLOW_RECOV (17*32+ 0) /* MCA overflow recovery support */ From patchwork Fri Dec 21 23:11:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741093 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 04ACC13B5 for ; Fri, 21 Dec 2018 23:12:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E9AB528538 for ; Fri, 21 Dec 2018 23:12:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DD66A28618; Fri, 21 Dec 2018 23:12:53 +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 9405228538 for ; Fri, 21 Dec 2018 23:12:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390890AbeLUXMx (ORCPT ); Fri, 21 Dec 2018 18:12:53 -0500 Received: from mga07.intel.com ([134.134.136.100]:34243 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390875AbeLUXMx (ORCPT ); Fri, 21 Dec 2018 18:12:53 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:12:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338254" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:12:43 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 05/25] x86/msr: Add SGX Launch Control MSR definitions Date: Sat, 22 Dec 2018 01:11:34 +0200 Message-Id: <20181221231154.6120-6-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 new IA32_FEATURE_CONTROL bit, SGX_LE_WR. When set, SGX_LE_WR allows software to write the SGXLEPUBKEYHASH MSRs (see below). The The existence of the bit is enumerated by CPUID as X86_FEATURE_SGX_LC. Like all other flags in IA32_FEATURE_CONTROL, the MSR must be locked for SGX_LE_WR to take effect. Add four MSRs, SGXLEPUBKEYHASH{0,1,2,3}, or in human readable form, the SGX Launch Enclave Public Key Hash MSRs. These MSRs correspond to the key that is used by the CPU to determine whether or not to allow software to enter an enclave. When ENCLS[EINIT] is executed, which is a prerequisite to entering the enclave, the CPU compares the key (technically its hash) used to sign the enclave with the key hash stored in the MSRs, and will reject EINIT if the keys do not match. Enclaves can also be blessed by proxy, in which case a Launch Enclave generates and signs an EINIT TOKEN. If a valid token is provided, ENCLS[EINIT] compares the signer of the token against the MSRs instead of the signer of the enclave. The SGXLEPUBKEYHASH MSRs only exist on CPUs that support SGX Launch Control, enumerated by X86_FEATURE_SGX_LC. CPUs without Launch Control use a hardcoded key for the ENCLS[EINIT] checks. An internal hardcoded key is also used as the reset value for the hash MSRs when they exist. As a final note, the SGX_LEPUBKEYHASH MSRs can also be written by pre-boot firmware prior to activating SGX (SGX activation is done by setting bit 0 in MSR 0x7A). Thus, firmware can lock the MSRs to a non-Intel value by writing the MSRs and locking IA32_FEATURE_CONTROL without setting SGX_LE_WR. Signed-off-by: Sean Christopherson Co-developed-by: Haim Cohen Signed-off-by: Haim Cohen Signed-off-by: Jarkko Sakkinen --- arch/x86/include/asm/msr-index.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 082890bff490..9274179a445c 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -487,6 +487,7 @@ #define FEATURE_CONTROL_LOCKED (1<<0) #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2) +#define FEATURE_CONTROL_SGX_LE_WR (1<<17) #define FEATURE_CONTROL_SGX_ENABLE (1<<18) #define FEATURE_CONTROL_LMCE (1<<20) @@ -500,6 +501,12 @@ #define MSR_IA32_UCODE_WRITE 0x00000079 #define MSR_IA32_UCODE_REV 0x0000008b +/* Intel SGX Launch Enclave Public Key Hash MSRs */ +#define MSR_IA32_SGXLEPUBKEYHASH0 0x0000008C +#define MSR_IA32_SGXLEPUBKEYHASH1 0x0000008D +#define MSR_IA32_SGXLEPUBKEYHASH2 0x0000008E +#define MSR_IA32_SGXLEPUBKEYHASH3 0x0000008F + #define MSR_IA32_SMM_MONITOR_CTL 0x0000009b #define MSR_IA32_SMBASE 0x0000009e From patchwork Fri Dec 21 23:11:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741095 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 DF59C161F for ; Fri, 21 Dec 2018 23:13:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CC43E28538 for ; Fri, 21 Dec 2018 23:13:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BD9B128618; Fri, 21 Dec 2018 23:13:02 +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 6BAAB28538 for ; Fri, 21 Dec 2018 23:13:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390875AbeLUXNC (ORCPT ); Fri, 21 Dec 2018 18:13:02 -0500 Received: from mga17.intel.com ([192.55.52.151]:17548 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388956AbeLUXNB (ORCPT ); Fri, 21 Dec 2018 18:13:01 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:13:01 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338273" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:12:53 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Dave Hansen , Jarkko Sakkinen Subject: [PATCH v18 06/25] x86/mm: x86/sgx: Add new 'PF_SGX' page fault error code bit Date: Sat, 22 Dec 2018 01:11:35 +0200 Message-Id: <20181221231154.6120-7-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 The SGX bit is set in the #PF error code if and only if the fault is detected by the Enclave Page Cache Map (EPCM), a hardware-managed table that enforces the paging permissions defined by the enclave, e.g. to prevent the kernel from changing the permissions of an enclave's page(s). Despite triggering a #PF, a #PF with PF_SGX has nothing to do with paging. Cc: Dave Hansen Signed-off-by: Sean Christopherson Signed-off-by: Jarkko Sakkinen --- arch/x86/include/asm/traps.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 3de69330e6c5..165c93dd700e 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -162,5 +162,6 @@ enum x86_pf_error_code { X86_PF_RSVD = 1 << 3, X86_PF_INSTR = 1 << 4, X86_PF_PK = 1 << 5, + X86_PF_SGX = 1 << 15, }; #endif /* _ASM_X86_TRAPS_H */ From patchwork Fri Dec 21 23:11:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741097 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 A1AB7161F for ; Fri, 21 Dec 2018 23:13:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9088E28538 for ; Fri, 21 Dec 2018 23:13:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 841CD28618; Fri, 21 Dec 2018 23:13:13 +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 2F08528538 for ; Fri, 21 Dec 2018 23:13:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390891AbeLUXNN (ORCPT ); Fri, 21 Dec 2018 18:13:13 -0500 Received: from mga17.intel.com ([192.55.52.151]:17555 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388956AbeLUXNM (ORCPT ); Fri, 21 Dec 2018 18:13:12 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:13:12 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338312" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:13:03 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Andy Lutomirski , Dave Hansen , Jarkko Sakkinen Subject: [PATCH v18 07/25] x86/mm: x86/sgx: Signal SIGSEGV for userspace #PFs w/ PF_SGX Date: Sat, 22 Dec 2018 01:11:36 +0200 Message-Id: <20181221231154.6120-8-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 The PF_SGX bit is set if and only if the #PF is detected by the SGX Enclave Page Cache Map (EPCM). The EPCM is a hardware-managed table that enforces accesses to an enclave's EPC pages in addition to the software-managed kernel page tables, i.e. the effective permissions for an EPC page are a logical AND of the kernel's page tables and the corresponding EPCM entry. The EPCM is consulted only after an access walks the kernel's page tables, i.e.: a. the access was allowed by the kernel b. the kernel's tables have become less restrictive than the EPCM c. the kernel cannot fixup the cause of the fault Noteably, (b) implies that either the kernel has botched the EPC mappings or the EPCM has been invalidated (see below). Regardless of why the fault occurred, userspace needs to be alerted so that it can take appropriate action, e.g. restart the enclave. This is reinforced by (c) as the kernel doesn't really have any other reasonable option, i.e. signalling SIGSEGV is actually the least severe action possible. Although the primary purpose of the EPCM is to prevent a malicious or compromised kernel from attacking an enclave, e.g. by modifying the enclave's page tables, do not WARN on a #PF w/ PF_SGX set. The SGX architecture effectively allows the CPU to invalidate all EPCM entries at will and requires that software be prepared to handle an EPCM fault at any time. The architecture defines this behavior because the EPCM is encrypted with an ephemeral key that isn't exposed to software. As such, the EPCM entries cannot be preserved across transitions that result in a new key being used, e.g. CPU power down as part of an S3 transition or when a VM is live migrated to a new physical system. Cc: Andy Lutomirski Cc: Dave Hansen Signed-off-by: Sean Christopherson Signed-off-by: Jarkko Sakkinen --- arch/x86/mm/fault.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 71d4b9d4d43f..eb8db2425b5b 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1108,6 +1108,19 @@ access_error(unsigned long error_code, struct vm_area_struct *vma) if (error_code & X86_PF_PK) return 1; + /* + * Access is blocked by the Enclave Page Cache Map (EPCM), i.e. the + * access is allowed by the PTE but not the EPCM. This usually happens + * when the EPCM is yanked out from under us, e.g. by hardware after a + * suspend/resume cycle. In any case, software, i.e. the kernel, can't + * fix the source of the fault as the EPCM can't be directly modified + * by software. Handle the fault as an access error in order to signal + * userspace, e.g. so that userspace can rebuild their enclave(s), even + * though userspace may not have actually violated access permissions. + */ + if (unlikely(error_code & X86_PF_SGX)) + return 1; + /* * Make sure to check the VMA so that we do not perform * faults just to hit a X86_PF_PK as soon as we fill in a From patchwork Fri Dec 21 23:11:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741099 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 A503A13B5 for ; Fri, 21 Dec 2018 23:13:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 956AD28538 for ; Fri, 21 Dec 2018 23:13:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 88B9F28618; Fri, 21 Dec 2018 23:13:25 +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 6C48928538 for ; Fri, 21 Dec 2018 23:13:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388956AbeLUXNX (ORCPT ); Fri, 21 Dec 2018 18:13:23 -0500 Received: from mga09.intel.com ([134.134.136.24]:16734 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389005AbeLUXNU (ORCPT ); Fri, 21 Dec 2018 18:13:20 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:13:19 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338331" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:13:13 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 08/25] x86/cpu/intel: Detect SGX support and update caps appropriately Date: Sat, 22 Dec 2018 01:11:37 +0200 Message-Id: <20181221231154.6120-9-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Similar to other large Intel features such as VMX and TXT, SGX must be explicitly enabled in IA32_FEATURE_CONTROL MSR to be truly usable. Clear all SGX related capabilities if SGX is not fully enabled in IA32_FEATURE_CONTROL or if the SGX1 instruction set isn't supported (impossible on bare metal, theoretically possible in a VM if the VMM is doing something weird). Like SGX itself, SGX Launch Control must be explicitly enabled via a flag in IA32_FEATURE_CONTROL. Clear the SGX_LC capability if Launch Control is not fully enabled (or obviously if SGX itself is disabled). Note that clearing X86_FEATURE_SGX_LC creates a bit of a conundrum regarding the SGXLEPUBKEYHASH MSRs, as it may be desirable to read the MSRs even if they are not writable, e.g. to query the configured key, but clearing the capability leaves no breadcrum for discerning whether or not the MSRs exist. But, such usage will be rare (KVM is the only known case at this time) and not performance critical, so it's not unreasonable to require the use of rdmsr_safe(). Clearing the cap bit eliminates the need for an additional flag to track whether or not Launch Control is truly enabled, which is what we care about the vast majority of the time. Signed-off-by: Sean Christopherson Co-developed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- 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 fc3c07fe7df5..19ac424b6591 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -596,6 +596,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_intel_energy_perf(struct cpuinfo_x86 *c) { u64 epb; @@ -763,6 +799,9 @@ static void init_intel(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_TME)) detect_tme(c); + if (IS_ENABLED(CONFIG_SGX) && cpu_has(c, X86_FEATURE_SGX)) + detect_sgx(c); + init_intel_energy_perf(c); init_intel_misc_features(c); From patchwork Fri Dec 21 23:11:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741101 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 6A316161F for ; Fri, 21 Dec 2018 23:13:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5674228538 for ; Fri, 21 Dec 2018 23:13:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 462BB28618; Fri, 21 Dec 2018 23:13:29 +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 D97DF28538 for ; Fri, 21 Dec 2018 23:13:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390892AbeLUXN2 (ORCPT ); Fri, 21 Dec 2018 18:13:28 -0500 Received: from mga11.intel.com ([192.55.52.93]:21116 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390789AbeLUXN2 (ORCPT ); Fri, 21 Dec 2018 18:13:28 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:13:28 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338370" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:13:21 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 09/25] x86/sgx: Define SGX1 and SGX2 ENCLS leafs Date: Sat, 22 Dec 2018 01:11:38 +0200 Message-Id: <20181221231154.6120-10-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 ENCLS, a.k.a. Enclave System instruction, is an umbrella instruction for a variety of privileged SGX functions. The ENCLS function to be executed is specified in EAX, a la GETSEC of SMX/TXT fame. Leafs may use additional registers for function-specific operands. ENCLS also introduces its own set of error codes that (some) leafs use to return pass/fail information to software. Leafs that return an error code also modify RFLAGS. And finally, ENCLS generates ENCLS-specific #GPs and #PFs. ENCLS leafs functions are organized under SGX sub-features, e.g. SGX1 defines the base ENCLS function set and SGX2 adds ENCLS functions to enable dynamic EPC management. At this time, only the SGX1 and SGX2 function sets are supported by Linux; the other published sets relate to VMM EPC oversubscription, which is far out on the horizon. Define the ENCLS leafs in a dedicated file as more architecturally defined SGX constants and data structures will be introduced in short order. Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/include/asm/sgx_arch.h | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 arch/x86/include/asm/sgx_arch.h diff --git a/arch/x86/include/asm/sgx_arch.h b/arch/x86/include/asm/sgx_arch.h new file mode 100644 index 000000000000..e068db46835e --- /dev/null +++ b/arch/x86/include/asm/sgx_arch.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/** + * Copyright(c) 2016-18 Intel Corporation. + * + * Contains data structures defined by the SGX architecture. Data structures + * defined by the Linux software stack should not be placed here. + */ +#ifndef _ASM_X86_SGX_ARCH_H +#define _ASM_X86_SGX_ARCH_H + +/** + * enum sgx_encls_leaves - ENCLS leaf functions + * %SGX_ECREATE: Create an enclave. + * %SGX_EADD: Add a page to an uninitialized enclave. + * %SGX_EINIT: Initialize an enclave, i.e. launch an enclave. + * %SGX_EREMOVE: Remove a page from an enclave. + * %SGX_EDBGRD: Read a word from an enclve (peek). + * %SGX_EDBGWR: Write a word to an enclave (poke). + * %SGX_EEXTEND: Measure 256 bytes of an added enclave page. + * %SGX_ELDB: Load a swapped page in blocked state. + * %SGX_ELDU: Load a swapped page in unblocked state. + * %SGX_EBLOCK: Change page state to blocked i.e. entering hardware + * threads cannot access it and create new TLB entries. + * %SGX_EPA: Create a Version Array (VA) page used to store isvsvn + * number for a swapped EPC page. + * %SGX_EWB: Swap an enclave page to the regular memory. Checks that + * all threads have exited that were in the previous + * shoot-down sequence. + * %SGX_ETRACK: Start a new shoot down sequence. Used to together with + * EBLOCK to make sure that a page is safe to swap. + * %SGX_EAUG: Add a page to an initialized enclave. + * %SGX_EMODPR: Restrict an EPC page's permissions. + * %SGX_EMODT: Modify the page type of an EPC page. + */ +enum sgx_encls_leaves { + SGX_ECREATE = 0x00, + SGX_EADD = 0x01, + SGX_EINIT = 0x02, + SGX_EREMOVE = 0x03, + SGX_EDGBRD = 0x04, + SGX_EDGBWR = 0x05, + SGX_EEXTEND = 0x06, + SGX_ELDB = 0x07, + SGX_ELDU = 0x08, + SGX_EBLOCK = 0x09, + SGX_EPA = 0x0A, + SGX_EWB = 0x0B, + SGX_ETRACK = 0x0C, + SGX_EAUG = 0x0D, + SGX_EMODPR = 0x0E, + SGX_EMODT = 0x0F, +}; + +#endif /* _ASM_X86_SGX_ARCH_H */ From patchwork Fri Dec 21 23:11:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741103 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 D3A9C161F for ; Fri, 21 Dec 2018 23:13:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C50A628538 for ; Fri, 21 Dec 2018 23:13:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B89EF28618; Fri, 21 Dec 2018 23:13:39 +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 525B028538 for ; Fri, 21 Dec 2018 23:13:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392204AbeLUXNj (ORCPT ); Fri, 21 Dec 2018 18:13:39 -0500 Received: from mga14.intel.com ([192.55.52.115]:13618 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390789AbeLUXNi (ORCPT ); Fri, 21 Dec 2018 18:13:38 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:13:38 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338384" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:13:30 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 10/25] x86/sgx: Add ENCLS architectural error codes Date: Sat, 22 Dec 2018 01:11:39 +0200 Message-Id: <20181221231154.6120-11-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 The SGX architecture defines an extensive set of error codes that are used by ENCL{S,U,V} instructions to provide software with (somewhat) precise error information. Though they are architectural, define the known error codes in a separate file from sgx_arch.h so that they can be exposed to userspace. For some ENCLS leafs, e.g. EINIT, returning the exact error code on failure can enable userspace to make informed decisions when an operation fails. Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/include/asm/sgx_arch.h | 2 + arch/x86/include/uapi/asm/sgx_errno.h | 91 +++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 arch/x86/include/uapi/asm/sgx_errno.h diff --git a/arch/x86/include/asm/sgx_arch.h b/arch/x86/include/asm/sgx_arch.h index e068db46835e..6cd572fa95fa 100644 --- a/arch/x86/include/asm/sgx_arch.h +++ b/arch/x86/include/asm/sgx_arch.h @@ -8,6 +8,8 @@ #ifndef _ASM_X86_SGX_ARCH_H #define _ASM_X86_SGX_ARCH_H +#include + /** * enum sgx_encls_leaves - ENCLS leaf functions * %SGX_ECREATE: Create an enclave. diff --git a/arch/x86/include/uapi/asm/sgx_errno.h b/arch/x86/include/uapi/asm/sgx_errno.h new file mode 100644 index 000000000000..48b87aed58d7 --- /dev/null +++ b/arch/x86/include/uapi/asm/sgx_errno.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright(c) 2018 Intel Corporation. + * + * Contains the architecturally defined error codes that are returned by SGX + * instructions, e.g. ENCLS, and may be propagated to userspace via errno. + */ + +#ifndef _UAPI_ASM_X86_SGX_ERRNO_H +#define _UAPI_ASM_X86_SGX_ERRNO_H + +/** + * enum sgx_encls_leaves - return codes for ENCLS, ENCLU and ENCLV + * %SGX_SUCCESS: No error. + * %SGX_INVALID_SIG_STRUCT: SIGSTRUCT contains an invalid value. + * %SGX_INVALID_ATTRIBUTE: Enclave is not attempting to access a resource + * for which it is not authorized. + * %SGX_BLKSTATE: EPC page is already blocked. + * %SGX_INVALID_MEASUREMENT: SIGSTRUCT or EINITTOKEN contains an incorrect + * measurement. + * %SGX_NOTBLOCKABLE: EPC page type is not one which can be blocked. + * %SGX_PG_INVLD: EPC page is invalid (and cannot be blocked). + * %SGX_EPC_PAGE_CONFLICT: EPC page in use by another SGX instruction. + * %SGX_INVALID_SIGNATURE: Enclave's signature does not validate with + * public key enclosed in SIGSTRUCT. + * %SGX_MAC_COMPARE_FAIL: MAC check failed when reloading EPC page. + * %SGX_PAGE_NOT_BLOCKED: EPC page is not marked as blocked. + * %SGX_NOT_TRACKED: ETRACK has not been completed on the EPC page. + * %SGX_VA_SLOT_OCCUPIED: Version array slot contains a valid entry. + * %SGX_CHILD_PRESENT: Enclave has child pages present in the EPC. + * %SGX_ENCLAVE_ACT: Logical processors are currently executing + * inside the enclave. + * %SGX_ENTRYEPOCH_LOCKED: SECS locked for EPOCH update, i.e. an ETRACK is + * currently executing on the SECS. + * %SGX_INVALID_EINITTOKEN: EINITTOKEN is invalid and enclave signer's + * public key does not match IA32_SGXLEPUBKEYHASH. + * %SGX_PREV_TRK_INCMPL: All processors did not complete the previous + * tracking sequence. + * %SGX_PG_IS_SECS: Target EPC page is an SECS and cannot be + * blocked. + * %SGX_PAGE_ATTRIBUTES_MISMATCH: Attributes of the EPC page do not match + * the expected values. + * %SGX_PAGE_NOT_MODIFIABLE: EPC page cannot be modified because it is in + * the PENDING or MODIFIED state. + * %SGX_PAGE_NOT_DEBUGGABLE: EPC page cannot be modified because it is in + * the PENDING or MODIFIED state. + * %SGX_INVALID_COUNTER: {In,De}crementing a counter would cause it to + * {over,under}flow. + * %SGX_PG_NONEPC: Target page is not an EPC page. + * %SGX_TRACK_NOT_REQUIRED: Target page type does not require tracking. + * %SGX_INVALID_CPUSVN: Security version number reported by CPU is less + * than what is required by the enclave. + * %SGX_INVALID_ISVSVN: Security version number of enclave is less than + * what is required by the KEYREQUEST struct. + * %SGX_UNMASKED_EVENT: An unmasked event, e.g. INTR, was received + * while the instruction was executing. + * %SGX_INVALID_KEYNAME: Requested key is not supported by hardware. + */ +enum sgx_return_codes { + SGX_SUCCESS = 0, + SGX_INVALID_SIG_STRUCT = 1, + SGX_INVALID_ATTRIBUTE = 2, + SGX_BLKSTATE = 3, + SGX_INVALID_MEASUREMENT = 4, + SGX_NOTBLOCKABLE = 5, + SGX_PG_INVLD = 6, + SGX_EPC_PAGE_CONFLICT = 7, + SGX_INVALID_SIGNATURE = 8, + SGX_MAC_COMPARE_FAIL = 9, + SGX_PAGE_NOT_BLOCKED = 10, + SGX_NOT_TRACKED = 11, + SGX_VA_SLOT_OCCUPIED = 12, + SGX_CHILD_PRESENT = 13, + SGX_ENCLAVE_ACT = 14, + SGX_ENTRYEPOCH_LOCKED = 15, + SGX_INVALID_EINITTOKEN = 16, + SGX_PREV_TRK_INCMPL = 17, + SGX_PG_IS_SECS = 18, + SGX_PAGE_ATTRIBUTES_MISMATCH = 19, + SGX_PAGE_NOT_MODIFIABLE = 20, + SGX_PAGE_NOT_DEBUGGABLE = 21, + SGX_INVALID_COUNTER = 25, + SGX_PG_NONEPC = 26, + SGX_TRACK_NOT_REQUIRED = 27, + SGX_INVALID_CPUSVN = 32, + SGX_INVALID_ISVSVN = 64, + SGX_UNMASKED_EVENT = 128, + SGX_INVALID_KEYNAME = 256, +}; + +#endif /* _UAPI_ASM_X86_SGX_ERRNO_H */ From patchwork Fri Dec 21 23:11:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741105 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 B84C317E1 for ; Fri, 21 Dec 2018 23:13:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A68A928618 for ; Fri, 21 Dec 2018 23:13:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9A4EC286A8; Fri, 21 Dec 2018 23:13:50 +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 59EA328618 for ; Fri, 21 Dec 2018 23:13:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392205AbeLUXNt (ORCPT ); Fri, 21 Dec 2018 18:13:49 -0500 Received: from mga01.intel.com ([192.55.52.88]:11636 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390789AbeLUXNt (ORCPT ); Fri, 21 Dec 2018 18:13:49 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:13:48 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338398" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:13:40 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 11/25] x86/sgx: Add SGX1 and SGX2 architectural data structures Date: Sat, 22 Dec 2018 01:11:40 +0200 Message-Id: <20181221231154.6120-12-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Define the data structures used by various ENCLS functions needed for Linux to support all SGX1 and SGX2 ENCLS leaf functions. This is not an exhaustive representation of all SGX data structures as several are only consumed by ENCLU (userspace), e.g. REPORT and KEYREQUEST, while others are only consumed by future features, e.g. RDINFO. Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/include/asm/sgx_arch.h | 329 ++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) diff --git a/arch/x86/include/asm/sgx_arch.h b/arch/x86/include/asm/sgx_arch.h index 6cd572fa95fa..d4c57154e6e6 100644 --- a/arch/x86/include/asm/sgx_arch.h +++ b/arch/x86/include/asm/sgx_arch.h @@ -8,6 +8,7 @@ #ifndef _ASM_X86_SGX_ARCH_H #define _ASM_X86_SGX_ARCH_H +#include #include /** @@ -53,4 +54,332 @@ enum sgx_encls_leaves { SGX_EMODT = 0x0F, }; +#define SGX_MODULUS_SIZE 384 + +/** + * enum sgx_miscselect - additional information to an SSA frame + * %SGX_MISC_EXINFO: Report #PF or #GP to the SSA frame. + * + * Save State Area (SSA) is a stack inside the enclave used to store processor + * state when an exception or interrupt occurs. This enum defines additional + * information stored to an SSA frame. + */ +enum sgx_miscselect { + SGX_MISC_EXINFO = BIT(0), + SGX_MISC_RESERVED_MASK = GENMASK_ULL(63, 1) +}; + +#define SGX_SSA_GPRS_SIZE 182 +#define SGX_SSA_MISC_EXINFO_SIZE 16 + +/** + * enum sgx_attributes - the attributes field in &struct sgx_secs + * %SGX_ATTR_INIT: Enclave can be entered (is initialized). + * %SGX_ATTR_DEBUG: Allow ENCLS(EDBGRD) and ENCLS(EDBGWR). + * %SGX_ATTR_MODE64BIT: Tell that this a 64-bit enclave. + * %SGX_ATTR_PROVISIONKEY: Allow to use provisioning keys for remote + * attestation. + * %SGX_ATTR_EINITTOKENKEY: Allow to use token signing key that is used to + * sign cryptographic tokens that can be passed to + * EINIT as an authorization to run an enclave. + */ +enum sgx_attribute { + SGX_ATTR_INIT = BIT(0), + SGX_ATTR_DEBUG = BIT(1), + SGX_ATTR_MODE64BIT = BIT(2), + SGX_ATTR_PROVISIONKEY = BIT(4), + SGX_ATTR_EINITTOKENKEY = BIT(5), + SGX_ATTR_RESERVED_MASK = BIT_ULL(3) | GENMASK_ULL(63, 6) +}; + +#define SGX_SECS_RESERVED1_SIZE 24 +#define SGX_SECS_RESERVED2_SIZE 32 +#define SGX_SECS_RESERVED3_SIZE 96 +#define SGX_SECS_RESERVED4_SIZE 3836 + +/** + * struct sgx_secs - SGX Enclave Control Structure (SECS) + * @size: size of the address space + * @base: base address of the address space + * @ssa_frame_size: size of an SSA frame + * @miscselect: additional information stored to an SSA frame + * @attributes: attributes for enclave + * @xfrm: XSave-Feature Request Mask (subset of XCR0) + * @mrenclave: SHA256-hash of the enclave contents + * @mrsigner: SHA256-hash of the public key used to sign the SIGSTRUCT + * @isvprodid: a user-defined value that is used in key derivation + * @isvsvn: a user-defined value that is used in key derivation + * + * SGX Enclave Control Structure (SECS) is a special enclave page that is not + * visible in the address space. In fact, this structure defines the address + * range and other global attributes for the enclave and it is the first EPC + * page created for any enclave. It is moved from a temporary buffer to an EPC + * by the means of ENCLS(ECREATE) leaf. + */ +struct sgx_secs { + u64 size; + u64 base; + u32 ssa_frame_size; + u32 miscselect; + u8 reserved1[SGX_SECS_RESERVED1_SIZE]; + u64 attributes; + u64 xfrm; + u32 mrenclave[8]; + u8 reserved2[SGX_SECS_RESERVED2_SIZE]; + u32 mrsigner[8]; + u8 reserved3[SGX_SECS_RESERVED3_SIZE]; + u16 isvprodid; + u16 isvsvn; + u8 reserved4[SGX_SECS_RESERVED4_SIZE]; +} __packed; + +/** + * enum sgx_tcs_flags - execution flags for TCS + * %SGX_TCS_DBGOPTIN: If enabled allows single-stepping and breakpoints + * inside an enclave. It is cleared by EADD but can + * be set later with EDBGWR. + */ +enum sgx_tcs_flags { + SGX_TCS_DBGOPTIN = 0x01, + SGX_TCS_RESERVED_MASK = GENMASK_ULL(63, 1) +}; + +#define SGX_TCS_RESERVED_SIZE 4024 + +/** + * struct sgx_tcs - Thread Control Structure (TCS) + * @state: used to mark an entered TCS + * @flags: execution flags (cleared by EADD) + * @ssa_offset: SSA stack offset relative to the enclave base + * @ssa_index: the current SSA frame index (cleard by EADD) + * @nr_ssa_frames: the number of frame in the SSA stack + * @entry_offset: entry point offset relative to the enclave base + * @exit_addr: address outside the enclave to exit on an exception or + * interrupt + * @fs_offset: offset relative to the enclave base to become FS + * segment inside the enclave + * @gs_offset: offset relative to the enclave base to become GS + * segment inside the enclave + * @fs_limit: size to become a new FS-limit (only 32-bit enclaves) + * @gs_limit: size to become a new GS-limit (only 32-bit enclaves) + * + * Thread Control Structure (TCS) is an enclave page visible in its address + * space that defines an entry point inside the enclave. A thread enters inside + * an enclave by supplying address of TCS to ENCLU(EENTER). A TCS can be entered + * by only one thread at a time. + */ +struct sgx_tcs { + u64 state; + u64 flags; + u64 ssa_offset; + u32 ssa_index; + u32 nr_ssa_frames; + u64 entry_offset; + u64 exit_addr; + u64 fs_offset; + u64 gs_offset; + u32 fs_limit; + u32 gs_limit; + u8 reserved[SGX_TCS_RESERVED_SIZE]; +} __packed; + +/** + * struct sgx_pageinfo - an enclave page descriptor + * @addr: address of the enclave page + * @contents: pointer to the page contents + * @metadata: pointer either to a SECINFO or PCMD instance + * @secs: address of the SECS page + */ +struct sgx_pageinfo { + u64 addr; + u64 contents; + u64 metadata; + u64 secs; +} __packed __aligned(32); + + +/** + * enum sgx_page_type - bits in the SECINFO flags defining the page type + * %SGX_PAGE_TYPE_SECS: a SECS page + * %SGX_PAGE_TYPE_TCS: a TCS page + * %SGX_PAGE_TYPE_REG: a regular page + * %SGX_PAGE_TYPE_VA: a VA page + * %SGX_PAGE_TYPE_TRIM: a page in trimmed state + */ +enum sgx_page_type { + SGX_PAGE_TYPE_SECS = 0, + SGX_PAGE_TYPE_TCS = 1, + SGX_PAGE_TYPE_REG = 2, + SGX_PAGE_TYPE_VA = 3, + SGX_PAGE_TYPE_TRIM = 4, + SGX_PAGE_TYPE_MASK = GENMASK(7, 0) +}; + +/** + * enum sgx_secinfo_flags - the flags field in &struct sgx_secinfo + * %SGX_SECINFO_R: allow read + * %SGX_SECINFO_W: allow write + * %SGX_SECINFO_X: allow execution + * %SGX_SECINFO_SECS: a SECS page + * %SGX_SECINFO_TCS: a TCS page + * %SGX_SECINFO_REG: a regular page + * %SGX_SECINFO_VA: a VA page + * %SGX_SECINFO_TRIM: a page in trimmed state + */ +enum sgx_secinfo_flags { + SGX_SECINFO_R = BIT(0), + SGX_SECINFO_W = BIT(1), + SGX_SECINFO_X = BIT(2), + SGX_SECINFO_PERMISSION_MASK = GENMASK_ULL(2, 0), + SGX_SECINFO_SECS = (SGX_PAGE_TYPE_SECS << 8), + SGX_SECINFO_TCS = (SGX_PAGE_TYPE_TCS << 8), + SGX_SECINFO_REG = (SGX_PAGE_TYPE_REG << 8), + SGX_SECINFO_VA = (SGX_PAGE_TYPE_VA << 8), + SGX_SECINFO_TRIM = (SGX_PAGE_TYPE_TRIM << 8), + SGX_SECINFO_PAGE_TYPE_MASK = (SGX_PAGE_TYPE_MASK << 8), + SGX_SECINFO_RESERVED_MASK = ~(SGX_SECINFO_PERMISSION_MASK | + SGX_SECINFO_PAGE_TYPE_MASK) +}; + +#define SGX_SECINFO_RESERVED_SIZE 56 + +/** + * struct sgx_secinfo - describes attributes of an EPC page + * @flags: permissions and type + * + * Used together with ENCLS leaves that add or modify an EPC page to an + * enclave to define page permissions and type. + */ +struct sgx_secinfo { + u64 flags; + u8 reserved[SGX_SECINFO_RESERVED_SIZE]; +} __packed __aligned(64); + +#define SGX_PCMD_RESERVED_SIZE 40 + +/** + * struct sgx_pcmd - Paging Crypto Metadata (PCMD) + * @enclave_id: enclave identifier + * @mac: MAC over PCMD, page contents and isvsvn + * + * PCMD is stored for every swapped page to the regular memory. When ELDU loads + * the page back it recalculates the MAC by using a isvsvn number stored in a + * VA page. Together these two structures bring integrity and rollback + * protection. + */ +struct sgx_pcmd { + struct sgx_secinfo secinfo; + u64 enclave_id; + u8 reserved[SGX_PCMD_RESERVED_SIZE]; + u8 mac[16]; +} __packed __aligned(128); + +#define SGX_SIGSTRUCT_RESERVED1_SIZE 84 +#define SGX_SIGSTRUCT_RESERVED2_SIZE 20 +#define SGX_SIGSTRUCT_RESERVED3_SIZE 32 +#define SGX_SIGSTRUCT_RESERVED4_SIZE 12 + +/** + * struct sgx_sigstruct - an enclave signature + * @header1: a constant byte string + * @vendor: must be either 0x0000 or 0x8086 + * @date: YYYYMMDD in BCD + * @header2: a costant byte string + * @application: an application defined value + * @modulus: the modulus of the public key + * @exponent: the exponent of the public key + * @signature: the signature calculated over the fields except modulus, + * exponent, signature, reserved4, q1 and q2 + * @miscselect: additional information stored to an SSA frame + * @misc_mask: required miscselect in SECS + * @attributes: attributes for enclave + * @xfrm: XSave-Feature Request Mask (subset of XCR0) + * @attributes_mask: required attributes in SECS + * @xfrm_mask: required XFRM in SECS + * @mrenclave: SHA256-hash of the enclave contents + * @isvprodid: a user-defined value that is used in key derivation + * @isvsvn: a user-defined value that is used in key derivation + * @q1: a value used in RSA signature verification + * @q2: a value used in RSA signature verification + */ +struct sgx_sigstruct { + u64 header1[2]; + u32 vendor; + u32 date; + u64 header2[2]; + u32 application; + u8 reserved1[SGX_SIGSTRUCT_RESERVED1_SIZE]; + u8 modulus[SGX_MODULUS_SIZE]; + u32 exponent; + u8 signature[SGX_MODULUS_SIZE]; + u32 miscselect; + u32 misc_mask; + u8 reserved2[SGX_SIGSTRUCT_RESERVED2_SIZE]; + u64 attributes; + u64 xfrm; + u64 attributes_mask; + u64 xfrm_mask; + u8 mrenclave[32]; + u8 reserved3[SGX_SIGSTRUCT_RESERVED3_SIZE]; + u16 isvprodid; + u16 isvsvn; + u8 reserved4[SGX_SIGSTRUCT_RESERVED4_SIZE]; + u8 q1[SGX_MODULUS_SIZE]; + u8 q2[SGX_MODULUS_SIZE]; +} __packed __aligned(4096); + +#define SGX_EINITTOKEN_RESERVED1_SIZE 11 +#define SGX_EINITTOKEN_RESERVED2_SIZE 32 +#define SGX_EINITTOKEN_RESERVED3_SIZE 32 +#define SGX_EINITTOKEN_RESERVED4_SIZE 24 + +/** + * struct sgx_einittoken - a token permitting to launch an enclave + * @valid: one if valid and zero if invalid + * @attributes: attributes for enclave + * @xfrm: XSave-Feature Request Mask (subset of XCR0) + * @mrenclave: SHA256-hash of the enclave contents + * @mrsigner: SHA256-hash of the public key used to sign the + * SIGSTRUCT + * @le_cpusvn: a value that reflects the SGX implementation + * running in in the CPU + * @le_isvprodid: a user-defined value that is used in key + * derivation + * @le_isvsvn: a user-defined value that is used in key + * derivation + * @le_keyed_miscselect: LE's miscselect masked with the token keys + * miscselect + * @le_keyed_attributes: LE's attributes masked with the token keys + * attributes + * @le_keyed_xfrm: LE's XFRM masked with the token keys xfrm + * @salt: random salt for wear-out protection + * @mac: CMAC over the preceding fields + * + * An enclave with EINITTOKENKEY attribute can access a key with the same name + * by using ENCLS(EGETKEY) and use this to sign cryptographic tokens that can + * be passed to ENCLS(EINIT) to permit the launch of other enclaves. This is + * the only viable way to launch enclaves if IA32_SGXLEPUBKEYHASHn MSRs are + * locked assuming that there is a Launch Enclave (LE) available that can be + * used for generating these tokens. + */ +struct sgx_einittoken { + u32 valid; + u32 reserved1[SGX_EINITTOKEN_RESERVED1_SIZE]; + u64 attributes; + u64 xfrm; + u8 mrenclave[32]; + u8 reserved2[SGX_EINITTOKEN_RESERVED2_SIZE]; + u8 mrsigner[32]; + u8 reserved3[SGX_EINITTOKEN_RESERVED3_SIZE]; + u8 le_cpusvn[16]; + u16 le_isvprodid; + u16 le_isvsvn; + u8 reserved4[SGX_EINITTOKEN_RESERVED4_SIZE]; + u32 le_keyed_miscselect; + u64 le_keyed_attributes; + u64 le_keyed_xfrm; + u8 salt[32]; + u8 mac[16]; +} __packed __aligned(512); + #endif /* _ASM_X86_SGX_ARCH_H */ From patchwork Fri Dec 21 23:11:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741107 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 BB925161F for ; Fri, 21 Dec 2018 23:13:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ABE4028558 for ; Fri, 21 Dec 2018 23:13:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9E7F42861C; Fri, 21 Dec 2018 23:13:59 +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 4A65328558 for ; Fri, 21 Dec 2018 23:13:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392206AbeLUXN7 (ORCPT ); Fri, 21 Dec 2018 18:13:59 -0500 Received: from mga01.intel.com ([192.55.52.88]:11643 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390789AbeLUXN7 (ORCPT ); Fri, 21 Dec 2018 18:13:59 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:13:58 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338426" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:13:50 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 12/25] x86/sgx: Add definitions for SGX's CPUID leaf and variable sub-leafs Date: Sat, 22 Dec 2018 01:11:41 +0200 Message-Id: <20181221231154.6120-13-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 SGX defines its own CPUID leaf, 0x12, along with a variable number of sub-leafs. Sub-leafs 0 and 1 are always available if SGX is supported and enumerate various SGX features, e.g. instruction sets and enclave capabilities. Sub-leafs 2+ are variable, both in their existence and in what they enumerate. Bits 3:0 of EAX report the sub-leaf type, with the remaining bits in EAX, EBX, ECX and EDX being type-specific. Currently, the only known sub-leaf type enumerates an EPC section. An EPC section is simply a range of EPC memory available to software. The "list" of varaible SGX sub-leafs is NULL-terminated, i.e. software is expected to query CPUID until an invalid sub-leaf is encountered. Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/include/asm/sgx_arch.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/x86/include/asm/sgx_arch.h b/arch/x86/include/asm/sgx_arch.h index d4c57154e6e6..188243e3eee1 100644 --- a/arch/x86/include/asm/sgx_arch.h +++ b/arch/x86/include/asm/sgx_arch.h @@ -11,6 +11,21 @@ #include #include +#define SGX_CPUID 0x12 +#define SGX_CPUID_FIRST_VARIABLE_SUB_LEAF 2 + +/** + * enum sgx_sub_leaf_types - SGX CPUID variable sub-leaf types + * %SGX_CPUID_SUB_LEAF_INVALID: Indicates this sub-leaf is invalid. + * %SGX_CPUID_SUB_LEAF_EPC_SECTION: Sub-leaf enumerates an EPC section. + * %SGX_CPUID_SUB_LEAF_TYPE_MASK: Mask for bits containing the type. + */ +enum sgx_sub_leaf_types { + SGX_CPUID_SUB_LEAF_INVALID = 0x0, + SGX_CPUID_SUB_LEAF_EPC_SECTION = 0x1, + SGX_CPUID_SUB_LEAF_TYPE_MASK = GENMASK(3, 0), +}; + /** * enum sgx_encls_leaves - ENCLS leaf functions * %SGX_ECREATE: Create an enclave. From patchwork Fri Dec 21 23:11:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741109 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 3CC9A13B5 for ; Fri, 21 Dec 2018 23:14:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2DA8328618 for ; Fri, 21 Dec 2018 23:14:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 21121286B6; Fri, 21 Dec 2018 23:14: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 0175828618 for ; Fri, 21 Dec 2018 23:14:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392207AbeLUXOJ (ORCPT ); Fri, 21 Dec 2018 18:14:09 -0500 Received: from mga02.intel.com ([134.134.136.20]:34346 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390789AbeLUXOJ (ORCPT ); Fri, 21 Dec 2018 18:14:09 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:14:08 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338475" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:14:00 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 13/25] x86/sgx: Add wrappers for ENCLS leaf functions Date: Sat, 22 Dec 2018 01:11:42 +0200 Message-Id: <20181221231154.6120-14-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 ENCLS is an umbrella instruction for a variety of cpl0 SGX functions. The ENCLS function that is executed is specified in EAX, with each function potentially having more leaf-specific operands beyond EAX. ENCLS introduces its own (positive value) error codes that (some) leafs use to return failure information in EAX. Leafs that return an error code also modify RFLAGS. And finally, ENCLS generates ENCLS-specific non-fatal #GPs and #PFs, i.e. a bug-free kernel may encounter faults on ENCLS that must be handled gracefully. Because of the complexity involved in encoding ENCLS and handling its assortment of failure paths, executing any given leaf is not a simple matter of emitting ENCLS. To enable adding support for ENCLS leafs with minimal fuss, add a two-layer macro system along with an encoding scheme to allow wrappers to return trap numbers along ENCLS-specific error codes. The bottom layer of the macro system splits between the leafs that return an error code and those that do not. The second layer generates the correct input/output annotations based on the number of operands for each leaf function. Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/include/asm/sgx.h | 252 +++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 arch/x86/include/asm/sgx.h diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h new file mode 100644 index 000000000000..3d5ba1d23dfb --- /dev/null +++ b/arch/x86/include/asm/sgx.h @@ -0,0 +1,252 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +#ifndef _ASM_X86_SGX_H +#define _ASM_X86_SGX_H + +#include +#include + +/** + * ENCLS_FAULT_FLAG - flag signifying an ENCLS return code is a trapnr + * + * ENCLS has its own (positive value) error codes and also generates + * ENCLS specific #GP and #PF faults. And the ENCLS values get munged + * with system error codes as everything percolates back up the stack. + * Unfortunately (for us), we need to precisely identify each unique + * error code, e.g. the action taken if EWB fails varies based on the + * type of fault and on the exact SGX error code, i.e. we can't simply + * convert all faults to -EFAULT. + * + * To make all three error types coexist, we set bit 30 to identify an + * ENCLS fault. Bit 31 (technically bits N:31) is used to differentiate + * between positive (faults and SGX error codes) and negative (system + * error codes) values. + */ +#define ENCLS_FAULT_FLAG 0x40000000 + +/** + * Check for a fault by looking for a postive value with the fault + * flag set. The postive value check is needed to filter out system + * error codes since negative values will have all higher order bits + * set, including ENCLS_FAULT_FLAG. + */ +#define IS_ENCLS_FAULT(r) ((int)(r) > 0 && ((r) & ENCLS_FAULT_FLAG)) + +/** + * Retrieve the encoded trapnr from the specified return code. + */ +#define ENCLS_TRAPNR(r) ((r) & ~ENCLS_FAULT_FLAG) + +/** + * encls_to_err - translate an ENCLS fault or SGX code into a system error code + * @ret: positive value return code + * + * Translate a postive return code, e.g. from ENCLS, into a system error + * code. Primarily used by functions that cannot return a non-negative + * error code, e.g. kernel callbacks. + * + * Return: + * 0 on success, + * -errno on failure + */ +static inline int encls_to_err(int ret) +{ + if (IS_ENCLS_FAULT(ret)) + return -EFAULT; + + switch (ret) { + case SGX_UNMASKED_EVENT: + return -EINTR; + case SGX_INVALID_SIG_STRUCT: + case SGX_INVALID_ATTRIBUTE: + case SGX_INVALID_MEASUREMENT: + case SGX_INVALID_EINITTOKEN: + case SGX_INVALID_CPUSVN: + case SGX_INVALID_ISVSVN: + case SGX_INVALID_KEYNAME: + return -EINVAL; + case SGX_ENCLAVE_ACT: + case SGX_CHILD_PRESENT: + case SGX_ENTRYEPOCH_LOCKED: + case SGX_PREV_TRK_INCMPL: + case SGX_PAGE_NOT_MODIFIABLE: + case SGX_PAGE_NOT_DEBUGGABLE: + return -EBUSY; + default: + return -EIO; + }; +} + +/** + * __encls_ret_N - encode an ENCLS leaf that returns an error code in EAX + * @rax: leaf number + * @inputs: asm inputs for the leaf + * + * Emit assembly for an ENCLS leaf that returns an error code, e.g. EREMOVE. + * And because SGX isn't complex enough as it is, leafs that return an error + * code also modify flags. + * + * Return: + * 0 on success, + * SGX error code on failure + */ +#define __encls_ret_N(rax, inputs...) \ + ({ \ + int ret; \ + asm volatile( \ + "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: orl $"__stringify(ENCLS_FAULT_FLAG)",%%eax\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE_FAULT(1b, 3b) \ + : "=a"(ret) \ + : "a"(rax), inputs \ + : "memory", "cc"); \ + ret; \ + }) + +#define __encls_ret_1(rax, rcx) \ + ({ \ + __encls_ret_N(rax, "c"(rcx)); \ + }) + +#define __encls_ret_2(rax, rbx, rcx) \ + ({ \ + __encls_ret_N(rax, "b"(rbx), "c"(rcx)); \ + }) + +#define __encls_ret_3(rax, rbx, rcx, rdx) \ + ({ \ + __encls_ret_N(rax, "b"(rbx), "c"(rcx), "d"(rdx)); \ + }) + +/** + * __encls_N - encode an ENCLS leaf that doesn't return an error code + * @rax: leaf number + * @rbx_out: optional output variable + * @inputs: asm inputs for the leaf + * + * Emit assembly for an ENCLS leaf that does not return an error code, + * e.g. ECREATE. Leaves without error codes either succeed or fault. + * @rbx_out is an optional parameter for use by EDGBRD, which returns + * the the requested value in RBX. + * + * Return: + * 0 on success, + * trapnr with ENCLS_FAULT_FLAG set on fault + */ +#define __encls_N(rax, rbx_out, inputs...) \ + ({ \ + int ret; \ + asm volatile( \ + "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ + " xor %%eax,%%eax;\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: orl $"__stringify(ENCLS_FAULT_FLAG)",%%eax\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE_FAULT(1b, 3b) \ + : "=a"(ret), "=b"(rbx_out) \ + : "a"(rax), inputs \ + : "memory"); \ + ret; \ + }) + +#define __encls_2(rax, rbx, rcx) \ + ({ \ + unsigned long ign_rbx_out; \ + __encls_N(rax, ign_rbx_out, "b"(rbx), "c"(rcx)); \ + }) + +#define __encls_1_1(rax, data, rcx) \ + ({ \ + unsigned long rbx_out; \ + int ret = __encls_N(rax, rbx_out, "c"(rcx)); \ + if (!ret) \ + data = rbx_out; \ + ret; \ + }) + +static inline int __ecreate(struct sgx_pageinfo *pginfo, void *secs) +{ + return __encls_2(SGX_ECREATE, pginfo, secs); +} + +static inline int __eextend(void *secs, void *addr) +{ + return __encls_2(SGX_EEXTEND, secs, addr); +} + +static inline int __eadd(struct sgx_pageinfo *pginfo, void *addr) +{ + return __encls_2(SGX_EADD, pginfo, addr); +} + +static inline int __einit(void *sigstruct, struct sgx_einittoken *einittoken, + void *secs) +{ + return __encls_ret_3(SGX_EINIT, sigstruct, secs, einittoken); +} + +static inline int __eremove(void *addr) +{ + return __encls_ret_1(SGX_EREMOVE, addr); +} + +static inline int __edbgwr(void *addr, unsigned long *data) +{ + return __encls_2(SGX_EDGBWR, *data, addr); +} + +static inline int __edbgrd(void *addr, unsigned long *data) +{ + return __encls_1_1(SGX_EDGBRD, *data, addr); +} + +static inline int __etrack(void *addr) +{ + return __encls_ret_1(SGX_ETRACK, addr); +} + +static inline int __eldu(struct sgx_pageinfo *pginfo, void *addr, + void *va) +{ + return __encls_ret_3(SGX_ELDU, pginfo, addr, va); +} + +static inline int __eblock(void *addr) +{ + return __encls_ret_1(SGX_EBLOCK, addr); +} + +static inline int __epa(void *addr) +{ + unsigned long rbx = SGX_PAGE_TYPE_VA; + + return __encls_2(SGX_EPA, rbx, addr); +} + +static inline int __ewb(struct sgx_pageinfo *pginfo, void *addr, + void *va) +{ + return __encls_ret_3(SGX_EWB, pginfo, addr, va); +} + +static inline int __eaug(struct sgx_pageinfo *pginfo, void *addr) +{ + return __encls_2(SGX_EAUG, pginfo, addr); +} + +static inline int __emodpr(struct sgx_secinfo *secinfo, void *addr) +{ + return __encls_ret_2(SGX_EMODPR, secinfo, addr); +} + +static inline int __emodt(struct sgx_secinfo *secinfo, void *addr) +{ + return __encls_ret_2(SGX_EMODT, secinfo, addr); +} + +#endif /* _ASM_X86_SGX_H */ From patchwork Fri Dec 21 23:11:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741111 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 92BAC161F for ; Fri, 21 Dec 2018 23:14:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8260428618 for ; Fri, 21 Dec 2018 23:14:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 75E10286B6; Fri, 21 Dec 2018 23:14:18 +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 01ED328618 for ; Fri, 21 Dec 2018 23:14:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392208AbeLUXOR (ORCPT ); Fri, 21 Dec 2018 18:14:17 -0500 Received: from mga18.intel.com ([134.134.136.126]:25896 "EHLO mga18.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390789AbeLUXOR (ORCPT ); Fri, 21 Dec 2018 18:14:17 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:14:16 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338498" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:14:09 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 14/25] x86/sgx: Enumerate and track EPC sections Date: Sat, 22 Dec 2018 01:11:43 +0200 Message-Id: <20181221231154.6120-15-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Enumerate Enclave Page Cache (EPC) sections via CPUID and add the data structures necessary to track EPC pages so that they can be allocated, freed and managed. As a system may have multiple EPC sections, invoke CPUID on SGX sub-leafs until an invalid leaf is encountered. On NUMA systems, a node can have at most one bank. A bank can be at most part of two nodes. SGX supports both nodes with a single memory controller and also sub-cluster nodes with severals memory controllers on a single die. For simplicity, support a maximum of eight EPC sections. Current client hardware supports only a single section, while upcoming server hardware will support at most eight sections. Bounding the number of sections also allows the section ID to be embedded along with a page's offset in a single unsigned long, enabling easy retrieval of both the VA and PA for a given page. Signed-off-by: Sean Christopherson Co-developed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Co-developed-by: Suresh Siddha Signed-off-by: Suresh Siddha Co-developed-by: Serge Ayoun Signed-off-by: Serge Ayoun --- arch/x86/Kconfig | 17 ++++ arch/x86/include/asm/sgx.h | 54 +++++++++++ arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/sgx/Makefile | 1 + arch/x86/kernel/cpu/sgx/main.c | 148 +++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+) create mode 100644 arch/x86/kernel/cpu/sgx/Makefile create mode 100644 arch/x86/kernel/cpu/sgx/main.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 9d734f3c8234..4c3a325351ce 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1919,6 +1919,23 @@ config X86_INTEL_MEMORY_PROTECTION_KEYS If unsure, say y. +config INTEL_SGX_CORE + bool "Intel SGX core functionality" + depends on X86_64 && CPU_SUP_INTEL + help + Intel Software Guard eXtensions (SGX) CPU feature that allows ring 3 + applications to create enclaves: private regions of memory that are + architecturally protected from unauthorized access and/or modification. + + This option enables kernel recognition of SGX, high-level management + of the Enclave Page Cache (EPC), tracking and writing of SGX Launch + Enclave Hash MSRs, and allows for virtualization of SGX via KVM. By + itself, this option does not provide SGX support to userspace. + + For details, see Documentation/x86/intel_sgx.rst + + If unsure, say N. + config EFI bool "EFI runtime service support" depends on ACPI diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h index 3d5ba1d23dfb..a37bc3650253 100644 --- a/arch/x86/include/asm/sgx.h +++ b/arch/x86/include/asm/sgx.h @@ -2,9 +2,63 @@ #ifndef _ASM_X86_SGX_H #define _ASM_X86_SGX_H +#include +#include +#include +#include +#include #include #include +struct sgx_epc_page { + unsigned long desc; + struct list_head list; +}; + +/** + * struct sgx_epc_section + * + * The firmware can define multiple chunks of EPC to the different areas of the + * physical memory e.g. for memory areas of the each node. This structure is + * used to store EPC pages for one EPC section and virtual memory area where + * the pages have been mapped. + */ +struct sgx_epc_section { + unsigned long pa; + void *va; + struct list_head page_list; + unsigned long free_cnt; + spinlock_t lock; +}; + +#define SGX_MAX_EPC_SECTIONS 8 + +extern struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; + +/** + * enum sgx_epc_page_desc - bits and masks for an EPC page's descriptor + * %SGX_EPC_SECTION_MASK: SGX allows to have multiple EPC sections in the + * physical memory. The existing and near-future + * hardware defines at most eight sections, hence + * three bits to hold a section. + */ +enum sgx_epc_page_desc { + SGX_EPC_SECTION_MASK = GENMASK_ULL(3, 0), + /* bits 12-63 are reserved for the physical page address of the page */ +}; + +static inline struct sgx_epc_section *sgx_epc_section(struct sgx_epc_page *page) +{ + return &sgx_epc_sections[page->desc & SGX_EPC_SECTION_MASK]; +} + +static inline void *sgx_epc_addr(struct sgx_epc_page *page) +{ + struct sgx_epc_section *section = sgx_epc_section(page); + + return section->va + (page->desc & PAGE_MASK) - section->pa; +} + /** * ENCLS_FAULT_FLAG - flag signifying an ENCLS return code is a trapnr * diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 1f5d2291c31e..b1a25ad4f780 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o obj-$(CONFIG_INTEL_RDT) += intel_rdt.o intel_rdt_rdtgroup.o intel_rdt_monitor.o obj-$(CONFIG_INTEL_RDT) += intel_rdt_ctrlmondata.o intel_rdt_pseudo_lock.o CFLAGS_intel_rdt_pseudo_lock.o = -I$(src) +obj-$(CONFIG_INTEL_SGX_CORE) += sgx/ obj-$(CONFIG_X86_MCE) += mcheck/ obj-$(CONFIG_MTRR) += mtrr/ diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makefile new file mode 100644 index 000000000000..b666967fd570 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/Makefile @@ -0,0 +1 @@ +obj-y += main.o diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c new file mode 100644 index 000000000000..cd5090ca00e5 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-17 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include + +struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; +EXPORT_SYMBOL_GPL(sgx_epc_sections); + +static int sgx_nr_epc_sections; + +static void sgx_section_put_page(struct sgx_epc_section *section, + struct sgx_epc_page *page) +{ + list_add_tail(&page->list, §ion->page_list); + section->free_cnt++; +} + +static __init void sgx_free_epc_section(struct sgx_epc_section *section) +{ + struct sgx_epc_page *page; + + while (!list_empty(§ion->page_list)) { + page = list_first_entry(§ion->page_list, + struct sgx_epc_page, list); + list_del(&page->list); + kfree(page); + } + memunmap(section->va); +} + +static __init int sgx_init_epc_section(u64 addr, u64 size, unsigned long index, + struct sgx_epc_section *section) +{ + unsigned long nr_pages = size >> PAGE_SHIFT; + struct sgx_epc_page *page; + unsigned long i; + + section->va = memremap(addr, size, MEMREMAP_WB); + if (!section->va) + return -ENOMEM; + + section->pa = addr; + spin_lock_init(§ion->lock); + INIT_LIST_HEAD(§ion->page_list); + + for (i = 0; i < nr_pages; i++) { + page = kzalloc(sizeof(*page), GFP_KERNEL); + if (!page) + goto out; + page->desc = (addr + (i << PAGE_SHIFT)) | index; + sgx_section_put_page(section, page); + } + + return 0; +out: + sgx_free_epc_section(section); + return -ENOMEM; +} + +static __init void sgx_page_cache_teardown(void) +{ + int i; + + for (i = 0; i < sgx_nr_epc_sections; i++) + sgx_free_epc_section(&sgx_epc_sections[i]); +} + +/** + * A section metric is concatenated in a way that @low bits 12-31 define the + * bits 12-31 of the metric and @high bits 0-19 define the bits 32-51 of the + * metric. + */ +static inline u64 sgx_calc_section_metric(u64 low, u64 high) +{ + return (low & GENMASK_ULL(31, 12)) + + ((high & GENMASK_ULL(19, 0)) << 32); +} + +static __init int sgx_page_cache_init(void) +{ + u32 eax, ebx, ecx, edx, type; + u64 pa, size; + int ret; + int i; + + BUILD_BUG_ON(SGX_MAX_EPC_SECTIONS > (SGX_EPC_SECTION_MASK + 1)); + + for (i = 0; i < (SGX_MAX_EPC_SECTIONS + 1); i++) { + cpuid_count(SGX_CPUID, i + SGX_CPUID_FIRST_VARIABLE_SUB_LEAF, + &eax, &ebx, &ecx, &edx); + + type = eax & SGX_CPUID_SUB_LEAF_TYPE_MASK; + if (type == SGX_CPUID_SUB_LEAF_INVALID) + break; + if (type != SGX_CPUID_SUB_LEAF_EPC_SECTION) { + pr_err_once("sgx: Unknown sub-leaf type: %u\n", type); + return -ENODEV; + } + if (i == SGX_MAX_EPC_SECTIONS) { + pr_warn("sgx: More than " + __stringify(SGX_MAX_EPC_SECTIONS) + " EPC sections\n"); + break; + } + + pa = sgx_calc_section_metric(eax, ebx); + size = sgx_calc_section_metric(ecx, edx); + pr_info("sgx: EPC section 0x%llx-0x%llx\n", pa, pa + size - 1); + + ret = sgx_init_epc_section(pa, size, i, &sgx_epc_sections[i]); + if (ret) { + sgx_page_cache_teardown(); + return ret; + } + + sgx_nr_epc_sections++; + } + + if (!sgx_nr_epc_sections) { + pr_err("sgx: There are zero EPC sections.\n"); + return -ENODEV; + } + + return 0; +} + +static __init int sgx_init(void) +{ + int ret; + + if (!boot_cpu_has(X86_FEATURE_SGX)) + return false; + + ret = sgx_page_cache_init(); + if (ret) + return ret; + + return 0; +} + +arch_initcall(sgx_init); From patchwork Fri Dec 21 23:11:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741113 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 30216161F for ; Fri, 21 Dec 2018 23:14:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2080D28618 for ; Fri, 21 Dec 2018 23:14:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 10564286B6; Fri, 21 Dec 2018 23:14:27 +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 00E1928618 for ; Fri, 21 Dec 2018 23:14:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2403906AbeLUXOZ (ORCPT ); Fri, 21 Dec 2018 18:14:25 -0500 Received: from mga14.intel.com ([192.55.52.115]:13668 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXOZ (ORCPT ); Fri, 21 Dec 2018 18:14:25 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:14:25 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338514" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:14:18 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 15/25] x86/sgx: Add functions to allocate and free EPC pages Date: Sat, 22 Dec 2018 01:11:44 +0200 Message-Id: <20181221231154.6120-16-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 At this time there is no support for reclaiming pages prior to the owner explicitly freeing the page. As for freeing pages, because freeing a page is expected to succeed in the vast majority of cases and because most call sites will not be equipped to handle failure, provide a variant for freeing a page that warns on failure, e.g. due to ENCLS[EREMOVE] failing. Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/include/asm/sgx.h | 4 ++ arch/x86/kernel/cpu/sgx/main.c | 88 ++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h index a37bc3650253..40caaac58747 100644 --- a/arch/x86/include/asm/sgx.h +++ b/arch/x86/include/asm/sgx.h @@ -303,4 +303,8 @@ static inline int __emodt(struct sgx_secinfo *secinfo, void *addr) return __encls_ret_2(SGX_EMODT, secinfo, 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); + #endif /* _ASM_X86_SGX_H */ diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c index cd5090ca00e5..0c74dcace908 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -22,6 +22,94 @@ static void sgx_section_put_page(struct sgx_epc_section *section, section->free_cnt++; } +static struct sgx_epc_page *sgx_section_get_page( + struct sgx_epc_section *section) +{ + struct sgx_epc_page *page; + + if (!section->free_cnt) + return NULL; + + page = list_first_entry(§ion->page_list, + struct sgx_epc_page, list); + list_del_init(&page->list); + section->free_cnt--; + return page; +} + +/** + * sgx_alloc_page - Allocate an EPC page + * + * Try to grab a page from the free EPC page list. + * + * Return: + * a pointer to a &struct sgx_epc_page instance, + * -errno on error + */ +struct sgx_epc_page *sgx_alloc_page(void) +{ + struct sgx_epc_section *section; + struct sgx_epc_page *page; + int i; + + for (i = 0; i < sgx_nr_epc_sections; i++) { + section = &sgx_epc_sections[i]; + spin_lock(§ion->lock); + page = sgx_section_get_page(section); + spin_unlock(§ion->lock); + + if (page) + return page; + } + + return ERR_PTR(-ENOMEM); +} +EXPORT_SYMBOL_GPL(sgx_alloc_page); + +/** + * __sgx_free_page - Free an EPC page + * @page: pointer a previously allocated EPC page + * + * EREMOVE an EPC page and insert it back to the list of free pages. + * + * Return: + * 0 on success + * SGX error code if EREMOVE fails + */ +int __sgx_free_page(struct sgx_epc_page *page) +{ + struct sgx_epc_section *section = sgx_epc_section(page); + int ret; + + ret = __eremove(sgx_epc_addr(page)); + if (ret) + return ret; + + spin_lock(§ion->lock); + sgx_section_put_page(section, page); + spin_unlock(§ion->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(__sgx_free_page); + +/** + * sgx_free_page - Free an EPC page and WARN on failure + * @page: pointer to a previously allocated EPC page + * + * EREMOVE an EPC page and insert it back to the list of free pages, and WARN + * if EREMOVE fails. For use when the call site cannot (or chooses not to) + * handle failure, i.e. the page is leaked on failure. + */ +void sgx_free_page(struct sgx_epc_page *page) +{ + int ret; + + ret = __sgx_free_page(page); + WARN(ret > 0, "sgx: EREMOVE returned %d (0x%x)", ret, ret); +} +EXPORT_SYMBOL_GPL(sgx_free_page); + static __init void sgx_free_epc_section(struct sgx_epc_section *section) { struct sgx_epc_page *page; From patchwork Fri Dec 21 23:11:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741115 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 87F7C13B5 for ; Fri, 21 Dec 2018 23:14:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7537F28618 for ; Fri, 21 Dec 2018 23:14:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 65CE4286B6; Fri, 21 Dec 2018 23:14:35 +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 5F49928618 for ; Fri, 21 Dec 2018 23:14:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2403907AbeLUXOe (ORCPT ); Fri, 21 Dec 2018 18:14:34 -0500 Received: from mga01.intel.com ([192.55.52.88]:11701 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXOe (ORCPT ); Fri, 21 Dec 2018 18:14:34 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:14:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338529" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:14:27 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 16/25] x86/sgx: Add sgx_einit() for initializing enclaves Date: Sat, 22 Dec 2018 01:11:45 +0200 Message-Id: <20181221231154.6120-17-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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/sgx/main.c | 51 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h index 40caaac58747..ad4a8ea57bd5 100644 --- a/arch/x86/include/asm/sgx.h +++ b/arch/x86/include/asm/sgx.h @@ -306,5 +306,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/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c index 0c74dcace908..d10cd0ceb96e 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.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); + static void sgx_section_put_page(struct sgx_epc_section *section, struct sgx_epc_page *page) { @@ -110,6 +113,54 @@ 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) { struct sgx_epc_page *page; From patchwork Fri Dec 21 23:11:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741117 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 8F0FF13B5 for ; Fri, 21 Dec 2018 23:14:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7FAAF286B6 for ; Fri, 21 Dec 2018 23:14:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 739D3286BC; Fri, 21 Dec 2018 23:14:43 +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 31A0F286B6 for ; Fri, 21 Dec 2018 23:14:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732065AbeLUXOn (ORCPT ); Fri, 21 Dec 2018 18:14:43 -0500 Received: from mga11.intel.com ([192.55.52.93]:21194 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXOm (ORCPT ); Fri, 21 Dec 2018 18:14:42 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:14:42 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338544" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:14:35 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 17/25] x86/mpx: pass @mm to kernel_managing_mpx_tables() in mpx_notify_unmap() Date: Sat, 22 Dec 2018 01:11:46 +0200 Message-Id: <20181221231154.6120-18-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 If @mm is not the same as current->mm, mpx_notify_unmap() will yield invalid results and at worst will lead to a crash if it gets called by a kthread. The function in question gets called through do_munmap(). ATM kernel does not use that function on x86 in such context that mm and current->mm would differ With the addition of SGX driver code, do_munmap() is called from workqueue thread. This commit changes the parameter passed to @mm so that this will yield the correct results and not crash as reference to current->mm would be NULL in a kthread context. Cc: Dave Hansen Fixes: 1de4fa14ee25 ("x86, mpx: Cleanup unused bound tables") Signed-off-by: Jarkko Sakkinen --- arch/x86/mm/mpx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index 2385538e8065..15fb62657ee9 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -882,7 +882,7 @@ static int mpx_unmap_tables(struct mm_struct *mm, * necessary, and the 'vma' is the first vma in this range (start -> end). */ void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long start, unsigned long end) + unsigned long start, unsigned long end) { int ret; @@ -890,7 +890,7 @@ void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma, * Refuse to do anything unless userspace has asked * the kernel to help manage the bounds tables, */ - if (!kernel_managing_mpx_tables(current->mm)) + if (!kernel_managing_mpx_tables(mm)) return; /* * This will look across the entire 'start -> end' range, From patchwork Fri Dec 21 23:11:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741119 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 B10EB161F for ; Fri, 21 Dec 2018 23:14:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9DF8F28618 for ; Fri, 21 Dec 2018 23:14:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9142E286B6; Fri, 21 Dec 2018 23:14:54 +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 533A628618 for ; Fri, 21 Dec 2018 23:14:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2403908AbeLUXOx (ORCPT ); Fri, 21 Dec 2018 18:14:53 -0500 Received: from mga11.intel.com ([192.55.52.93]:21206 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXOw (ORCPT ); Fri, 21 Dec 2018 18:14:52 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:14:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338558" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:14:44 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 18/25] x86/sgx: Add the Linux SGX Enclave Driver Date: Sat, 22 Dec 2018 01:11:47 +0200 Message-Id: <20181221231154.6120-19-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Intel Software Guard eXtensions (SGX) is a set of CPU instructions that can be used by applications to set aside private regions of code and data. The code outside the enclave is disallowed to access the memory inside the enclave by the CPU access control. This commit adds the Linux SGX Enclave Driver that provides an ioctl API to manage enclaves. The address range for an enclave, commonly referred as ELRANGE in the documentation (e.g. Intel SDM), is reserved with mmap() against /dev/sgx. After that a set ioctls is used to build the enclave to the ELRANGE. Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Co-developed-by: Serge Ayoun Signed-off-by: Serge Ayoun Co-developed-by: Shay Katz-zamir Signed-off-by: Shay Katz-zamir Co-developed-by: Suresh Siddha Signed-off-by: Suresh Siddha --- Documentation/ioctl/ioctl-number.txt | 1 + arch/x86/Kconfig | 27 +- arch/x86/include/uapi/asm/sgx.h | 59 ++ arch/x86/kernel/cpu/sgx/Makefile | 1 + arch/x86/kernel/cpu/sgx/driver/Kconfig | 20 + arch/x86/kernel/cpu/sgx/driver/Makefile | 2 + arch/x86/kernel/cpu/sgx/driver/driver.h | 170 +++++ arch/x86/kernel/cpu/sgx/driver/encl.c | 813 ++++++++++++++++++++++++ arch/x86/kernel/cpu/sgx/driver/ioctl.c | 230 +++++++ arch/x86/kernel/cpu/sgx/driver/main.c | 270 ++++++++ arch/x86/kernel/cpu/sgx/driver/pte.c | 56 ++ arch/x86/kernel/cpu/sgx/driver/vma.c | 43 ++ 12 files changed, 1689 insertions(+), 3 deletions(-) create mode 100644 arch/x86/include/uapi/asm/sgx.h create mode 100644 arch/x86/kernel/cpu/sgx/driver/Kconfig create mode 100644 arch/x86/kernel/cpu/sgx/driver/Makefile create mode 100644 arch/x86/kernel/cpu/sgx/driver/driver.h create mode 100644 arch/x86/kernel/cpu/sgx/driver/encl.c create mode 100644 arch/x86/kernel/cpu/sgx/driver/ioctl.c create mode 100644 arch/x86/kernel/cpu/sgx/driver/main.c create mode 100644 arch/x86/kernel/cpu/sgx/driver/pte.c create mode 100644 arch/x86/kernel/cpu/sgx/driver/vma.c diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index af6f6ba1fe80..0b01906c1307 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -311,6 +311,7 @@ Code Seq#(hex) Include File Comments 0xA3 90-9F linux/dtlk.h 0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem +0xA4 00-02 uapi/asm/sgx.h conflict! 0xAA 00-3F linux/uapi/linux/userfaultfd.h 0xAB 00-1F linux/nbd.h 0xAC 00-1F linux/raw.h diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4c3a325351ce..9673d74dc744 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1923,9 +1923,15 @@ config INTEL_SGX_CORE bool "Intel SGX core functionality" depends on X86_64 && CPU_SUP_INTEL help - Intel Software Guard eXtensions (SGX) CPU feature that allows ring 3 - applications to create enclaves: private regions of memory that are - architecturally protected from unauthorized access and/or modification. + Intel(R) SGX is a set of CPU instructions that can be used by + applications to set aside private regions of code and data. The code + outside the enclave is disallowed to access the memory inside the + enclave by the CPU access control. + + The firmware uses PRMRR registers to reserve an area of physical memory + called Enclave Page Cache (EPC). There is a hardware unit in the + processor called Memory Encryption Engine. The MEE encrypts and decrypts + the EPC pages as they enter and leave the processor package. This option enables kernel recognition of SGX, high-level management of the Enclave Page Cache (EPC), tracking and writing of SGX Launch @@ -1936,6 +1942,21 @@ config INTEL_SGX_CORE If unsure, say N. +config INTEL_SGX + tristate "Intel(R) SGX Driver" + depends on X86_64 && CPU_SUP_INTEL && INTEL_SGX_CORE + select MMU_NOTIFIER + select CRYPTO + select CRYPTO_SHA256 + help + This options enables the kernel SGX driver that allows to construct + enclaves to the process memory by using a device node (by default + /dev/sgx) and a set of ioctls. The driver requires that the MSRs + specifying the public key hash for the launch enclave are writable so + that Linux has the full control to run enclaves. + + For details, see Documentation/x86/intel_sgx.rst + config EFI bool "EFI runtime service support" depends on ACPI diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h new file mode 100644 index 000000000000..aadf9c76e360 --- /dev/null +++ b/arch/x86/include/uapi/asm/sgx.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/** + * Copyright(c) 2016-18 Intel Corporation. + */ +#ifndef _UAPI_ASM_X86_SGX_H +#define _UAPI_ASM_X86_SGX_H + +#include +#include + +#define SGX_MAGIC 0xA4 + +#define SGX_IOC_ENCLAVE_CREATE \ + _IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create) +#define SGX_IOC_ENCLAVE_ADD_PAGE \ + _IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page) +#define SGX_IOC_ENCLAVE_INIT \ + _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) + +/* IOCTL return values */ +#define SGX_POWER_LOST_ENCLAVE 0x40000000 + +/** + * struct sgx_enclave_create - parameter structure for the + * %SGX_IOC_ENCLAVE_CREATE ioctl + * @src: address for the SECS page data + */ +struct sgx_enclave_create { + __u64 src; +}; + +/** + * struct sgx_enclave_add_page - parameter structure for the + * %SGX_IOC_ENCLAVE_ADD_PAGE ioctl + * @addr: address within the ELRANGE + * @src: address for the page data + * @secinfo: address for the SECINFO data + * @mrmask: bitmask for the measured 256 byte chunks + */ +struct sgx_enclave_add_page { + __u64 addr; + __u64 src; + __u64 secinfo; + __u16 mrmask; +} __attribute__((__packed__)); + + +/** + * struct sgx_enclave_init - parameter structure for the + * %SGX_IOC_ENCLAVE_INIT ioctl + * @addr: address within the ELRANGE + * @sigstruct: address for the SIGSTRUCT data + */ +struct sgx_enclave_init { + __u64 addr; + __u64 sigstruct; +}; + +#endif /* _UAPI_ASM_X86_SGX_H */ diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makefile index b666967fd570..f29aeec34c8b 100644 --- a/arch/x86/kernel/cpu/sgx/Makefile +++ b/arch/x86/kernel/cpu/sgx/Makefile @@ -1 +1,2 @@ obj-y += main.o +obj-$(CONFIG_INTEL_SGX) += driver/ diff --git a/arch/x86/kernel/cpu/sgx/driver/Kconfig b/arch/x86/kernel/cpu/sgx/driver/Kconfig new file mode 100644 index 000000000000..7d22d44acce9 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/Kconfig @@ -0,0 +1,20 @@ +# +# Intel SGX +# + +config INTEL_SGX + tristate "Intel(R) SGX Driver" + depends on X86_64 && CPU_SUP_INTEL && INTEL_SGX_CORE + select MMU_NOTIFIER + select CRYPTO + select CRYPTO_SHA256 + help + Intel(R) SGX is a set of CPU instructions that can be used by + applications to set aside private regions of code and data. The code + outside the enclave is disallowed to access the memory inside the + enclave by the CPU access control. + + The firmware uses PRMRR registers to reserve an area of physical memory + called Enclave Page Cache (EPC). There is a hardware unit in the + processor called Memory Encryption Engine. The MEE encrypts and decrypts + the EPC pages as they enter and leave the processor package. diff --git a/arch/x86/kernel/cpu/sgx/driver/Makefile b/arch/x86/kernel/cpu/sgx/driver/Makefile new file mode 100644 index 000000000000..2bd952cc8a65 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_INTEL_SGX) += sgx.o +sgx-$(CONFIG_INTEL_SGX) += encl.o ioctl.o main.o pte.o vma.o diff --git a/arch/x86/kernel/cpu/sgx/driver/driver.h b/arch/x86/kernel/cpu/sgx/driver/driver.h new file mode 100644 index 000000000000..c9e40e090c58 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/driver.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/** + * Copyright(c) 2016-18 Intel Corporation. + */ +#ifndef __ARCH_INTEL_SGX_H__ +#define __ARCH_INTEL_SGX_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define sgx_pr(level, encl, fmt, ...) \ + pr_ ## level("sgx: [%d:0x%p] " fmt, pid_nr((encl)->tgid), \ + (void *)(encl)->base, ##__VA_ARGS__) +#define sgx_dbg(encl, fmt, ...) \ + sgx_pr(debug, encl, fmt, ##__VA_ARGS__) +#define sgx_info(encl, fmt, ...) \ + sgx_pr(info, encl, fmt, ##__VA_ARGS__) +#define sgx_warn(encl, fmt, ...) \ + sgx_pr(warn, encl, fmt, ##__VA_ARGS__) +#define sgx_err(encl, fmt, ...) \ + sgx_pr(err, encl, fmt, ##__VA_ARGS__) +#define sgx_crit(encl, fmt, ...) \ + sgx_pr(crit, encl, fmt, ##__VA_ARGS__) + +#define SGX_DRV_NR_DEVICES 1 +#define SGX_EINIT_SPIN_COUNT 20 +#define SGX_EINIT_SLEEP_COUNT 50 +#define SGX_EINIT_SLEEP_TIME 20 +#define SGX_VA_SLOT_COUNT 512 + +/** + * enum sgx_encl_page_desc - defines bits for an enclave page's descriptor + * %SGX_ENCL_PAGE_TCS: The page is a TCS page. + * %SGX_ENCL_PAGE_LOADED: The page is not swapped. + * %SGX_ENCL_PAGE_ADDR_MASK: Holds the virtual address of the page. + * + * The page address for SECS is zero and is used by the subsystem to recognize + * the SECS page. + */ +enum sgx_encl_page_desc { + SGX_ENCL_PAGE_TCS = BIT(0), + SGX_ENCL_PAGE_LOADED = BIT(1), + /* Bits 11:3 are available when the page is not swapped. */ + SGX_ENCL_PAGE_ADDR_MASK = PAGE_MASK, +}; + +#define SGX_ENCL_PAGE_ADDR(encl_page) \ + ((encl_page)->desc & SGX_ENCL_PAGE_ADDR_MASK) +#define SGX_ENCL_PAGE_VA_OFFSET(encl_page) \ + ((encl_page)->desc & SGX_ENCL_PAGE_VA_OFFSET_MASK) + +struct sgx_encl_page { + unsigned long desc; + union { + struct sgx_epc_page *epc_page; + struct sgx_va_page *va_page; + }; + struct sgx_encl *encl; +}; + +enum sgx_encl_flags { + SGX_ENCL_INITIALIZED = BIT(0), + SGX_ENCL_DEBUG = BIT(1), + SGX_ENCL_SUSPEND = BIT(2), + SGX_ENCL_DEAD = BIT(3), + SGX_ENCL_MM_RELEASED = BIT(4), +}; + +struct sgx_encl { + unsigned int flags; + uint64_t attributes; + uint64_t xfrm; + unsigned int page_cnt; + unsigned int secs_child_cnt; + struct mutex lock; + struct mm_struct *mm; + unsigned long backing; + struct kref refcount; + unsigned long base; + unsigned long size; + unsigned long ssaframesize; + struct radix_tree_root page_tree; + struct list_head add_page_reqs; + struct work_struct work; + struct sgx_encl_page secs; + struct pid *tgid; + struct mmu_notifier mmu_notifier; + struct notifier_block pm_notifier; +}; + +extern struct workqueue_struct *sgx_encl_wq; +extern u64 sgx_encl_size_max_32; +extern u64 sgx_encl_size_max_64; +extern u64 sgx_xfrm_mask; +extern u32 sgx_misc_reserved; +extern u32 sgx_xsave_size_tbl[64]; +extern int sgx_epcm_trapnr; + +extern const struct vm_operations_struct sgx_vm_ops; + +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, + struct vm_area_struct **vma); +void sgx_invalidate(struct sgx_encl *encl, bool flush_cpus); + +/** + * SGX_INVD - invalidate an enclave on failure, i.e. if ret != 0 + * @ret: a return code to check + * @encl: pointer to an enclave + * @fmt: message for WARN if failure is detected + * @...: optional arguments used by @fmt + * + * SGX_INVD is used in flows where an error, i.e. @ret is non-zero, is + * indicative of a driver bug. Invalidate @encl if @ret indicates an + * error and WARN on error unless the error was due to a fault signaled + * by the EPCM. + * + * Faults from the EPCM occur in normal kernel operation, e.g. due to + * misonfigured mprotect() from userspace or because the EPCM invalidated + * all EPC pages. The EPCM invalidates the EPC on transitions to S3 or + * lower sleep states, and VMMs emulate loss of EPC when migrating VMs. + * + * Defined as a macro instead of a function so that WARN can provide a + * more precise trace. + */ +#define SGX_INVD(ret, encl, fmt, ...) \ +do { \ + if (unlikely(ret)) { \ + int trapnr = IS_ENCLS_FAULT(ret) ? ENCLS_TRAPNR(ret) : 0; \ + WARN(trapnr != sgx_epcm_trapnr, fmt, ##__VA_ARGS__); \ + sgx_invalidate(encl, true); \ + } \ +} while (0) + +struct sgx_encl *sgx_encl_alloc(struct sgx_secs *secs); +int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs); +struct sgx_encl_page *sgx_encl_alloc_page(struct sgx_encl *encl, + unsigned long addr); +void sgx_encl_free_page(struct sgx_encl_page *encl_page); +int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr, void *data, + struct sgx_secinfo *secinfo, unsigned int mrmask); +int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, + struct sgx_einittoken *einittoken); +void sgx_encl_block(struct sgx_encl_page *encl_page); +void sgx_encl_track(struct sgx_encl *encl); +void sgx_encl_release(struct kref *ref); +pgoff_t sgx_encl_get_index(struct sgx_encl *encl, struct sgx_encl_page *page); + +long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +long sgx_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); +#endif + +struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma, + unsigned long addr, + bool do_reserve); + +int sgx_test_and_clear_young(struct sgx_encl_page *page); +void sgx_flush_cpus(struct sgx_encl *encl); + +#endif /* __ARCH_X86_INTEL_SGX_H__ */ diff --git a/arch/x86/kernel/cpu/sgx/driver/encl.c b/arch/x86/kernel/cpu/sgx/driver/encl.c new file mode 100644 index 000000000000..0ea85c77d437 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/encl.c @@ -0,0 +1,813 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "driver.h" + +struct sgx_add_page_req { + struct sgx_encl *encl; + struct sgx_encl_page *encl_page; + struct sgx_secinfo secinfo; + unsigned long mrmask; + struct list_head list; +}; + +/** + * sgx_encl_find - find an enclave + * @mm: mm struct of the current process + * @addr: address in the ELRANGE + * @vma: the resulting VMA + * + * Finds an enclave identified by the given address. Gives back the VMA, that + * is part of the enclave, located in that address. The VMA is given back if it + * is a proper enclave VMA even if an &sgx_encl instance does not exist + * yet (enclave creation has not been performed). + * + * Return: + * 0 on success, + * -EINVAL if an enclave was not found, + * -ENOENT if the enclave has not been created yet + */ +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, + struct vm_area_struct **vma) +{ + struct vm_area_struct *result; + struct sgx_encl *encl; + + result = find_vma(mm, addr); + if (!result || result->vm_ops != &sgx_vm_ops || addr < result->vm_start) + return -EINVAL; + + encl = result->vm_private_data; + *vma = result; + + return encl ? 0 : -ENOENT; +} + +/** + * sgx_invalidate - kill an enclave + * @encl: an &sgx_encl instance + * @flush_cpus Set if there can be active threads inside the enclave. + * + * Mark the enclave as dead and immediately free its EPC pages (but not + * its resources). For active enclaves, the entry points to the enclave + * are destroyed first and hardware threads are kicked out so that the + * EPC pages can be safely manipulated. + */ +void sgx_invalidate(struct sgx_encl *encl, bool flush_cpus) +{ + struct sgx_encl_page *entry; + struct radix_tree_iter iter; + struct vm_area_struct *vma; + unsigned long addr; + void **slot; + + encl->flags |= SGX_ENCL_DEAD; + + if (flush_cpus && (encl->flags & SGX_ENCL_INITIALIZED)) { + radix_tree_for_each_slot(slot, &encl->page_tree, &iter, 0) { + entry = *slot; + addr = SGX_ENCL_PAGE_ADDR(entry); + if ((entry->desc & SGX_ENCL_PAGE_LOADED) && + (entry->desc & SGX_ENCL_PAGE_TCS) && + !sgx_encl_find(encl->mm, addr, &vma)) + zap_vma_ptes(vma, addr, PAGE_SIZE); + } + sgx_flush_cpus(encl); + } + + radix_tree_for_each_slot(slot, &encl->page_tree, &iter, 0) { + entry = *slot; + if (entry->desc & SGX_ENCL_PAGE_LOADED) { + if (!__sgx_free_page(entry->epc_page)) { + encl->secs_child_cnt--; + entry->desc &= ~SGX_ENCL_PAGE_LOADED; + } + } + } + + if (!encl->secs_child_cnt && + (encl->secs.desc & SGX_ENCL_PAGE_LOADED)) { + encl->secs.desc &= ~SGX_ENCL_PAGE_LOADED; + sgx_free_page(encl->secs.epc_page); + } +} + +static bool sgx_process_add_page_req(struct sgx_add_page_req *req, + struct sgx_epc_page *epc_page) +{ + struct sgx_encl_page *encl_page = req->encl_page; + struct sgx_encl *encl = req->encl; + unsigned long page_index = sgx_encl_get_index(encl, encl_page); + unsigned long backing_addr = encl->backing + page_index * PAGE_SIZE; + struct sgx_secinfo secinfo; + struct sgx_pageinfo pginfo; + struct vm_area_struct *vma; + struct page *backing; + unsigned long addr; + int ret; + int i; + + if (encl->flags & (SGX_ENCL_SUSPEND | SGX_ENCL_DEAD)) + return false; + + addr = SGX_ENCL_PAGE_ADDR(encl_page); + ret = sgx_encl_find(encl->mm, addr, &vma); + if (ret) + return false; + + ret = get_user_pages_remote(NULL, encl->mm, backing_addr, 1, 0, + &backing, NULL, NULL); + if (ret < 0) + return false; + + ret = vmf_insert_pfn(vma, addr, PFN_DOWN(epc_page->desc)); + if (ret != VM_FAULT_NOPAGE) { + put_page(backing); + return false; + } + + /* + * The SECINFO field must be 64-byte aligned, copy it to a local + * variable that is guaranteed to be aligned as req->secinfo may + * or may not be 64-byte aligned, e.g. req may have been allocated + * via kzalloc which is not aware of __aligned attributes. + */ + memcpy(&secinfo, &req->secinfo, sizeof(secinfo)); + + pginfo.secs = (unsigned long)sgx_epc_addr(encl->secs.epc_page); + pginfo.addr = addr; + pginfo.metadata = (unsigned long)&secinfo; + pginfo.contents = (unsigned long)kmap_atomic(backing); + ret = __eadd(&pginfo, sgx_epc_addr(epc_page)); + kunmap_atomic((void *)(unsigned long)pginfo.contents); + + put_page(backing); + if (ret) { + SGX_INVD(ret, encl, "EADD returned %d (0x%x)", ret, ret); + zap_vma_ptes(vma, addr, PAGE_SIZE); + return false; + } + + for_each_set_bit(i, &req->mrmask, 16) { + ret = __eextend(sgx_epc_addr(encl->secs.epc_page), + sgx_epc_addr(epc_page) + (i * 0x100)); + if (ret) { + SGX_INVD(ret, encl, "EEXTEND returned %d (0x%x)", ret, + ret); + zap_vma_ptes(vma, addr, PAGE_SIZE); + return ret; + } + } + + encl_page->encl = encl; + encl_page->epc_page = epc_page; + encl_page->desc |= SGX_ENCL_PAGE_LOADED; + encl->secs_child_cnt++; + sgx_test_and_clear_young(encl_page); + + return true; +} + +static void sgx_add_page_worker(struct work_struct *work) +{ + struct sgx_add_page_req *req; + bool skip_rest = false; + bool is_empty = false; + struct sgx_encl *encl; + struct sgx_epc_page *epc_page; + + encl = container_of(work, struct sgx_encl, work); + + do { + schedule(); + + mutex_lock(&encl->lock); + if (encl->flags & SGX_ENCL_DEAD) + skip_rest = true; + + req = list_first_entry(&encl->add_page_reqs, + struct sgx_add_page_req, list); + list_del(&req->list); + is_empty = list_empty(&encl->add_page_reqs); + mutex_unlock(&encl->lock); + + if (skip_rest) + goto next; + + epc_page = sgx_alloc_page(); + down_read(&encl->mm->mmap_sem); + mutex_lock(&encl->lock); + + if (IS_ERR(epc_page)) { + sgx_invalidate(encl, false); + skip_rest = true; + } else if (!sgx_process_add_page_req(req, epc_page)) { + sgx_free_page(epc_page); + sgx_invalidate(encl, false); + skip_rest = true; + } + + mutex_unlock(&encl->lock); + up_read(&encl->mm->mmap_sem); + +next: + kfree(req); + } while (!kref_put(&encl->refcount, sgx_encl_release) && !is_empty); +} + +static u32 sgx_calc_ssaframesize(u32 miscselect, u64 xfrm) +{ + u32 size_max = PAGE_SIZE; + u32 size; + int i; + + for (i = 2; i < 64; i++) { + if (!((1 << i) & xfrm)) + continue; + + size = SGX_SSA_GPRS_SIZE + sgx_xsave_size_tbl[i]; + if (miscselect & SGX_MISC_EXINFO) + size += SGX_SSA_MISC_EXINFO_SIZE; + + if (size > size_max) + size_max = size; + } + + return PFN_UP(size_max); +} + +static int sgx_validate_secs(const struct sgx_secs *secs, + unsigned long ssaframesize) +{ + if (secs->size < (2 * PAGE_SIZE) || !is_power_of_2(secs->size)) + return -EINVAL; + + if (secs->base & (secs->size - 1)) + return -EINVAL; + + if (secs->attributes & SGX_ATTR_RESERVED_MASK || + secs->miscselect & sgx_misc_reserved) + return -EINVAL; + + if (secs->attributes & SGX_ATTR_MODE64BIT) { + if (secs->size > sgx_encl_size_max_64) + return -EINVAL; + } else if (secs->size > sgx_encl_size_max_32) + return -EINVAL; + + if (!(secs->xfrm & XFEATURE_MASK_FP) || + !(secs->xfrm & XFEATURE_MASK_SSE) || + (((secs->xfrm >> XFEATURE_BNDREGS) & 1) != + ((secs->xfrm >> XFEATURE_BNDCSR) & 1)) || + (secs->xfrm & ~sgx_xfrm_mask)) + return -EINVAL; + + if (!secs->ssa_frame_size || ssaframesize > secs->ssa_frame_size) + return -EINVAL; + + if (memchr_inv(secs->reserved1, 0, SGX_SECS_RESERVED1_SIZE) || + memchr_inv(secs->reserved2, 0, SGX_SECS_RESERVED2_SIZE) || + memchr_inv(secs->reserved3, 0, SGX_SECS_RESERVED3_SIZE) || + memchr_inv(secs->reserved4, 0, SGX_SECS_RESERVED4_SIZE)) + return -EINVAL; + + return 0; +} + +static void sgx_mmu_notifier_release(struct mmu_notifier *mn, + struct mm_struct *mm) +{ + struct sgx_encl *encl = + container_of(mn, struct sgx_encl, mmu_notifier); + + mutex_lock(&encl->lock); + encl->flags |= SGX_ENCL_DEAD | SGX_ENCL_MM_RELEASED; + mutex_unlock(&encl->lock); +} + +static const struct mmu_notifier_ops sgx_mmu_notifier_ops = { + .release = sgx_mmu_notifier_release, +}; + +/** + * sgx_encl_alloc - allocate memory for an enclave and set attributes + * + * @secs: SECS data (must be page aligned) + * + * Allocates a new &sgx_encl instance. Validates SECS attributes, creates + * backing storage for the enclave and sets enclave attributes to sane initial + * values. + * + * Return: + * an &sgx_encl instance, + * -errno otherwise + */ +struct sgx_encl *sgx_encl_alloc(struct sgx_secs *secs) +{ + unsigned long ssaframesize; + struct sgx_encl *encl; + unsigned long backing; + int ret; + + ssaframesize = sgx_calc_ssaframesize(secs->miscselect, secs->xfrm); + if (sgx_validate_secs(secs, ssaframesize)) + return ERR_PTR(-EINVAL); + + backing = vm_mmap(NULL, 0, secs->size + PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_PRIVATE, 0); + if (IS_ERR((void *)backing)) { + ret = PTR_ERR((void *)backing); + goto out_err; + } + + encl = kzalloc(sizeof(*encl), GFP_KERNEL); + if (!encl) { + ret = -ENOMEM; + goto out_backing; + } + + encl->attributes = SGX_ATTR_MODE64BIT | SGX_ATTR_DEBUG; + encl->xfrm = secs->xfrm; + kref_init(&encl->refcount); + INIT_LIST_HEAD(&encl->add_page_reqs); + INIT_RADIX_TREE(&encl->page_tree, GFP_KERNEL); + mutex_init(&encl->lock); + INIT_WORK(&encl->work, sgx_add_page_worker); + encl->mm = current->mm; + encl->base = secs->base; + encl->size = secs->size; + encl->ssaframesize = secs->ssa_frame_size; + encl->backing = backing; + + return encl; + +out_backing: + vm_munmap((unsigned long)backing, secs->size + PAGE_SIZE); + +out_err: + return ERR_PTR(ret); +} + +static int sgx_encl_pm_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct sgx_encl *encl = container_of(nb, struct sgx_encl, pm_notifier); + + if (action != PM_SUSPEND_PREPARE && action != PM_HIBERNATION_PREPARE) + return NOTIFY_DONE; + + mutex_lock(&encl->lock); + sgx_invalidate(encl, false); + encl->flags |= SGX_ENCL_SUSPEND; + mutex_unlock(&encl->lock); + flush_work(&encl->work); + return NOTIFY_DONE; +} + +/** + * sgx_encl_create - create an enclave + * + * @encl: an enclave + * @secs: page aligned SECS data + * + * Validates SECS attributes, allocates an EPC page for the SECS and creates + * the enclave by performing ECREATE. + * + * Return: + * 0 on success, + * -errno otherwise + */ +int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs) +{ + struct vm_area_struct *vma; + struct sgx_pageinfo pginfo; + struct sgx_secinfo secinfo; + struct sgx_epc_page *secs_epc; + long ret; + + secs_epc = sgx_alloc_page(); + if (IS_ERR(secs_epc)) { + ret = PTR_ERR(secs_epc); + return ret; + } + + encl->secs.encl = encl; + encl->secs.epc_page = secs_epc; + encl->secs.desc |= SGX_ENCL_PAGE_LOADED; + encl->tgid = get_pid(task_tgid(current)); + + pginfo.addr = 0; + pginfo.contents = (unsigned long)secs; + pginfo.metadata = (unsigned long)&secinfo; + pginfo.secs = 0; + memset(&secinfo, 0, sizeof(secinfo)); + ret = __ecreate((void *)&pginfo, sgx_epc_addr(secs_epc)); + + if (ret) { + sgx_dbg(encl, "ECREATE returned %ld\n", ret); + return ret; + } + + if (secs->attributes & SGX_ATTR_DEBUG) + encl->flags |= SGX_ENCL_DEBUG; + + encl->mmu_notifier.ops = &sgx_mmu_notifier_ops; + ret = mmu_notifier_register(&encl->mmu_notifier, encl->mm); + if (ret) { + if (ret == -EINTR) + ret = -ERESTARTSYS; + encl->mmu_notifier.ops = NULL; + return ret; + } + + encl->pm_notifier.notifier_call = &sgx_encl_pm_notifier; + ret = register_pm_notifier(&encl->pm_notifier); + if (ret) { + encl->pm_notifier.notifier_call = NULL; + return ret; + } + + down_read(¤t->mm->mmap_sem); + ret = sgx_encl_find(current->mm, secs->base, &vma); + if (ret != -ENOENT) { + if (!ret) + ret = -EINVAL; + up_read(¤t->mm->mmap_sem); + return ret; + } + + if (vma->vm_start != secs->base || + vma->vm_end != (secs->base + secs->size) || + vma->vm_pgoff != 0) { + ret = -EINVAL; + up_read(¤t->mm->mmap_sem); + return ret; + } + + vma->vm_private_data = encl; + up_read(¤t->mm->mmap_sem); + return 0; +} + +static int sgx_validate_secinfo(struct sgx_secinfo *secinfo) +{ + u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK; + u64 perm = secinfo->flags & SGX_SECINFO_PERMISSION_MASK; + int i; + + if ((secinfo->flags & SGX_SECINFO_RESERVED_MASK) || + ((perm & SGX_SECINFO_W) && !(perm & SGX_SECINFO_R)) || + (page_type != SGX_SECINFO_TCS && + page_type != SGX_SECINFO_REG)) + return -EINVAL; + + for (i = 0; i < SGX_SECINFO_RESERVED_SIZE; i++) + if (secinfo->reserved[i]) + return -EINVAL; + + return 0; +} + +static bool sgx_validate_offset(struct sgx_encl *encl, unsigned long offset) +{ + if (offset & (PAGE_SIZE - 1)) + return false; + + if (offset >= encl->size) + return false; + + return true; +} + +static int sgx_validate_tcs(struct sgx_encl *encl, struct sgx_tcs *tcs) +{ + int i; + + if (tcs->flags & SGX_TCS_RESERVED_MASK) + return -EINVAL; + + if (tcs->flags & SGX_TCS_DBGOPTIN) + return -EINVAL; + + if (!sgx_validate_offset(encl, tcs->ssa_offset)) + return -EINVAL; + + if (!sgx_validate_offset(encl, tcs->fs_offset)) + return -EINVAL; + + if (!sgx_validate_offset(encl, tcs->gs_offset)) + return -EINVAL; + + if ((tcs->fs_limit & 0xFFF) != 0xFFF) + return -EINVAL; + + if ((tcs->gs_limit & 0xFFF) != 0xFFF) + return -EINVAL; + + for (i = 0; i < SGX_TCS_RESERVED_SIZE; i++) + if (tcs->reserved[i]) + return -EINVAL; + + return 0; +} + +static int __sgx_encl_add_page(struct sgx_encl *encl, + struct sgx_encl_page *encl_page, + void *data, + struct sgx_secinfo *secinfo, + unsigned int mrmask) +{ + unsigned long page_index = sgx_encl_get_index(encl, encl_page); + unsigned long backing_addr = encl->backing + page_index * PAGE_SIZE; + u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK; + struct sgx_add_page_req *req = NULL; + struct page *backing; + void *backing_ptr; + int empty; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = get_user_pages(backing_addr, 1, FOLL_WRITE, &backing, NULL); + if (ret < 0) { + kfree(req); + return ret; + } + backing_ptr = kmap(backing); + memcpy(backing_ptr, data, PAGE_SIZE); + kunmap(backing); + if (page_type == SGX_SECINFO_TCS) + encl_page->desc |= SGX_ENCL_PAGE_TCS; + memcpy(&req->secinfo, secinfo, sizeof(*secinfo)); + req->encl = encl; + req->encl_page = encl_page; + req->mrmask = mrmask; + empty = list_empty(&encl->add_page_reqs); + kref_get(&encl->refcount); + list_add_tail(&req->list, &encl->add_page_reqs); + if (empty) + queue_work(sgx_encl_wq, &encl->work); + set_page_dirty(backing); + put_page(backing); + return 0; +} + +/** + * sgx_encl_alloc_page - allocate a new enclave page + * @encl: an enclave + * @addr: page address in the ELRANGE + * + * Return: + * an &sgx_encl_page instance on success, + * -errno otherwise + */ +struct sgx_encl_page *sgx_encl_alloc_page(struct sgx_encl *encl, + unsigned long addr) +{ + struct sgx_encl_page *encl_page; + int ret; + + if (radix_tree_lookup(&encl->page_tree, PFN_DOWN(addr))) + return ERR_PTR(-EEXIST); + encl_page = kzalloc(sizeof(*encl_page), GFP_KERNEL); + if (!encl_page) + return ERR_PTR(-ENOMEM); + encl_page->desc = addr; + encl_page->encl = encl; + ret = radix_tree_insert(&encl->page_tree, PFN_DOWN(encl_page->desc), + encl_page); + if (ret) { + kfree(encl_page); + return ERR_PTR(ret); + } + return encl_page; +} + +/** + * sgx_encl_add_page - add a page to the enclave + * + * @encl: an enclave + * @addr: page address in the ELRANGE + * @data: page data + * @secinfo: page permissions + * @mrmask: bitmask to select the 256 byte chunks to be measured + * + * Creates a new enclave page and enqueues an EADD operation that will be + * processed by a worker thread later on. + * + * Return: + * 0 on success, + * -errno otherwise + */ +int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr, void *data, + struct sgx_secinfo *secinfo, unsigned int mrmask) +{ + u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK; + struct sgx_encl_page *encl_page; + int ret; + + if (sgx_validate_secinfo(secinfo)) + return -EINVAL; + if (page_type == SGX_SECINFO_TCS) { + ret = sgx_validate_tcs(encl, data); + if (ret) + return ret; + } + + down_read(¤t->mm->mmap_sem); + mutex_lock(&encl->lock); + + if (encl->flags & (SGX_ENCL_INITIALIZED | SGX_ENCL_DEAD)) { + ret = -EINVAL; + goto out; + } + + encl_page = sgx_encl_alloc_page(encl, addr); + if (IS_ERR(encl_page)) { + ret = PTR_ERR(encl_page); + goto out; + } + + ret = __sgx_encl_add_page(encl, encl_page, data, secinfo, mrmask); + if (ret) { + radix_tree_delete(&encl_page->encl->page_tree, + PFN_DOWN(encl_page->desc)); + kfree(encl_page); + } + +out: + mutex_unlock(&encl->lock); + up_read(¤t->mm->mmap_sem); + return ret; +} + +static int __sgx_get_key_hash(struct crypto_shash *tfm, const void *modulus, + void *hash) +{ + SHASH_DESC_ON_STACK(shash, tfm); + + shash->tfm = tfm; + shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + 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; +} + +/** + * sgx_encl_init - perform EINIT for the given enclave + * + * @encl: an enclave + * @sigstruct: SIGSTRUCT for the enclave + * @token: EINITTOKEN for the enclave + * + * Retries a few times in order to perform EINIT operation on an enclave + * because there could be potentially an interrupt storm. + * + * Return: + * 0 on success, + * SGX error code on EINIT failure, + * -errno otherwise + */ +int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, + struct sgx_einittoken *token) +{ + u64 mrsigner[4]; + int ret; + int i; + int j; + + if (sigstruct->attributes & ~encl->attributes) + return -EINVAL; + + ret = sgx_get_key_hash(sigstruct->modulus, mrsigner); + if (ret) + return ret; + + flush_work(&encl->work); + + mutex_lock(&encl->lock); + + if (encl->flags & SGX_ENCL_INITIALIZED) { + mutex_unlock(&encl->lock); + return 0; + } + if (encl->flags & SGX_ENCL_DEAD) { + mutex_unlock(&encl->lock); + return -EFAULT; + } + + 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)) { + mutex_unlock(&encl->lock); + return -ERESTARTSYS; + } + } + + if (unlikely(IS_ENCLS_FAULT(ret))) + SGX_INVD(ret, encl, "EINIT returned %d (%x)", ret, ret); + else if (ret > 0) + sgx_dbg(encl, "EINIT returned %d\n", ret); + else if (!ret) + encl->flags |= SGX_ENCL_INITIALIZED; + mutex_unlock(&encl->lock); + + return ret; +} + +static void sgx_encl_release_worker(struct work_struct *work) +{ + struct sgx_encl *encl = container_of(work, struct sgx_encl, work); + unsigned long backing_size = encl->size + PAGE_SIZE; + + if (encl->flags & SGX_ENCL_MM_RELEASED) { + down_write(&encl->mm->mmap_sem); + do_munmap(encl->mm, (unsigned long)encl->backing, backing_size, + NULL); + up_write(&encl->mm->mmap_sem); + } + + if (encl->mmu_notifier.ops) + mmu_notifier_unregister(&encl->mmu_notifier, encl->mm); + + if (encl->tgid) + put_pid(encl->tgid); + + kfree(encl); +} + +/** + * sgx_encl_release - destroy an enclave instance + * @kref: address of a kref inside &sgx_encl + * + * Used together with kref_put(). Frees all the resources associated with the + * enclave and the instance itself. Done as a deferred call so that we can + * freely use mmap_sem. + */ +void sgx_encl_release(struct kref *ref) +{ + struct sgx_encl *encl = container_of(ref, struct sgx_encl, refcount); + + if (encl->pm_notifier.notifier_call) + unregister_pm_notifier(&encl->pm_notifier); + + sgx_invalidate(encl, false); + + INIT_WORK(&encl->work, sgx_encl_release_worker); + queue_work(sgx_encl_wq, &encl->work); +} + +/** + * sgx_encl_get_index() - convert page descriptor to a page index + * @encl: an enclave + * @page: an enclave page + * + * Given an enclave page descriptor, convert it to a page index used to access + * backing storage. The backing page for SECS is located after the enclave + * pages. + */ +pgoff_t sgx_encl_get_index(struct sgx_encl *encl, struct sgx_encl_page *page) +{ + if (!PFN_DOWN(page->desc)) + return PFN_DOWN(encl->size); + + return PFN_DOWN(page->desc - encl->base); +} diff --git a/arch/x86/kernel/cpu/sgx/driver/ioctl.c b/arch/x86/kernel/cpu/sgx/driver/ioctl.c new file mode 100644 index 000000000000..3a712950e116 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/ioctl.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include "driver.h" + +static int sgx_encl_get(unsigned long addr, struct sgx_encl **encl) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + int ret; + + if (addr & (PAGE_SIZE - 1)) + return -EINVAL; + + down_read(&mm->mmap_sem); + + ret = sgx_encl_find(mm, addr, &vma); + if (!ret) { + *encl = vma->vm_private_data; + + if ((*encl)->flags & SGX_ENCL_SUSPEND) + ret = SGX_POWER_LOST_ENCLAVE; + else + kref_get(&(*encl)->refcount); + } + + up_read(&mm->mmap_sem); + return ret; +} + +/** + * sgx_ioc_enclave_create - handler for %SGX_IOC_ENCLAVE_CREATE + * @filep: open file to /dev/sgx + * @cmd: the command value + * @arg: pointer to an &sgx_enclave_create instance + * + * Validates SECS attributes, allocates an EPC page for the SECS and performs + * ECREATE. + * + * Return: + * 0 on success, + * -errno otherwise + */ +static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + struct sgx_enclave_create *createp = (struct sgx_enclave_create *)arg; + struct page *secs_page; + struct sgx_secs *secs; + struct sgx_encl *encl; + int ret; + + secs_page = alloc_page(GFP_HIGHUSER); + if (!secs_page) + return -ENOMEM; + + secs = kmap(secs_page); + ret = copy_from_user(secs, (void __user *)createp->src, sizeof(*secs)); + if (ret) + goto out; + + encl = sgx_encl_alloc(secs); + if (IS_ERR(encl)) { + ret = PTR_ERR(encl); + goto out; + } + + ret = sgx_encl_create(encl, secs); + if (ret) + kref_put(&encl->refcount, sgx_encl_release); + +out: + kunmap(secs_page); + __free_page(secs_page); + return ret; +} + +/** + * sgx_ioc_enclave_add_page - handler for %SGX_IOC_ENCLAVE_ADD_PAGE + * + * @filep: open file to /dev/sgx + * @cmd: the command value + * @arg: pointer to an &sgx_enclave_add_page instance + * + * Creates a new enclave page and enqueues an EADD operation that will be + * processed by a worker thread later on. + * + * Return: + * 0 on success, + * -errno otherwise + */ +static long sgx_ioc_enclave_add_page(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + struct sgx_enclave_add_page *addp = (void *)arg; + struct sgx_secinfo secinfo; + struct sgx_encl *encl; + struct page *data_page; + void *data; + int ret; + + ret = sgx_encl_get(addp->addr, &encl); + if (ret) + return ret; + + if (copy_from_user(&secinfo, (void __user *)addp->secinfo, + sizeof(secinfo))) { + kref_put(&encl->refcount, sgx_encl_release); + return -EFAULT; + } + + data_page = alloc_page(GFP_HIGHUSER); + if (!data_page) { + kref_put(&encl->refcount, sgx_encl_release); + return -ENOMEM; + } + + data = kmap(data_page); + + ret = copy_from_user((void *)data, (void __user *)addp->src, PAGE_SIZE); + if (ret) + goto out; + + ret = sgx_encl_add_page(encl, addp->addr, data, &secinfo, addp->mrmask); + if (ret) + goto out; + +out: + kref_put(&encl->refcount, sgx_encl_release); + kunmap(data_page); + __free_page(data_page); + return ret; +} + +/** + * sgx_ioc_enclave_init - handler for %SGX_IOC_ENCLAVE_INIT + * + * @filep: open file to /dev/sgx + * @cmd: the command value + * @arg: pointer to an &sgx_enclave_init instance + * + * Flushes the remaining enqueued EADD operations and performs EINIT. + * + * Return: + * 0 on success, + * SGX error code on EINIT failure, + * -errno otherwise + */ +static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + struct sgx_enclave_init *initp = (struct sgx_enclave_init *)arg; + struct sgx_sigstruct *sigstruct; + struct sgx_einittoken *einittoken; + struct sgx_encl *encl; + struct page *initp_page; + int ret; + + initp_page = alloc_page(GFP_HIGHUSER); + if (!initp_page) + return -ENOMEM; + + sigstruct = kmap(initp_page); + einittoken = (struct sgx_einittoken *) + ((unsigned long)sigstruct + PAGE_SIZE / 2); + memset(einittoken, 0, sizeof(*einittoken)); + + if (copy_from_user(sigstruct, (void __user *)initp->sigstruct, + sizeof(*sigstruct))) { + ret = -EFAULT; + goto out; + } + + ret = sgx_encl_get(initp->addr, &encl); + if (ret) + goto out; + + ret = sgx_encl_init(encl, sigstruct, einittoken); + + kref_put(&encl->refcount, sgx_encl_release); + +out: + kunmap(initp_page); + __free_page(initp_page); + return ret; +} + +typedef long (*sgx_ioc_t)(struct file *filep, unsigned int cmd, + unsigned long arg); + +long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + char data[256]; + sgx_ioc_t handler = NULL; + long ret; + + switch (cmd) { + case SGX_IOC_ENCLAVE_CREATE: + handler = sgx_ioc_enclave_create; + break; + case SGX_IOC_ENCLAVE_ADD_PAGE: + handler = sgx_ioc_enclave_add_page; + break; + case SGX_IOC_ENCLAVE_INIT: + handler = sgx_ioc_enclave_init; + break; + default: + return -ENOIOCTLCMD; + } + + if (copy_from_user(data, (void __user *)arg, _IOC_SIZE(cmd))) + return -EFAULT; + + ret = handler(filep, cmd, (unsigned long)((void *)data)); + if (!ret && (cmd & IOC_OUT)) { + if (copy_to_user((void __user *)arg, data, _IOC_SIZE(cmd))) + return -EFAULT; + } + if (IS_ENCLS_FAULT(ret)) + return -EFAULT; + return ret; +} diff --git a/arch/x86/kernel/cpu/sgx/driver/main.c b/arch/x86/kernel/cpu/sgx/driver/main.c new file mode 100644 index 000000000000..19280863d703 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/main.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include +#include +#include +#include "driver.h" + +MODULE_DESCRIPTION("Intel SGX Enclave Driver"); +MODULE_AUTHOR("Jarkko Sakkinen "); +MODULE_LICENSE("Dual BSD/GPL"); + +struct workqueue_struct *sgx_encl_wq; +u64 sgx_encl_size_max_32; +u64 sgx_encl_size_max_64; +u64 sgx_xfrm_mask = 0x3; +u32 sgx_misc_reserved; +u32 sgx_xsave_size_tbl[64]; +int sgx_epcm_trapnr; + +#ifdef CONFIG_COMPAT +long sgx_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + return sgx_ioctl(filep, cmd, arg); +} +#endif + +static int sgx_mmap(struct file *file, struct vm_area_struct *vma) +{ + vma->vm_ops = &sgx_vm_ops; + vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO | + VM_DONTCOPY; + + return 0; +} + +static unsigned long sgx_get_unmapped_area(struct file *file, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags) +{ + if (len < 2 * PAGE_SIZE || (len & (len - 1))) + return -EINVAL; + + addr = current->mm->get_unmapped_area(file, addr, 2 * len, pgoff, + flags); + if (IS_ERR_VALUE(addr)) + return addr; + + addr = (addr + (len - 1)) & ~(len - 1); + + return addr; +} + +static const struct file_operations sgx_ctrl_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = sgx_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = sgx_compat_ioctl, +#endif + .mmap = sgx_mmap, + .get_unmapped_area = sgx_get_unmapped_area, +}; + +static struct bus_type sgx_bus_type = { + .name = "sgx", +}; + +struct sgx_dev_ctx { + struct device ctrl_dev; + struct cdev ctrl_cdev; +}; + +static dev_t sgx_devt; + +static void sgx_dev_release(struct device *dev) +{ + struct sgx_dev_ctx *ctx = container_of(dev, struct sgx_dev_ctx, + ctrl_dev); + + kfree(ctx); +} + +static void sgx_dev_init(struct device *dev, struct cdev *cdev, + struct device *parent, const char *name, + const struct file_operations *fops) +{ + device_initialize(dev); + + dev->bus = &sgx_bus_type; + dev->parent = parent; + dev->devt = MKDEV(MAJOR(sgx_devt), 0); + dev->release = sgx_dev_release; + + dev_set_name(dev, name); + + cdev_init(cdev, fops); + cdev->owner = THIS_MODULE; +} + +static struct sgx_dev_ctx *sgx_dev_ctx_alloc(struct device *parent) +{ + struct sgx_dev_ctx *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + sgx_dev_init(&ctx->ctrl_dev, &ctx->ctrl_cdev, parent, "sgx", + &sgx_ctrl_fops); + dev_set_drvdata(parent, ctx); + + return ctx; +} + +static struct sgx_dev_ctx *sgxm_dev_ctx_alloc(struct device *parent) +{ + struct sgx_dev_ctx *ctx; + int rc; + + ctx = sgx_dev_ctx_alloc(parent); + if (IS_ERR(ctx)) + return ctx; + + rc = devm_add_action_or_reset(parent, (void (*)(void *))put_device, + &ctx->ctrl_dev); + if (rc) { + kfree(ctx); + return ERR_PTR(rc); + } + + return ctx; +} + +static int sgx_drv_init(struct device *parent) +{ + struct sgx_dev_ctx *sgx_dev; + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + int ret; + int i; + + sgx_dev = sgxm_dev_ctx_alloc(parent); + + cpuid_count(SGX_CPUID, 0, &eax, &ebx, &ecx, &edx); + /* Only allow misc bits supported by the driver. */ + sgx_misc_reserved = ~ebx | SGX_MISC_RESERVED_MASK; + sgx_encl_size_max_64 = 1ULL << ((edx >> 8) & 0xFF); + sgx_encl_size_max_32 = 1ULL << (edx & 0xFF); + + if (boot_cpu_has(X86_FEATURE_OSXSAVE)) { + cpuid_count(SGX_CPUID, 1, &eax, &ebx, &ecx, &edx); + sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx; + + for (i = 2; i < 64; i++) { + cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx); + if ((1 << i) & sgx_xfrm_mask) + sgx_xsave_size_tbl[i] = eax + ebx; + } + } + + sgx_epcm_trapnr = boot_cpu_has(X86_FEATURE_SGX2) ? X86_TRAP_PF : + X86_TRAP_GP; + + sgx_encl_wq = alloc_workqueue("sgx-encl-wq", + WQ_UNBOUND | WQ_FREEZABLE, 1); + if (!sgx_encl_wq) + return -ENOMEM; + + ret = cdev_device_add(&sgx_dev->ctrl_cdev, &sgx_dev->ctrl_dev); + if (ret) + goto err_device_add; + + return 0; + +err_device_add: + destroy_workqueue(sgx_encl_wq); + return ret; +} + +static int sgx_drv_probe(struct platform_device *pdev) +{ + if (!boot_cpu_has(X86_FEATURE_SGX)) + return -ENODEV; + + if (!boot_cpu_has(X86_FEATURE_SGX_LC)) { + pr_warn("sgx: IA32_SGXLEPUBKEYHASHx MSRs are not writable\n"); + return -ENODEV; + } + + return sgx_drv_init(&pdev->dev); +} + +static int sgx_drv_remove(struct platform_device *pdev) +{ + struct sgx_dev_ctx *ctx = dev_get_drvdata(&pdev->dev); + + cdev_device_del(&ctx->ctrl_cdev, &ctx->ctrl_dev); + destroy_workqueue(sgx_encl_wq); + + return 0; +} + +#ifdef CONFIG_ACPI +static struct acpi_device_id sgx_device_ids[] = { + {"INT0E0C", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, sgx_device_ids); +#endif + +static struct platform_driver sgx_drv = { + .probe = sgx_drv_probe, + .remove = sgx_drv_remove, + .driver = { + .name = "sgx", + .acpi_match_table = ACPI_PTR(sgx_device_ids), + }, +}; + +static int __init sgx_drv_subsys_init(void) +{ + int ret; + + ret = bus_register(&sgx_bus_type); + if (ret) + return ret; + + ret = alloc_chrdev_region(&sgx_devt, 0, SGX_DRV_NR_DEVICES, "sgx"); + if (ret < 0) { + bus_unregister(&sgx_bus_type); + return ret; + } + + return 0; +} + +static void sgx_drv_subsys_exit(void) +{ + bus_unregister(&sgx_bus_type); + unregister_chrdev_region(sgx_devt, SGX_DRV_NR_DEVICES); +} + +static int __init sgx_init(void) +{ + int ret; + + ret = sgx_drv_subsys_init(); + if (ret) + return ret; + + ret = platform_driver_register(&sgx_drv); + if (ret) + sgx_drv_subsys_exit(); + + return ret; +} +module_init(sgx_init); + +static void __exit sgx_exit(void) +{ + platform_driver_unregister(&sgx_drv); + sgx_drv_subsys_exit(); +} +module_exit(sgx_exit); diff --git a/arch/x86/kernel/cpu/sgx/driver/pte.c b/arch/x86/kernel/cpu/sgx/driver/pte.c new file mode 100644 index 000000000000..224a42bc0b1d --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/pte.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include "driver.h" + +static int sgx_test_and_clear_young_cb(pte_t *ptep, pgtable_t token, + unsigned long addr, void *data) +{ + pte_t pte; + int ret; + + ret = pte_young(*ptep); + if (ret) { + pte = pte_mkold(*ptep); + set_pte_at((struct mm_struct *)data, addr, ptep, pte); + } + + return ret; +} + +/** + * sgx_test_and_clear_young() - Test and reset the accessed bit + * @page: enclave page to be tested for recent access + * + * Checks the Access (A) bit from the PTE corresponding to the + * enclave page and clears it. Returns 1 if the page has been + * recently accessed and 0 if not. + */ +int sgx_test_and_clear_young(struct sgx_encl_page *page) +{ + unsigned long addr = SGX_ENCL_PAGE_ADDR(page); + struct sgx_encl *encl = page->encl; + struct vm_area_struct *vma; + int ret; + + ret = sgx_encl_find(encl->mm, addr, &vma); + if (ret) + return 0; + + if (encl != vma->vm_private_data) + return 0; + + return apply_to_page_range(vma->vm_mm, addr, PAGE_SIZE, + sgx_test_and_clear_young_cb, vma->vm_mm); +} + +static void sgx_ipi_cb(void *info) +{ +} + +void sgx_flush_cpus(struct sgx_encl *encl) +{ + on_each_cpu_mask(mm_cpumask(encl->mm), sgx_ipi_cb, NULL, 1); +} diff --git a/arch/x86/kernel/cpu/sgx/driver/vma.c b/arch/x86/kernel/cpu/sgx/driver/vma.c new file mode 100644 index 000000000000..e62e45e68c90 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/vma.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include "driver.h" + +static void sgx_vma_open(struct vm_area_struct *vma) +{ + struct sgx_encl *encl = vma->vm_private_data; + + if (!encl) + return; + + /* kref cannot underflow because ECREATE ioctl checks that there is only + * one single VMA for the enclave before proceeding. + */ + kref_get(&encl->refcount); +} + +static void sgx_vma_close(struct vm_area_struct *vma) +{ + struct sgx_encl *encl = vma->vm_private_data; + + if (!encl) + return; + + mutex_lock(&encl->lock); + sgx_invalidate(encl, true); + mutex_unlock(&encl->lock); + kref_put(&encl->refcount, sgx_encl_release); +} + +const struct vm_operations_struct sgx_vm_ops = { + .close = sgx_vma_close, + .open = sgx_vma_open, +}; From patchwork Fri Dec 21 23:11:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741121 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 A295513B5 for ; Fri, 21 Dec 2018 23:15:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8CE7A286B3 for ; Fri, 21 Dec 2018 23:15:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 79BC1286B6; Fri, 21 Dec 2018 23:15:04 +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 E7AEA28618 for ; Fri, 21 Dec 2018 23:15:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2403909AbeLUXPD (ORCPT ); Fri, 21 Dec 2018 18:15:03 -0500 Received: from mga09.intel.com ([134.134.136.24]:16862 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXPD (ORCPT ); Fri, 21 Dec 2018 18:15:03 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:15:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338605" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:14:53 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen , James Morris , "Serge E . Hallyn" , linux-security-module@vger.kernel.org Subject: [PATCH v18 19/25] x86/sgx: Add provisioning Date: Sat, 22 Dec 2018 01:11:48 +0200 Message-Id: <20181221231154.6120-20-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 In order to provide a mechanism for devilering provisoning rights: 1. Add a new file to the securityfs file called sgx/provision that works as a token for allowing an enclave to have the provisioning privileges. 2. Add a new ioctl called SGX_IOC_ENCLAVE_SET_ATTRIBUTE that accepts the following data structure: struct sgx_enclave_set_attribute { __u64 addr; __u64 token_fd; }; A daemon could sit on top of sgx/provision and send a file descriptor of this file to a process that needs to be able to provision enclaves. The way this API is used is more or less straight-forward. Lets assume that dev_fd is a handle to /dev/sgx and prov_fd is a handle to sgx/provision. You would allow SGX_IOC_ENCLAVE_CREATE to initialize an enclave with the PROVISIONKEY attribute by params.addr = ; params.token_fd = prov_fd; ioctl(dev_fd, SGX_IOC_ENCLAVE_SET_ATTRIBUTE, ¶ms); Cc: James Morris Cc: Serge E. Hallyn Cc: linux-security-module@vger.kernel.org Suggested-by: Andy Lutomirski Signed-off-by: Jarkko Sakkinen --- arch/x86/include/uapi/asm/sgx.h | 13 +++++++ arch/x86/kernel/cpu/sgx/driver/Makefile | 2 +- arch/x86/kernel/cpu/sgx/driver/driver.h | 5 +++ arch/x86/kernel/cpu/sgx/driver/fs.c | 49 +++++++++++++++++++++++++ arch/x86/kernel/cpu/sgx/driver/ioctl.c | 43 ++++++++++++++++++++++ arch/x86/kernel/cpu/sgx/driver/main.c | 7 ++++ 6 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 arch/x86/kernel/cpu/sgx/driver/fs.c diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h index aadf9c76e360..150a784db395 100644 --- a/arch/x86/include/uapi/asm/sgx.h +++ b/arch/x86/include/uapi/asm/sgx.h @@ -16,6 +16,8 @@ _IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page) #define SGX_IOC_ENCLAVE_INIT \ _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) +#define SGX_IOC_ENCLAVE_SET_ATTRIBUTE \ + _IOW(SGX_MAGIC, 0x03, struct sgx_enclave_set_attribute) /* IOCTL return values */ #define SGX_POWER_LOST_ENCLAVE 0x40000000 @@ -56,4 +58,15 @@ struct sgx_enclave_init { __u64 sigstruct; }; +/** + * struct sgx_enclave_set_attribute - parameter structure for the + * %SGX_IOC_ENCLAVE_INIT ioctl + * @addr: address within the ELRANGE + * @attribute_fd: file handle of the attribute file in the securityfs + */ +struct sgx_enclave_set_attribute { + __u64 addr; + __u64 attribute_fd; +}; + #endif /* _UAPI_ASM_X86_SGX_H */ diff --git a/arch/x86/kernel/cpu/sgx/driver/Makefile b/arch/x86/kernel/cpu/sgx/driver/Makefile index 2bd952cc8a65..0325de93d605 100644 --- a/arch/x86/kernel/cpu/sgx/driver/Makefile +++ b/arch/x86/kernel/cpu/sgx/driver/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_INTEL_SGX) += sgx.o -sgx-$(CONFIG_INTEL_SGX) += encl.o ioctl.o main.o pte.o vma.o +sgx-$(CONFIG_INTEL_SGX) += encl.o fs.o ioctl.o main.o pte.o vma.o diff --git a/arch/x86/kernel/cpu/sgx/driver/driver.h b/arch/x86/kernel/cpu/sgx/driver/driver.h index c9e40e090c58..e3487a077b6c 100644 --- a/arch/x86/kernel/cpu/sgx/driver/driver.h +++ b/arch/x86/kernel/cpu/sgx/driver/driver.h @@ -167,4 +167,9 @@ struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma, int sgx_test_and_clear_young(struct sgx_encl_page *page); void sgx_flush_cpus(struct sgx_encl *encl); +extern const struct file_operations sgx_fs_provision_fops; + +int sgx_fs_init(struct device *dev); +void sgx_fs_remove(void); + #endif /* __ARCH_X86_INTEL_SGX_H__ */ diff --git a/arch/x86/kernel/cpu/sgx/driver/fs.c b/arch/x86/kernel/cpu/sgx/driver/fs.c new file mode 100644 index 000000000000..b36b62a9cafb --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/fs.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include "driver.h" + +const struct file_operations sgx_fs_provision_fops; + +static struct dentry *sgx_fs; +static struct dentry *sgx_fs_provision; + +int sgx_fs_init(struct device *dev) +{ + int ret; + + sgx_fs = securityfs_create_dir(dev_name(dev), NULL); + if (IS_ERR(sgx_fs)) { + ret = PTR_ERR(sgx_fs); + goto err_sgx_fs; + } + + sgx_fs_provision = securityfs_create_file("provision", 0600, sgx_fs, + NULL, &sgx_fs_provision_fops); + if (IS_ERR(sgx_fs)) { + ret = PTR_ERR(sgx_fs_provision); + goto err_sgx_fs_provision; + } + + return 0; + +err_sgx_fs_provision: + securityfs_remove(sgx_fs); + sgx_fs_provision = NULL; + +err_sgx_fs: + sgx_fs = NULL; + return ret; +} + +void sgx_fs_remove(void) +{ + securityfs_remove(sgx_fs_provision); + securityfs_remove(sgx_fs); +} diff --git a/arch/x86/kernel/cpu/sgx/driver/ioctl.c b/arch/x86/kernel/cpu/sgx/driver/ioctl.c index 3a712950e116..d249a4329116 100644 --- a/arch/x86/kernel/cpu/sgx/driver/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/driver/ioctl.c @@ -193,6 +193,46 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, return ret; } +/** + * sgx_ioc_enclave_set_attribute - handler for %SGX_IOC_ENCLAVE_SET_ATTRIBUTE + * @filep: open file to /dev/sgx + * @cmd: the command value + * @arg: pointer to a struct sgx_enclave_set_attribute instance + * + * Sets an attribute matching the attribute file that is pointed by the + * parameter structure field attribute_fd. + * + * Return: 0 on success, -errno otherwise + */ +static long sgx_ioc_enclave_set_attribute(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + struct sgx_enclave_set_attribute *params = (void *)arg; + struct file *attribute_file; + struct sgx_encl *encl; + int ret; + + attribute_file = fget(params->attribute_fd); + if (!attribute_file->f_op) + return -EINVAL; + + if (attribute_file->f_op != &sgx_fs_provision_fops) { + ret = -EINVAL; + goto out; + } + + ret = sgx_encl_get(params->addr, &encl); + if (ret) + goto out; + + encl->attributes |= SGX_ATTR_PROVISIONKEY; + kref_put(&encl->refcount, sgx_encl_release); + +out: + fput(attribute_file); + return ret; +} + typedef long (*sgx_ioc_t)(struct file *filep, unsigned int cmd, unsigned long arg); @@ -212,6 +252,9 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) case SGX_IOC_ENCLAVE_INIT: handler = sgx_ioc_enclave_init; break; + case SGX_IOC_ENCLAVE_SET_ATTRIBUTE: + handler = sgx_ioc_enclave_set_attribute; + break; default: return -ENOIOCTLCMD; } diff --git a/arch/x86/kernel/cpu/sgx/driver/main.c b/arch/x86/kernel/cpu/sgx/driver/main.c index 19280863d703..ba125365a0d3 100644 --- a/arch/x86/kernel/cpu/sgx/driver/main.c +++ b/arch/x86/kernel/cpu/sgx/driver/main.c @@ -172,6 +172,10 @@ static int sgx_drv_init(struct device *parent) if (!sgx_encl_wq) return -ENOMEM; + ret = sgx_fs_init(&sgx_dev->ctrl_dev); + if (ret) + goto err_fs_init; + ret = cdev_device_add(&sgx_dev->ctrl_cdev, &sgx_dev->ctrl_dev); if (ret) goto err_device_add; @@ -179,6 +183,9 @@ static int sgx_drv_init(struct device *parent) return 0; err_device_add: + sgx_fs_remove(); + +err_fs_init: destroy_workqueue(sgx_encl_wq); return ret; } From patchwork Fri Dec 21 23:11:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741125 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 19E931399 for ; Fri, 21 Dec 2018 23:15:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 071D128618 for ; Fri, 21 Dec 2018 23:15:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EE47C286B6; Fri, 21 Dec 2018 23:15:15 +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 1AB1728618 for ; Fri, 21 Dec 2018 23:15:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730467AbeLUXPO (ORCPT ); Fri, 21 Dec 2018 18:15:14 -0500 Received: from mga06.intel.com ([134.134.136.31]:16600 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXPO (ORCPT ); Fri, 21 Dec 2018 18:15:14 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:15:14 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338666" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:15:04 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 20/25] x86/sgx: Add swapping code to the SGX driver Date: Sat, 22 Dec 2018 01:11:49 +0200 Message-Id: <20181221231154.6120-21-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Because the kernel is untrusted, swapping pages in/out of the Enclave Page Cache (EPC) has specialized requirements: * The kernel cannot directly access EPC memory, i.e. cannot copy data to/from the EPC. * To evict a page from the EPC, the kernel must "prove" to hardware that are no valid TLB entries for said page since a stale TLB entry would allow an attacker to bypass SGX access controls. * When loading a page back into the EPC, hardware must be able to verify the integrity and freshness of the data. * When loading an enclave page, e.g. regular pages and Thread Control Structures (TCS), hardware must be able to associate the page with a Secure Enclave Control Structure (SECS). To satisfy the above requirements, the CPU provides dedicated ENCLS functions to support paging data in/out of the EPC: * EBLOCK: Mark a page as blocked in the EPC Map (EPCM). Attempting to access a blocked page that misses the TLB will fault. * ETRACK: Activate blocking tracking. Hardware verifies that all translations for pages marked as "blocked" have been flushed from the TLB. * EPA: Add version array page to the EPC. As the name suggests, a VA page is an 512-entry array of version numbers that are used to uniquely identify pages evicted from the EPC. * EWB: Write back a page from EPC to memory, e.g. RAM. Software must supply a VA slot, memory to hold the a Paging Crypto Metadata (PCMD) of the page and obviously backing for the evicted page. * ELD{B,U}: Load a page in {un}blocked state from memory to EPC. The driver only uses the ELDU variant as there is no use case for loading a page as "blocked" in a bare metal environment. To top things off, all of the above ENCLS functions are subject to strict concurrency rules, e.g. many operations will #GP fault if two or more operations attempt to access common pages/structures. To put it succinctly, paging in/out of the EPC requires coordinating with the SGX driver where all of an enclave's tracking resides. But, simply shoving all reclaim logic into the driver is not desirable as doing so has unwanted long term implications: * Oversubscribing EPC to KVM guests, i.e. virtualizing SGX in KVM and swapping a guest's EPC pages (without the guest's cooperation) needs the same high level flows for reclaim but has painfully different semantics in the details. * Accounting EPC, i.e. adding an EPC cgroup controller, is desirable as EPC is effectively a specialized memory type and even more scarce than system memory. Providing a single touchpoint for EPC accounting regardless of end consumer greatly simplifies the EPC controller. * Allowing the userspace-facing driver to be built as a loaded module is desirable, e.g. for debug, testing and development. The cgroup infrastructure does not support dependencies on loadable modules. * Separating EPC swapping from the driver once it has been tightly coupled to the driver is non-trivial (speaking from experience). So, although the SGX driver is currently the sole consumer of EPC, encapsulate EPC swapping in the driver to minimize the dependencies between the core SGX code and driver, and do so in a way that can be extended to an abstracted interface with minimal effort. To that end, add functions to swap EPC pages to the driver. The user of these functions will be the core SGX subsystem, which will be enabled in a future patch. * sgx_encl_page_{get,put}() - Attempt to pin/unpin (the owner of) an EPC page so that it can be operated on by a reclaimer. * sgx_encl_page_reclaim() - Mark a page as being reclaimed. The page is considered reclaimable if it hasn't been accessed recently and it isn't reserved by the driver for other use. * sgx_encl_page_block() - EBLOCK an EPC page * sgx_encl_page_write() - Evict an EPC page to the regular memory via EWB. Activates ETRACK (via sgx_encl_track()) if necessary. Since we also need to be able to fault pages back into the EPC, add a page fault handler to allocate an EPC page and ELDU a previously evicted page. Cc: Andrew Morton Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Co-developed-by: Serge Ayoun Signed-off-by: Serge Ayoun Co-developed-by: Shay Katz-zamir Signed-off-by: Shay Katz-zamir --- arch/x86/kernel/cpu/sgx/driver/Makefile | 1 + arch/x86/kernel/cpu/sgx/driver/driver.h | 23 +++ arch/x86/kernel/cpu/sgx/driver/encl.c | 138 +++++++++++++-- arch/x86/kernel/cpu/sgx/driver/encl_page.c | 191 +++++++++++++++++++++ arch/x86/kernel/cpu/sgx/driver/fault.c | 170 ++++++++++++++++++ arch/x86/kernel/cpu/sgx/driver/va.c | 75 ++++++++ arch/x86/kernel/cpu/sgx/driver/vma.c | 15 ++ 7 files changed, 603 insertions(+), 10 deletions(-) create mode 100644 arch/x86/kernel/cpu/sgx/driver/encl_page.c create mode 100644 arch/x86/kernel/cpu/sgx/driver/fault.c create mode 100644 arch/x86/kernel/cpu/sgx/driver/va.c diff --git a/arch/x86/kernel/cpu/sgx/driver/Makefile b/arch/x86/kernel/cpu/sgx/driver/Makefile index 0325de93d605..96c905649bec 100644 --- a/arch/x86/kernel/cpu/sgx/driver/Makefile +++ b/arch/x86/kernel/cpu/sgx/driver/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_INTEL_SGX) += sgx.o sgx-$(CONFIG_INTEL_SGX) += encl.o fs.o ioctl.o main.o pte.o vma.o +sgx-$(CONFIG_INTEL_SGX) += encl_page.o fault.o va.o diff --git a/arch/x86/kernel/cpu/sgx/driver/driver.h b/arch/x86/kernel/cpu/sgx/driver/driver.h index e3487a077b6c..f8e52d1c8ccc 100644 --- a/arch/x86/kernel/cpu/sgx/driver/driver.h +++ b/arch/x86/kernel/cpu/sgx/driver/driver.h @@ -38,10 +38,23 @@ #define SGX_EINIT_SLEEP_TIME 20 #define SGX_VA_SLOT_COUNT 512 +#define SGX_VA_SLOT_COUNT 512 + +struct sgx_va_page { + struct sgx_epc_page *epc_page; + DECLARE_BITMAP(slots, SGX_VA_SLOT_COUNT); + struct list_head list; +}; + /** * enum sgx_encl_page_desc - defines bits for an enclave page's descriptor * %SGX_ENCL_PAGE_TCS: The page is a TCS page. * %SGX_ENCL_PAGE_LOADED: The page is not swapped. + * %SGX_ENCL_PAGE_RESERVED: The page cannot be reclaimed. + * %SGX_ENCL_PAGE_RECLAIMED: The page is in the process of being + * reclaimed. + * %SGX_ENCL_PAGE_VA_OFFSET_MASK: Holds the offset in the Version Array + * (VA) page for a swapped page. * %SGX_ENCL_PAGE_ADDR_MASK: Holds the virtual address of the page. * * The page address for SECS is zero and is used by the subsystem to recognize @@ -51,6 +64,9 @@ enum sgx_encl_page_desc { SGX_ENCL_PAGE_TCS = BIT(0), SGX_ENCL_PAGE_LOADED = BIT(1), /* Bits 11:3 are available when the page is not swapped. */ + SGX_ENCL_PAGE_RESERVED = BIT(3), + SGX_ENCL_PAGE_RECLAIMED = BIT(4), + SGX_ENCL_PAGE_VA_OFFSET_MASK = GENMASK_ULL(11, 3), SGX_ENCL_PAGE_ADDR_MASK = PAGE_MASK, }; @@ -89,6 +105,7 @@ struct sgx_encl { unsigned long base; unsigned long size; unsigned long ssaframesize; + struct list_head va_pages; struct radix_tree_root page_tree; struct list_head add_page_reqs; struct work_struct work; @@ -152,6 +169,8 @@ int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, struct sgx_einittoken *einittoken); void sgx_encl_block(struct sgx_encl_page *encl_page); void sgx_encl_track(struct sgx_encl *encl); +int sgx_encl_load_page(struct sgx_encl_page *encl_page, + struct sgx_epc_page *epc_page); void sgx_encl_release(struct kref *ref); pgoff_t sgx_encl_get_index(struct sgx_encl *encl, struct sgx_encl_page *page); @@ -166,6 +185,10 @@ struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma, int sgx_test_and_clear_young(struct sgx_encl_page *page); void sgx_flush_cpus(struct sgx_encl *encl); +struct sgx_epc_page *sgx_alloc_va_page(void); +unsigned int sgx_alloc_va_slot(struct sgx_va_page *va_page); +void sgx_free_va_slot(struct sgx_va_page *va_page, unsigned int offset); +bool sgx_va_page_full(struct sgx_va_page *va_page); extern const struct file_operations sgx_fs_provision_fops; diff --git a/arch/x86/kernel/cpu/sgx/driver/encl.c b/arch/x86/kernel/cpu/sgx/driver/encl.c index 0ea85c77d437..4ae7674e9c8c 100644 --- a/arch/x86/kernel/cpu/sgx/driver/encl.c +++ b/arch/x86/kernel/cpu/sgx/driver/encl.c @@ -53,6 +53,19 @@ int sgx_encl_find(struct mm_struct *mm, unsigned long addr, return encl ? 0 : -ENOENT; } +static void sgx_free_va_pages(struct sgx_encl *encl) +{ + struct sgx_va_page *va_page; + + while (!list_empty(&encl->va_pages)) { + va_page = list_first_entry(&encl->va_pages, struct sgx_va_page, + list); + list_del(&va_page->list); + sgx_free_page(va_page->epc_page); + kfree(va_page); + } +} + /** * sgx_invalidate - kill an enclave * @encl: an &sgx_encl instance @@ -87,7 +100,12 @@ void sgx_invalidate(struct sgx_encl *encl, bool flush_cpus) radix_tree_for_each_slot(slot, &encl->page_tree, &iter, 0) { entry = *slot; - if (entry->desc & SGX_ENCL_PAGE_LOADED) { + /* + * If the page has RECLAIMED set, the reclaimer effectively + * owns the page, i.e. we need to let the reclaimer free it. + */ + if ((entry->desc & SGX_ENCL_PAGE_LOADED) && + !(entry->desc & SGX_ENCL_PAGE_RECLAIMED)) { if (!__sgx_free_page(entry->epc_page)) { encl->secs_child_cnt--; entry->desc &= ~SGX_ENCL_PAGE_LOADED; @@ -100,6 +118,7 @@ void sgx_invalidate(struct sgx_encl *encl, bool flush_cpus) encl->secs.desc &= ~SGX_ENCL_PAGE_LOADED; sgx_free_page(encl->secs.epc_page); } + sgx_free_va_pages(encl); } static bool sgx_process_add_page_req(struct sgx_add_page_req *req, @@ -299,6 +318,51 @@ static const struct mmu_notifier_ops sgx_mmu_notifier_ops = { .release = sgx_mmu_notifier_release, }; +static int sgx_encl_grow(struct sgx_encl *encl) +{ + struct sgx_va_page *va_page; + int ret; + + BUILD_BUG_ON(SGX_VA_SLOT_COUNT != + (SGX_ENCL_PAGE_VA_OFFSET_MASK >> 3) + 1); + + mutex_lock(&encl->lock); + if (encl->flags & SGX_ENCL_DEAD) { + mutex_unlock(&encl->lock); + return -EFAULT; + } + + if (!(encl->page_cnt % SGX_VA_SLOT_COUNT)) { + mutex_unlock(&encl->lock); + + va_page = kzalloc(sizeof(*va_page), GFP_KERNEL); + if (!va_page) + return -ENOMEM; + va_page->epc_page = sgx_alloc_va_page(); + if (IS_ERR(va_page->epc_page)) { + ret = PTR_ERR(va_page->epc_page); + kfree(va_page); + return ret; + } + + mutex_lock(&encl->lock); + if (encl->flags & SGX_ENCL_DEAD) { + sgx_free_page(va_page->epc_page); + kfree(va_page); + mutex_unlock(&encl->lock); + return -EFAULT; + } else if (encl->page_cnt % SGX_VA_SLOT_COUNT) { + sgx_free_page(va_page->epc_page); + kfree(va_page); + } else { + list_add(&va_page->list, &encl->va_pages); + } + } + encl->page_cnt++; + mutex_unlock(&encl->lock); + return 0; +} + /** * sgx_encl_alloc - allocate memory for an enclave and set attributes * @@ -314,6 +378,7 @@ static const struct mmu_notifier_ops sgx_mmu_notifier_ops = { */ struct sgx_encl *sgx_encl_alloc(struct sgx_secs *secs) { + unsigned long backing_size = secs->size + PAGE_SIZE; unsigned long ssaframesize; struct sgx_encl *encl; unsigned long backing; @@ -323,23 +388,24 @@ struct sgx_encl *sgx_encl_alloc(struct sgx_secs *secs) if (sgx_validate_secs(secs, ssaframesize)) return ERR_PTR(-EINVAL); - backing = vm_mmap(NULL, 0, secs->size + PAGE_SIZE, + backing = vm_mmap(NULL, 0, backing_size + (backing_size >> 5), PROT_READ | PROT_WRITE, MAP_PRIVATE, 0); if (IS_ERR((void *)backing)) { ret = PTR_ERR((void *)backing); - goto out_err; + goto err_backing; } encl = kzalloc(sizeof(*encl), GFP_KERNEL); if (!encl) { ret = -ENOMEM; - goto out_backing; + goto err_alloc; } encl->attributes = SGX_ATTR_MODE64BIT | SGX_ATTR_DEBUG; encl->xfrm = secs->xfrm; kref_init(&encl->refcount); INIT_LIST_HEAD(&encl->add_page_reqs); + INIT_LIST_HEAD(&encl->va_pages); INIT_RADIX_TREE(&encl->page_tree, GFP_KERNEL); mutex_init(&encl->lock); INIT_WORK(&encl->work, sgx_add_page_worker); @@ -351,10 +417,10 @@ struct sgx_encl *sgx_encl_alloc(struct sgx_secs *secs) return encl; -out_backing: - vm_munmap((unsigned long)backing, secs->size + PAGE_SIZE); +err_alloc: + vm_munmap((unsigned long)backing, backing_size + (backing_size >> 5)); -out_err: +err_backing: return ERR_PTR(ret); } @@ -406,6 +472,10 @@ int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs) encl->secs.desc |= SGX_ENCL_PAGE_LOADED; encl->tgid = get_pid(task_tgid(current)); + ret = sgx_encl_grow(encl); + if (ret) + return ret; + pginfo.addr = 0; pginfo.contents = (unsigned long)secs; pginfo.metadata = (unsigned long)&secinfo; @@ -626,6 +696,10 @@ int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr, void *data, return ret; } + ret = sgx_encl_grow(encl); + if (ret) + return ret; + down_read(¤t->mm->mmap_sem); mutex_lock(&encl->lock); @@ -753,15 +827,59 @@ int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, return ret; } +/** + * sgx_encl_block - block an enclave page + * @encl_page: an enclave page + * + * Changes the state of the associated EPC page to blocked. + */ +void sgx_encl_block(struct sgx_encl_page *encl_page) +{ + unsigned long addr = SGX_ENCL_PAGE_ADDR(encl_page); + struct sgx_encl *encl = encl_page->encl; + struct vm_area_struct *vma; + int ret; + + if (encl->flags & SGX_ENCL_DEAD) + return; + + ret = sgx_encl_find(encl->mm, addr, &vma); + if (!ret && encl == vma->vm_private_data) + zap_vma_ptes(vma, addr, PAGE_SIZE); + + ret = __eblock(sgx_epc_addr(encl_page->epc_page)); + SGX_INVD(ret, encl, "EBLOCK returned %d (0x%x)", ret, ret); +} + +/** + * sgx_encl_track - start tracking pages in the blocked state + * @encl: an enclave + * + * Start blocking accesses for pages in the blocked state for threads that enter + * inside the enclave by executing the ETRACK leaf instruction. This starts a + * shootdown sequence for threads that entered before ETRACK. + * + * The caller must take care (with an IPI when necessary) to make sure that the + * previous shootdown sequence was completed before calling this function. If + * this is not the case, the callee prints a critical error to the klog and + * kills the enclave. + */ +void sgx_encl_track(struct sgx_encl *encl) +{ + int ret = __etrack(sgx_epc_addr(encl->secs.epc_page)); + + SGX_INVD(ret, encl, "ETRACK returned %d (0x%x)", ret, ret); +} + static void sgx_encl_release_worker(struct work_struct *work) { struct sgx_encl *encl = container_of(work, struct sgx_encl, work); unsigned long backing_size = encl->size + PAGE_SIZE; - if (encl->flags & SGX_ENCL_MM_RELEASED) { + if (!(encl->flags & SGX_ENCL_MM_RELEASED)) { down_write(&encl->mm->mmap_sem); - do_munmap(encl->mm, (unsigned long)encl->backing, backing_size, - NULL); + do_munmap(encl->mm, (unsigned long)encl->backing, backing_size + + (backing_size >> 5), NULL); up_write(&encl->mm->mmap_sem); } diff --git a/arch/x86/kernel/cpu/sgx/driver/encl_page.c b/arch/x86/kernel/cpu/sgx/driver/encl_page.c new file mode 100644 index 000000000000..1bd27444a1f9 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/encl_page.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include "driver.h" + +static inline struct sgx_encl_page *to_encl_page(struct sgx_epc_page *epc_page) +{ + WARN_ON_ONCE(1); + return NULL; +} + +bool sgx_encl_page_get(struct sgx_epc_page *epc_page) +{ + struct sgx_encl_page *encl_page = to_encl_page(epc_page); + struct sgx_encl *encl = encl_page->encl; + + return kref_get_unless_zero(&encl->refcount) != 0; +} + +void sgx_encl_page_put(struct sgx_epc_page *epc_page) +{ + struct sgx_encl_page *encl_page = to_encl_page(epc_page); + struct sgx_encl *encl = encl_page->encl; + + kref_put(&encl->refcount, sgx_encl_release); +} + +bool sgx_encl_page_reclaim(struct sgx_epc_page *epc_page) +{ + struct sgx_encl_page *encl_page = to_encl_page(epc_page); + struct sgx_encl *encl = encl_page->encl; + bool ret; + + down_read(&encl->mm->mmap_sem); + mutex_lock(&encl->lock); + + if (encl->flags & SGX_ENCL_DEAD) + ret = true; + else if (encl_page->desc & SGX_ENCL_PAGE_RESERVED) + ret = false; + else + ret = !sgx_test_and_clear_young(encl_page); + if (ret) + encl_page->desc |= SGX_ENCL_PAGE_RECLAIMED; + + mutex_unlock(&encl->lock); + up_read(&encl->mm->mmap_sem); + + return ret; +} + +void sgx_encl_page_block(struct sgx_epc_page *epc_page) +{ + struct sgx_encl_page *encl_page = to_encl_page(epc_page); + struct sgx_encl *encl = encl_page->encl; + + down_read(&encl->mm->mmap_sem); + mutex_lock(&encl->lock); + sgx_encl_block(encl_page); + mutex_unlock(&encl->lock); + up_read(&encl->mm->mmap_sem); +} + +static int sgx_ewb(struct sgx_encl *encl, struct sgx_epc_page *epc_page, + struct sgx_va_page *va_page, unsigned int va_offset) +{ + struct sgx_encl_page *encl_page = to_encl_page(epc_page); + pgoff_t page_index = sgx_encl_get_index(encl, encl_page); + unsigned long pcmd_offset = + (page_index & (PAGE_SIZE / sizeof(struct sgx_pcmd) - 1)) * + sizeof(struct sgx_pcmd); + unsigned long page_addr = encl->backing + page_index * PAGE_SIZE; + unsigned long pcmd_addr = encl->backing + encl->size + PAGE_SIZE + + ((page_index * PAGE_SIZE) >> 5); + struct sgx_pageinfo pginfo; + struct page *backing; + struct page *pcmd; + int ret; + + ret = get_user_pages_remote(NULL, encl->mm, page_addr, 1, FOLL_WRITE, + &backing, NULL, NULL); + if (ret < 0) + goto err_backing; + + ret = get_user_pages_remote(NULL, encl->mm, pcmd_addr, 1, FOLL_WRITE, + &pcmd, NULL, NULL); + if (ret < 0) + goto err_pcmd; + + pginfo.addr = 0; + pginfo.contents = (unsigned long)kmap_atomic(backing); + pginfo.metadata = (unsigned long)kmap_atomic(pcmd) + pcmd_offset; + pginfo.secs = 0; + ret = __ewb(&pginfo, sgx_epc_addr(epc_page), + sgx_epc_addr(va_page->epc_page) + va_offset); + kunmap_atomic((void *)(unsigned long)(pginfo.metadata - pcmd_offset)); + kunmap_atomic((void *)(unsigned long)pginfo.contents); + + set_page_dirty(pcmd); + put_page(pcmd); + set_page_dirty(backing); + +err_pcmd: + put_page(backing); + +err_backing: + return ret; +} + +/** + * sgx_write_page - write a page to the regular memory + * + * Writes an EPC page to the shmem file associated with the enclave. Flushes + * CPUs and retries if there are hardware threads that can potentially have TLB + * entries to the page (indicated by SGX_NOT_TRACKED). Clears the reserved flag + * after the page is swapped. + * + * @epc_page: an EPC page + */ +static void sgx_write_page(struct sgx_epc_page *epc_page, bool do_free) +{ + struct sgx_encl_page *encl_page = to_encl_page(epc_page); + struct sgx_encl *encl = encl_page->encl; + struct sgx_va_page *va_page; + unsigned int va_offset; + int ret; + + encl_page->desc &= ~(SGX_ENCL_PAGE_LOADED | SGX_ENCL_PAGE_RECLAIMED); + + if (!(encl->flags & SGX_ENCL_DEAD)) { + va_page = list_first_entry(&encl->va_pages, struct sgx_va_page, + list); + va_offset = sgx_alloc_va_slot(va_page); + if (sgx_va_page_full(va_page)) + list_move_tail(&va_page->list, &encl->va_pages); + + ret = sgx_ewb(encl, epc_page, va_page, va_offset); + if (ret == SGX_NOT_TRACKED) { + sgx_encl_track(encl); + ret = sgx_ewb(encl, epc_page, va_page, va_offset); + if (ret == SGX_NOT_TRACKED) { + /* slow path, IPI needed */ + sgx_flush_cpus(encl); + ret = sgx_ewb(encl, epc_page, va_page, + va_offset); + } + } + + /* Invalidate silently as the backing VMA has been kicked out. + */ + if (ret < 0) + sgx_invalidate(encl, true); + else + SGX_INVD(ret, encl, "EWB returned %d (0x%x)", + ret, ret); + + encl_page->desc |= va_offset; + encl_page->va_page = va_page; + } else if (!do_free) { + ret = __eremove(sgx_epc_addr(epc_page)); + WARN(ret, "EREMOVE returned %d\n", ret); + } + + if (do_free) + sgx_free_page(epc_page); +} + +void sgx_encl_page_write(struct sgx_epc_page *epc_page) +{ + struct sgx_encl_page *encl_page = to_encl_page(epc_page); + struct sgx_encl *encl = encl_page->encl; + + down_read(&encl->mm->mmap_sem); + mutex_lock(&encl->lock); + + sgx_write_page(epc_page, false); + encl->secs_child_cnt--; + if (!encl->secs_child_cnt && + (encl->flags & (SGX_ENCL_DEAD | SGX_ENCL_INITIALIZED))) + sgx_write_page(encl->secs.epc_page, true); + + mutex_unlock(&encl->lock); + up_read(&encl->mm->mmap_sem); +} diff --git a/arch/x86/kernel/cpu/sgx/driver/fault.c b/arch/x86/kernel/cpu/sgx/driver/fault.c new file mode 100644 index 000000000000..b30c4b837f0f --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/fault.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include "driver.h" + +static int sgx_eldu(struct sgx_encl_page *encl_page, + struct sgx_epc_page *epc_page) +{ + unsigned long addr = SGX_ENCL_PAGE_ADDR(encl_page); + unsigned long va_offset = SGX_ENCL_PAGE_VA_OFFSET(encl_page); + struct sgx_encl *encl = encl_page->encl; + pgoff_t page_index = sgx_encl_get_index(encl, encl_page); + unsigned long pcmd_offset = + (page_index & (PAGE_SIZE / sizeof(struct sgx_pcmd) - 1)) * + sizeof(struct sgx_pcmd); + unsigned long page_addr = encl->backing + page_index * PAGE_SIZE; + unsigned long pcmd_addr = encl->backing + encl->size + PAGE_SIZE + + ((page_index * PAGE_SIZE) >> 5); + struct sgx_pageinfo pginfo; + struct page *backing; + struct page *pcmd; + int ret; + + ret = get_user_pages_remote(NULL, encl->mm, page_addr, 1, 0, &backing, + NULL, NULL); + if (ret < 0) + goto err_backing; + + ret = get_user_pages_remote(NULL, encl->mm, pcmd_addr, 1, 0, &pcmd, + NULL, NULL); + if (ret < 0) + goto err_pcmd; + + pginfo.addr = addr; + pginfo.contents = (unsigned long)kmap_atomic(backing); + pginfo.metadata = (unsigned long)kmap_atomic(pcmd) + pcmd_offset; + pginfo.secs = addr ? (unsigned long)sgx_epc_addr(encl->secs.epc_page) : + 0; + + ret = __eldu(&pginfo, sgx_epc_addr(epc_page), + sgx_epc_addr(encl_page->va_page->epc_page) + va_offset); + if (ret) { + SGX_INVD(ret, encl, "ELDU returned %d (0x%x)", ret, ret); + ret = encls_to_err(ret); + } + + kunmap_atomic((void *)(unsigned long)(pginfo.metadata - pcmd_offset)); + kunmap_atomic((void *)(unsigned long)pginfo.contents); + + put_page(pcmd); + +err_pcmd: + put_page(backing); + +err_backing: + /* Invalidate silently as the backing VMA has been kicked out. */ + if (ret < 0) { + sgx_invalidate(encl, true); + return 0; + } + + return ret; +} + +static struct sgx_epc_page *sgx_load_page(struct sgx_encl_page *encl_page) +{ + unsigned long va_offset = SGX_ENCL_PAGE_VA_OFFSET(encl_page); + struct sgx_encl *encl = encl_page->encl; + struct sgx_epc_page *epc_page; + int ret; + + epc_page = sgx_alloc_page(); + if (IS_ERR(epc_page)) + return epc_page; + + ret = sgx_eldu(encl_page, epc_page); + if (ret) { + sgx_free_page(epc_page); + return ERR_PTR(ret); + } + + sgx_free_va_slot(encl_page->va_page, va_offset); + list_move(&encl_page->va_page->list, &encl->va_pages); + encl_page->desc &= ~SGX_ENCL_PAGE_VA_OFFSET_MASK; + encl_page->epc_page = epc_page; + encl_page->desc |= SGX_ENCL_PAGE_LOADED; + + return epc_page; +} + +static struct sgx_encl_page *sgx_try_fault_page(struct vm_area_struct *vma, + unsigned long addr, + bool do_reserve) +{ + struct sgx_encl *encl = vma->vm_private_data; + struct sgx_epc_page *epc_page; + struct sgx_encl_page *entry; + int rc = 0; + + if ((encl->flags & SGX_ENCL_DEAD) || + !(encl->flags & SGX_ENCL_INITIALIZED)) + return ERR_PTR(-EFAULT); + + entry = radix_tree_lookup(&encl->page_tree, addr >> PAGE_SHIFT); + if (!entry) + return ERR_PTR(-EFAULT); + + /* Page is already resident in the EPC. */ + if (entry->desc & SGX_ENCL_PAGE_LOADED) { + if (entry->desc & SGX_ENCL_PAGE_RESERVED) { + sgx_dbg(encl, "EPC page 0x%p is already reserved\n", + (void *)SGX_ENCL_PAGE_ADDR(entry)); + return ERR_PTR(-EBUSY); + } + if (entry->desc & SGX_ENCL_PAGE_RECLAIMED) { + sgx_dbg(encl, "EPC page 0x%p is being reclaimed\n", + (void *)SGX_ENCL_PAGE_ADDR(entry)); + return ERR_PTR(-EBUSY); + } + if (do_reserve) + entry->desc |= SGX_ENCL_PAGE_RESERVED; + return entry; + } + + if (!(encl->secs.desc & SGX_ENCL_PAGE_LOADED)) { + epc_page = sgx_load_page(&encl->secs); + if (IS_ERR(epc_page)) + return ERR_CAST(epc_page); + } + epc_page = sgx_load_page(entry); + if (IS_ERR(epc_page)) + return ERR_CAST(epc_page); + + encl->secs_child_cnt++; + sgx_test_and_clear_young(entry); + if (do_reserve) + entry->desc |= SGX_ENCL_PAGE_RESERVED; + + rc = vmf_insert_pfn(vma, addr, PFN_DOWN(entry->epc_page->desc)); + if (rc != VM_FAULT_NOPAGE) { + sgx_invalidate(encl, true); + return ERR_PTR(-EFAULT); + } + + return entry; +} + +struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma, + unsigned long addr, bool do_reserve) +{ + struct sgx_encl *encl = vma->vm_private_data; + struct sgx_encl_page *entry; + + /* If process was forked, VMA is still there but vm_private_data is set + * to NULL. + */ + if (!encl) + return ERR_PTR(-EFAULT); + do { + mutex_lock(&encl->lock); + entry = sgx_try_fault_page(vma, addr, do_reserve); + mutex_unlock(&encl->lock); + if (!do_reserve) + break; + } while (PTR_ERR(entry) == -EBUSY); + + return entry; +} diff --git a/arch/x86/kernel/cpu/sgx/driver/va.c b/arch/x86/kernel/cpu/sgx/driver/va.c new file mode 100644 index 000000000000..f57aacefb6eb --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/va.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include "driver.h" + +/** + * sgx_alloc_page - allocate a VA page + * + * Allocates an &sgx_epc_page instance and converts it to a VA page. + * + * Return: + * a &struct sgx_va_page instance, + * -errno otherwise + */ +struct sgx_epc_page *sgx_alloc_va_page(void) +{ + struct sgx_epc_page *epc_page; + int ret; + + epc_page = sgx_alloc_page(); + if (IS_ERR(epc_page)) + return ERR_CAST(epc_page); + + ret = __epa(sgx_epc_addr(epc_page)); + if (ret) { + WARN_ONCE(1, "sgx: EPA returned %d (0x%x)", ret, ret); + sgx_free_page(epc_page); + return ERR_PTR(encls_to_err(ret)); + } + + return epc_page; +} + +/** + * sgx_alloc_va_slot - allocate a VA slot + * @va_page: a &struct sgx_va_page instance + * + * Allocates a slot from a &struct sgx_va_page instance. + * + * Return: offset of the slot inside the VA page + */ +unsigned int sgx_alloc_va_slot(struct sgx_va_page *va_page) +{ + int slot = find_first_zero_bit(va_page->slots, SGX_VA_SLOT_COUNT); + + if (slot < SGX_VA_SLOT_COUNT) + set_bit(slot, va_page->slots); + + return slot << 3; +} + +/** + * sgx_free_va_slot - free a VA slot + * @va_page: a &struct sgx_va_page instance + * @offset: offset of the slot inside the VA page + * + * Frees a slot from a &struct sgx_va_page instance. + */ +void sgx_free_va_slot(struct sgx_va_page *va_page, unsigned int offset) +{ + clear_bit(offset >> 3, va_page->slots); +} + +/** + * sgx_va_page_full - is the VA page full? + * @va_page: a &struct sgx_va_page instance + * + * Return: true if all slots have been taken + */ +bool sgx_va_page_full(struct sgx_va_page *va_page) +{ + int slot = find_first_zero_bit(va_page->slots, SGX_VA_SLOT_COUNT); + + return slot == SGX_VA_SLOT_COUNT; +} diff --git a/arch/x86/kernel/cpu/sgx/driver/vma.c b/arch/x86/kernel/cpu/sgx/driver/vma.c index e62e45e68c90..da7b4080a4a6 100644 --- a/arch/x86/kernel/cpu/sgx/driver/vma.c +++ b/arch/x86/kernel/cpu/sgx/driver/vma.c @@ -37,7 +37,22 @@ static void sgx_vma_close(struct vm_area_struct *vma) kref_put(&encl->refcount, sgx_encl_release); } +static int sgx_vma_fault(struct vm_fault *vmf) +{ + unsigned long addr = (unsigned long)vmf->address; + struct vm_area_struct *vma = vmf->vma; + struct sgx_encl_page *entry; + + entry = sgx_fault_page(vma, addr, 0); + + if (!IS_ERR(entry) || PTR_ERR(entry) == -EBUSY) + return VM_FAULT_NOPAGE; + else + return VM_FAULT_SIGBUS; +} + const struct vm_operations_struct sgx_vm_ops = { .close = sgx_vma_close, .open = sgx_vma_open, + .fault = sgx_vma_fault, }; From patchwork Fri Dec 21 23:11:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741127 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 7B8BA1399 for ; Fri, 21 Dec 2018 23:15:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 697C028618 for ; Fri, 21 Dec 2018 23:15:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5D2B0286B6; Fri, 21 Dec 2018 23:15:24 +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 BBAF628618 for ; Fri, 21 Dec 2018 23:15:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388562AbeLUXPX (ORCPT ); Fri, 21 Dec 2018 18:15:23 -0500 Received: from mga17.intel.com ([192.55.52.151]:17725 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXPX (ORCPT ); Fri, 21 Dec 2018 18:15:23 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:15:23 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338694" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:15:14 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 21/25] x86/sgx: Add a simple swapper for the EPC memory manager Date: Sat, 22 Dec 2018 01:11:50 +0200 Message-Id: <20181221231154.6120-22-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Wire up the EPC manager's reclaim flow to the SGX driver's swapping functionality. In the long term there will be multiple users of the EPC manager, e.g. SGX driver and KVM, thus the interface between the EPC manager and the driver is fairly genericized and decoupled. But to avoid adding unusued infrastructure, do not add any indirection between the EPC manager and the SGX driver. This has the unfortunate and odd side effect of preventing the SGX driver from being compiled as a loadable module. However, this should be a temporary situation that is remedied when a second user of EPC is added, i.e. KVM. The swapper thread ksgxswapd reclaims pages on the event when the number of free EPC pages goes below %SGX_NR_LOW_PAGES up until it reaches %SGX_NR_HIGH_PAGES. Pages are reclaimed in LRU fashion from a global list. The consumers take care of calling EBLOCK (block page from new accesses), ETRACK (restart counting the entering hardware threads) and EWB (write page to the regular memory) because executing these operations usually (if not always) requires to do some subsystem-internal locking operations. Cc: Andrew Morton Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Co-developed-by: Serge Ayoun Signed-off-by: Serge Ayoun Co-developed-by: Shay Katz-zamir Signed-off-by: Shay Katz-zamir --- arch/x86/Kconfig | 1 + arch/x86/include/asm/sgx.h | 15 +- arch/x86/kernel/cpu/sgx/driver/encl.c | 5 +- arch/x86/kernel/cpu/sgx/driver/encl_page.c | 3 +- arch/x86/kernel/cpu/sgx/driver/fault.c | 3 +- arch/x86/kernel/cpu/sgx/driver/va.c | 2 +- arch/x86/kernel/cpu/sgx/main.c | 241 +++++++++++++++++++-- 7 files changed, 250 insertions(+), 20 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 9673d74dc744..267df58d9704 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1922,6 +1922,7 @@ config X86_INTEL_MEMORY_PROTECTION_KEYS config INTEL_SGX_CORE bool "Intel SGX core functionality" depends on X86_64 && CPU_SUP_INTEL + select INTEL_SGX help Intel(R) SGX is a set of CPU instructions that can be used by applications to set aside private regions of code and data. The code diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h index ad4a8ea57bd5..d4f61d1c5c2a 100644 --- a/arch/x86/include/asm/sgx.h +++ b/arch/x86/include/asm/sgx.h @@ -12,6 +12,7 @@ struct sgx_epc_page { unsigned long desc; + void *owner; struct list_head list; }; @@ -41,9 +42,14 @@ extern struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; * physical memory. The existing and near-future * hardware defines at most eight sections, hence * three bits to hold a section. + * %SGX_EPC_PAGE_RECLAIMABLE: The page has been been marked as reclaimable. + * Pages need to be colored this way because a page + * can be out of the active page list in the + * process of being swapped out. */ enum sgx_epc_page_desc { SGX_EPC_SECTION_MASK = GENMASK_ULL(3, 0), + SGX_EPC_PAGE_RECLAIMABLE = BIT(4), /* bits 12-63 are reserved for the physical page address of the page */ }; @@ -303,10 +309,17 @@ static inline int __emodt(struct sgx_secinfo *secinfo, void *addr) return __encls_ret_2(SGX_EMODT, secinfo, addr); } -struct sgx_epc_page *sgx_alloc_page(void); +struct sgx_epc_page *sgx_alloc_page(void *owner, bool reclaim); 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); +void sgx_page_reclaimable(struct sgx_epc_page *page); + +bool sgx_encl_page_get(struct sgx_epc_page *epc_page); +void sgx_encl_page_put(struct sgx_epc_page *epc_page); +bool sgx_encl_page_reclaim(struct sgx_epc_page *epc_page); +void sgx_encl_page_block(struct sgx_epc_page *epc_page); +void sgx_encl_page_write(struct sgx_epc_page *epc_page); #endif /* _ASM_X86_SGX_H */ diff --git a/arch/x86/kernel/cpu/sgx/driver/encl.c b/arch/x86/kernel/cpu/sgx/driver/encl.c index 4ae7674e9c8c..ded5105f2a8d 100644 --- a/arch/x86/kernel/cpu/sgx/driver/encl.c +++ b/arch/x86/kernel/cpu/sgx/driver/encl.c @@ -193,6 +193,7 @@ static bool sgx_process_add_page_req(struct sgx_add_page_req *req, encl_page->desc |= SGX_ENCL_PAGE_LOADED; encl->secs_child_cnt++; sgx_test_and_clear_young(encl_page); + sgx_page_reclaimable(encl_page->epc_page); return true; } @@ -223,7 +224,7 @@ static void sgx_add_page_worker(struct work_struct *work) if (skip_rest) goto next; - epc_page = sgx_alloc_page(); + epc_page = sgx_alloc_page(req->encl_page, true); down_read(&encl->mm->mmap_sem); mutex_lock(&encl->lock); @@ -461,7 +462,7 @@ int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs) struct sgx_epc_page *secs_epc; long ret; - secs_epc = sgx_alloc_page(); + secs_epc = sgx_alloc_page(&encl->secs, true); if (IS_ERR(secs_epc)) { ret = PTR_ERR(secs_epc); return ret; diff --git a/arch/x86/kernel/cpu/sgx/driver/encl_page.c b/arch/x86/kernel/cpu/sgx/driver/encl_page.c index 1bd27444a1f9..58da36b0e39c 100644 --- a/arch/x86/kernel/cpu/sgx/driver/encl_page.c +++ b/arch/x86/kernel/cpu/sgx/driver/encl_page.c @@ -12,8 +12,7 @@ static inline struct sgx_encl_page *to_encl_page(struct sgx_epc_page *epc_page) { - WARN_ON_ONCE(1); - return NULL; + return (struct sgx_encl_page *)epc_page->owner; } bool sgx_encl_page_get(struct sgx_epc_page *epc_page) diff --git a/arch/x86/kernel/cpu/sgx/driver/fault.c b/arch/x86/kernel/cpu/sgx/driver/fault.c index b30c4b837f0f..ec5b76fdc709 100644 --- a/arch/x86/kernel/cpu/sgx/driver/fault.c +++ b/arch/x86/kernel/cpu/sgx/driver/fault.c @@ -71,7 +71,7 @@ static struct sgx_epc_page *sgx_load_page(struct sgx_encl_page *encl_page) struct sgx_epc_page *epc_page; int ret; - epc_page = sgx_alloc_page(); + epc_page = sgx_alloc_page(encl_page, false); if (IS_ERR(epc_page)) return epc_page; @@ -135,6 +135,7 @@ static struct sgx_encl_page *sgx_try_fault_page(struct vm_area_struct *vma, encl->secs_child_cnt++; sgx_test_and_clear_young(entry); + sgx_page_reclaimable(entry->epc_page); if (do_reserve) entry->desc |= SGX_ENCL_PAGE_RESERVED; diff --git a/arch/x86/kernel/cpu/sgx/driver/va.c b/arch/x86/kernel/cpu/sgx/driver/va.c index f57aacefb6eb..fe0fc39bc098 100644 --- a/arch/x86/kernel/cpu/sgx/driver/va.c +++ b/arch/x86/kernel/cpu/sgx/driver/va.c @@ -17,7 +17,7 @@ struct sgx_epc_page *sgx_alloc_va_page(void) struct sgx_epc_page *epc_page; int ret; - epc_page = sgx_alloc_page(); + epc_page = sgx_alloc_page(NULL, true); if (IS_ERR(epc_page)) return ERR_CAST(epc_page); diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c index d10cd0ceb96e..30fd69f1fc07 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -10,10 +10,28 @@ #include #include +/** + * enum sgx_swap_constants - the constants used by the swapping code + * %SGX_NR_TO_SCAN: the number of pages to scan in a single round + * %SGX_NR_LOW_PAGES: the low watermark for ksgxswapd when it starts to swap + * pages. + * %SGX_NR_HIGH_PAGES: the high watermark for ksgxswapd what it stops swapping + * pages. + */ +enum sgx_swap_constants { + SGX_NR_TO_SCAN = 16, + SGX_NR_LOW_PAGES = 32, + SGX_NR_HIGH_PAGES = 64, +}; + struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; EXPORT_SYMBOL_GPL(sgx_epc_sections); static int sgx_nr_epc_sections; +static LIST_HEAD(sgx_active_page_list); +static DEFINE_SPINLOCK(sgx_active_page_list_lock); +static struct task_struct *ksgxswapd_tsk; +static DECLARE_WAIT_QUEUE_HEAD(ksgxswapd_waitq); /* A per-cpu cache for the last known values of IA32_SGXLEPUBKEYHASHx MSRs. */ static DEFINE_PER_CPU(u64 [4], sgx_lepubkeyhash_cache); @@ -41,15 +59,114 @@ static struct sgx_epc_page *sgx_section_get_page( } /** - * sgx_alloc_page - Allocate an EPC page - * - * Try to grab a page from the free EPC page list. + * sgx_reclaim_pages - reclaim EPC pages from the consumers * - * Return: - * a pointer to a &struct sgx_epc_page instance, - * -errno on error + * Takes a fixed chunk of pages from the global list of consumed EPC pages and + * tries to swap them. Only the pages that are either being freed by the + * consumer or actively used are skipped. */ -struct sgx_epc_page *sgx_alloc_page(void) +static void sgx_reclaim_pages(void) +{ + struct sgx_epc_page *chunk[SGX_NR_TO_SCAN + 1]; + struct sgx_epc_page *epc_page; + struct sgx_epc_section *section; + int i, j; + + spin_lock(&sgx_active_page_list_lock); + for (i = 0, j = 0; i < SGX_NR_TO_SCAN; i++) { + if (list_empty(&sgx_active_page_list)) + break; + + epc_page = list_first_entry(&sgx_active_page_list, + struct sgx_epc_page, list); + list_del_init(&epc_page->list); + + if (sgx_encl_page_get(epc_page)) + chunk[j++] = epc_page; + else + /* The owner is freeing the page. No need to add the + * page back to the list of reclaimable pages. + */ + epc_page->desc &= ~SGX_EPC_PAGE_RECLAIMABLE; + } + spin_unlock(&sgx_active_page_list_lock); + + for (i = 0; i < j; i++) { + epc_page = chunk[i]; + if (sgx_encl_page_reclaim(epc_page)) + continue; + + sgx_encl_page_put(epc_page); + + spin_lock(&sgx_active_page_list_lock); + list_add_tail(&epc_page->list, &sgx_active_page_list); + spin_unlock(&sgx_active_page_list_lock); + + chunk[i] = NULL; + } + + for (i = 0; i < j; i++) { + epc_page = chunk[i]; + if (epc_page) + sgx_encl_page_block(epc_page); + } + + for (i = 0; i < j; i++) { + epc_page = chunk[i]; + if (epc_page) { + sgx_encl_page_write(epc_page); + sgx_encl_page_put(epc_page); + epc_page->desc &= ~SGX_EPC_PAGE_RECLAIMABLE; + + section = sgx_epc_section(epc_page); + spin_lock(§ion->lock); + sgx_section_put_page(section, epc_page); + spin_unlock(§ion->lock); + } + } +} + +static unsigned long sgx_calc_free_cnt(void) +{ + struct sgx_epc_section *section; + unsigned long free_cnt = 0; + int i; + + for (i = 0; i < sgx_nr_epc_sections; i++) { + section = &sgx_epc_sections[i]; + free_cnt += section->free_cnt; + } + + return free_cnt; +} + +static inline bool sgx_should_reclaim(void) +{ + return sgx_calc_free_cnt() < SGX_NR_HIGH_PAGES && + !list_empty(&sgx_active_page_list); +} + +static int ksgxswapd(void *p) +{ + set_freezable(); + + while (!kthread_should_stop()) { + if (try_to_freeze()) + continue; + + wait_event_freezable(ksgxswapd_waitq, kthread_should_stop() || + sgx_should_reclaim()); + + if (sgx_should_reclaim()) + sgx_reclaim_pages(); + + cond_resched(); + } + + return 0; +} + +static struct sgx_epc_page *sgx_try_alloc_page(void *owner) { struct sgx_epc_section *section; struct sgx_epc_page *page; @@ -61,11 +178,58 @@ struct sgx_epc_page *sgx_alloc_page(void) page = sgx_section_get_page(section); spin_unlock(§ion->lock); - if (page) + if (page) { + page->owner = owner; return page; + } + } + + return NULL; +} + +/** + * sgx_alloc_page - Allocate an EPC page + * @owner: the owner of the EPC page + * @reclaim: reclaim pages if necessary + * + * Try to grab a page from the free EPC page list. If there is a free page + * available, it is returned to the caller. The @reclaim parameter hints + * the EPC memory manager to swap pages when required. + * + * Return: + * a pointer to a &struct sgx_epc_page instance, + * -errno on error + */ +struct sgx_epc_page *sgx_alloc_page(void *owner, bool reclaim) +{ + struct sgx_epc_page *entry; + + for ( ; ; ) { + entry = sgx_try_alloc_page(owner); + if (entry) + break; + + if (list_empty(&sgx_active_page_list)) + return ERR_PTR(-ENOMEM); + + if (!reclaim) { + entry = ERR_PTR(-EBUSY); + break; + } + + if (signal_pending(current)) { + entry = ERR_PTR(-ERESTARTSYS); + break; + } + + sgx_reclaim_pages(); + schedule(); } - return ERR_PTR(-ENOMEM); + if (sgx_calc_free_cnt() < SGX_NR_LOW_PAGES) + wake_up(&ksgxswapd_waitq); + + return entry; } EXPORT_SYMBOL_GPL(sgx_alloc_page); @@ -73,10 +237,12 @@ EXPORT_SYMBOL_GPL(sgx_alloc_page); * __sgx_free_page - Free an EPC page * @page: pointer a previously allocated EPC page * - * EREMOVE an EPC page and insert it back to the list of free pages. + * EREMOVE an EPC page and insert it back to the list of free pages. If the + * page is reclaimable, delete it from the active page list. * * Return: * 0 on success + * -EBUSY if the page cannot be removed from the active list * SGX error code if EREMOVE fails */ int __sgx_free_page(struct sgx_epc_page *page) @@ -84,6 +250,23 @@ int __sgx_free_page(struct sgx_epc_page *page) struct sgx_epc_section *section = sgx_epc_section(page); int ret; + /* + * Remove the page from the active list if necessary. If the page + * is actively being reclaimed, i.e. RECLAIMABLE is set but the + * page isn't on the active list, return -EBUSY as we can't free + * the page at this time since it is "owned" by the reclaimer. + */ + spin_lock(&sgx_active_page_list_lock); + if (page->desc & SGX_EPC_PAGE_RECLAIMABLE) { + if (list_empty(&page->list)) { + spin_unlock(&sgx_active_page_list_lock); + return -EBUSY; + } + list_del(&page->list); + page->desc &= ~SGX_EPC_PAGE_RECLAIMABLE; + } + spin_unlock(&sgx_active_page_list_lock); + ret = __eremove(sgx_epc_addr(page)); if (ret) return ret; @@ -100,15 +283,17 @@ EXPORT_SYMBOL_GPL(__sgx_free_page); * sgx_free_page - Free an EPC page and WARN on failure * @page: pointer to a previously allocated EPC page * - * EREMOVE an EPC page and insert it back to the list of free pages, and WARN - * if EREMOVE fails. For use when the call site cannot (or chooses not to) - * handle failure, i.e. the page is leaked on failure. + * EREMOVE an EPC page and insert it back to the list of free pages. If the + * page is reclaimable, delete it from the active page list. WARN on any + * failure. For use when the call site cannot (or chooses not to) handle + * failure, i.e. the page is leaked on failure. */ void sgx_free_page(struct sgx_epc_page *page) { int ret; ret = __sgx_free_page(page); + WARN(ret < 0, "sgx: cannot free page, reclaim in-progress"); WARN(ret > 0, "sgx: EREMOVE returned %d (0x%x)", ret, ret); } EXPORT_SYMBOL_GPL(sgx_free_page); @@ -161,6 +346,23 @@ int sgx_einit(struct sgx_sigstruct *sigstruct, struct sgx_einittoken *token, } EXPORT_SYMBOL(sgx_einit); +/** + * sgx_page_reclaimable - mark a page as reclaimable + * + * @page: EPC page + * + * Mark a page as reclaimable and add it to the active page list. Pages + * are automatically removed from the active list when freed. + */ +void sgx_page_reclaimable(struct sgx_epc_page *page) +{ + spin_lock(&sgx_active_page_list_lock); + page->desc |= SGX_EPC_PAGE_RECLAIMABLE; + list_add_tail(&page->list, &sgx_active_page_list); + spin_unlock(&sgx_active_page_list_lock); +} +EXPORT_SYMBOL_GPL(sgx_page_reclaimable); + static __init void sgx_free_epc_section(struct sgx_epc_section *section) { struct sgx_epc_page *page; @@ -207,6 +409,11 @@ static __init void sgx_page_cache_teardown(void) { int i; + if (ksgxswapd_tsk) { + kthread_stop(ksgxswapd_tsk); + ksgxswapd_tsk = NULL; + } + for (i = 0; i < sgx_nr_epc_sections; i++) sgx_free_epc_section(&sgx_epc_sections[i]); } @@ -272,6 +479,7 @@ static __init int sgx_page_cache_init(void) static __init int sgx_init(void) { + struct task_struct *tsk; int ret; if (!boot_cpu_has(X86_FEATURE_SGX)) @@ -281,6 +489,13 @@ static __init int sgx_init(void) if (ret) return ret; + tsk = kthread_run(ksgxswapd, NULL, "ksgxswapd"); + if (IS_ERR(tsk)) { + sgx_page_cache_teardown(); + return PTR_ERR(tsk); + } + ksgxswapd_tsk = tsk; + return 0; } From patchwork Fri Dec 21 23:11:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741129 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 7465913B5 for ; Fri, 21 Dec 2018 23:15:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6594128618 for ; Fri, 21 Dec 2018 23:15:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 59006286B6; Fri, 21 Dec 2018 23:15:34 +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 0579128618 for ; Fri, 21 Dec 2018 23:15:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388638AbeLUXPd (ORCPT ); Fri, 21 Dec 2018 18:15:33 -0500 Received: from mga06.intel.com ([134.134.136.31]:16623 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXPd (ORCPT ); Fri, 21 Dec 2018 18:15:33 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:15:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338726" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:15:25 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 22/25] x86/sgx: ptrace() support for the SGX driver Date: Sat, 22 Dec 2018 01:11:51 +0200 Message-Id: <20181221231154.6120-23-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Add VMA callbacks for ptrace() that can be used with debug enclaves. With debug enclaves data can be read and write the memory word at a time by using ENCLS(EDBGRD) and ENCLS(EDBGWR) leaf instructions. Signed-off-by: Jarkko Sakkinen --- arch/x86/kernel/cpu/sgx/driver/vma.c | 109 +++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/arch/x86/kernel/cpu/sgx/driver/vma.c b/arch/x86/kernel/cpu/sgx/driver/vma.c index da7b4080a4a6..e971a42cc64e 100644 --- a/arch/x86/kernel/cpu/sgx/driver/vma.c +++ b/arch/x86/kernel/cpu/sgx/driver/vma.c @@ -51,8 +51,117 @@ static int sgx_vma_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; } +static int sgx_edbgrd(struct sgx_encl *encl, struct sgx_encl_page *page, + unsigned long addr, void *data) +{ + unsigned long offset; + int ret; + + offset = addr & ~PAGE_MASK; + + if ((page->desc & SGX_ENCL_PAGE_TCS) && + offset > offsetof(struct sgx_tcs, gs_limit)) + return -ECANCELED; + + ret = __edbgrd(sgx_epc_addr(page->epc_page) + offset, data); + if (ret) { + sgx_dbg(encl, "EDBGRD returned %d\n", ret); + return encls_to_err(ret); + } + + return 0; +} + +static int sgx_edbgwr(struct sgx_encl *encl, struct sgx_encl_page *page, + unsigned long addr, void *data) +{ + unsigned long offset; + int ret; + + offset = addr & ~PAGE_MASK; + + /* Writing anything else than flags will cause #GP */ + if ((page->desc & SGX_ENCL_PAGE_TCS) && + offset != offsetof(struct sgx_tcs, flags)) + return -ECANCELED; + + ret = __edbgwr(sgx_epc_addr(page->epc_page) + offset, data); + if (ret) { + sgx_dbg(encl, "EDBGWR returned %d\n", ret); + return encls_to_err(ret); + } + + return 0; +} + +static int sgx_vma_access(struct vm_area_struct *vma, unsigned long addr, + void *buf, int len, int write) +{ + struct sgx_encl *encl = vma->vm_private_data; + struct sgx_encl_page *entry = NULL; + unsigned long align; + char data[sizeof(unsigned long)]; + int offset; + int cnt; + int ret = 0; + int i; + + /* If process was forked, VMA is still there but vm_private_data is set + * to NULL. + */ + if (!encl) + return -EFAULT; + + if (!(encl->flags & SGX_ENCL_DEBUG) || + !(encl->flags & SGX_ENCL_INITIALIZED) || + (encl->flags & SGX_ENCL_DEAD)) + return -EFAULT; + + for (i = 0; i < len; i += cnt) { + if (!entry || !((addr + i) & (PAGE_SIZE - 1))) { + if (entry) + entry->desc &= ~SGX_ENCL_PAGE_RESERVED; + + entry = sgx_fault_page(vma, (addr + i) & PAGE_MASK, + true); + if (IS_ERR(entry)) { + ret = PTR_ERR(entry); + entry = NULL; + break; + } + } + + /* Locking is not needed because only immutable fields of the + * page are accessed and page itself is reserved so that it + * cannot be swapped out in the middle. + */ + + align = ALIGN_DOWN(addr + i, sizeof(unsigned long)); + offset = (addr + i) & (sizeof(unsigned long) - 1); + cnt = sizeof(unsigned long) - offset; + cnt = min(cnt, len - i); + + ret = sgx_edbgrd(encl, entry, align, data); + if (ret) + break; + if (write) { + memcpy(data + offset, buf + i, cnt); + ret = sgx_edbgwr(encl, entry, align, data); + if (ret) + break; + } else + memcpy(buf + i, data + offset, cnt); + } + + if (entry) + entry->desc &= ~SGX_ENCL_PAGE_RESERVED; + + return ret < 0 ? ret : i; +} + const struct vm_operations_struct sgx_vm_ops = { .close = sgx_vma_close, .open = sgx_vma_open, .fault = sgx_vma_fault, + .access = sgx_vma_access, }; From patchwork Fri Dec 21 23:11:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741135 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 3168013B5 for ; Fri, 21 Dec 2018 23:16:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1E86928618 for ; Fri, 21 Dec 2018 23:16:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0EDE3286B6; Fri, 21 Dec 2018 23:16:46 +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 691C628618 for ; Fri, 21 Dec 2018 23:16:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730898AbeLUXQp (ORCPT ); Fri, 21 Dec 2018 18:16:45 -0500 Received: from mga11.intel.com ([192.55.52.93]:21291 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbeLUXQp (ORCPT ); Fri, 21 Dec 2018 18:16:45 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:15:42 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338744" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:15:35 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 23/25] x86/sgx: SGX documentation Date: Sat, 22 Dec 2018 01:11:52 +0200 Message-Id: <20181221231154.6120-24-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Documentation of the features of the Software Guard eXtensions (SGX), the basic design choices for the core and driver functionality and the UAPI. Signed-off-by: Jarkko Sakkinen Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- Documentation/index.rst | 1 + Documentation/x86/index.rst | 10 ++ Documentation/x86/sgx.rst | 234 ++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 Documentation/x86/index.rst create mode 100644 Documentation/x86/sgx.rst diff --git a/Documentation/index.rst b/Documentation/index.rst index c858c2e66e36..63864826dcd6 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -101,6 +101,7 @@ implementation. :maxdepth: 2 sh/index + x86/index Filesystem Documentation ------------------------ diff --git a/Documentation/x86/index.rst b/Documentation/x86/index.rst new file mode 100644 index 000000000000..f137d7109052 --- /dev/null +++ b/Documentation/x86/index.rst @@ -0,0 +1,10 @@ +.. SPDX-License-Identifier: GPL-2.0 + +====================== +x86 Architecture Guide +====================== + +.. toctree:: + :maxdepth: 2 + + sgx diff --git a/Documentation/x86/sgx.rst b/Documentation/x86/sgx.rst new file mode 100644 index 000000000000..72c3ea2e8889 --- /dev/null +++ b/Documentation/x86/sgx.rst @@ -0,0 +1,234 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================== +Intel(R) Software Guard eXtensions +================================== + +Introduction +============ + +Intel(R) SGX is a set of CPU instructions that can be used by applications to +set aside private regions of code and data. The code outside the enclave is +disallowed to access the memory inside the enclave by the CPU access control. +In a way you can think that SGX provides an inverted sandbox. It protects the +application from a malicious host. + +You can tell if your CPU supports SGX by looking into ``/proc/cpuinfo``: + + ``cat /proc/cpuinfo | grep sgx`` + +Overview of SGX +=============== + +SGX has a set of data structures to maintain information about the enclaves and +their security properties. BIOS reserves a fixed size region of physical memory +for these structures by setting Processor Reserved Memory Range Registers +(PRMRR). + +This memory range is protected from outside access by the CPU and all the data +coming in and out of the CPU package is encrypted by a key that is generated for +each boot cycle. + +Enclaves execute in ring 3 in a special enclave submode using pages from the +reserved memory range. A fixed logical address range for the enclave is reserved +by ENCLS(ECREATE), a leaf instruction used to create enclaves. It is referred to +in the documentation commonly as the *ELRANGE*. + +Every memory access to the ELRANGE is asserted by the CPU. If the CPU is not +executing in the enclave mode inside the enclave, #GP is raised. On the other +hand, enclave code can make memory accesses both inside and outside of the +ELRANGE. + +An enclave can only execute code inside the ELRANGE. Instructions that may cause +VMEXIT, IO instructions and instructions that require a privilege change are +prohibited inside the enclave. Interrupts and exceptions always cause an enclave +to exit and jump to an address outside the enclave given when the enclave is +entered by using the leaf instruction ENCLS(EENTER). + +Protected memory +---------------- + +Enclave Page Cache (EPC) + Physical pages used with enclaves that are protected by the CPU from + unauthorized access. + +Enclave Page Cache Map (EPCM) + A database that describes the properties and state of the pages e.g. their + permissions or which enclave they belong to. + +Memory Encryption Engine (MEE) integrity tree + Autonomously updated integrity tree. The root of the tree located in on-die + SRAM. + +EPC data types +-------------- + +SGX Enclave Control Structure (SECS) + Describes the global properties of an enclave. Will not be mapped to the + ELRANGE. + +Regular (REG) + These pages contain code and data. + +Thread Control Structure (TCS) + The pages that define the entry points inside an enclave. An enclave can + only be entered through these entry points and each can host a single + hardware thread at a time. + +Version Array (VA) + The pages contain 64-bit version numbers for pages that have been swapped + outside the enclave. Each page has the capacity of 512 version numbers. + +Launch control +-------------- + +To launch an enclave, two structures must be provided for ENCLS(EINIT): + +1. **SIGSTRUCT:** signed measurement of the enclave binary. +2. **EINITTOKEN:** a cryptographic token CMAC-signed with a AES256-key called + *launch key*, which is regenerated for each boot cycle. + +The CPU holds a SHA256 hash of a 3072-bit RSA public key inside +IA32_SGXLEPUBKEYHASHn MSRs. Enclaves with a SIGSTRUCT that is signed with this +key do not require a valid EINITTOKEN and can be authorized with special +privileges. One of those privileges is ability to acquire the launch key with +ENCLS(EGETKEY). + +**IA32_FEATURE_CONTROL[SGX_LE_WR]** is used by the BIOS configure whether +IA32_SGXLEPUBKEYHASH MSRs are read-only or read-write before locking the feature +control register and handing over control to the operating system. + +Enclave construction +-------------------- + +The construction is started by filling out the SECS that contains enclave +address range, privileged attributes and measurement of TCS and REG pages (pages +that will be mapped to the address range) among the other things. This structure +is passed to the ENCLS(ECREATE) together with a physical address of a page in +EPC that will hold the SECS. + +The pages are added with ENCLS(EADD) and measured with ENCLS(EEXTEND), i.e. +SHA256 hash MRENCLAVE residing in the SECS is extended with the page data. + +After all of the pages have been added, the enclave is initialized with +ENCLS(EINIT). It will check that the SIGSTRUCT is signed with the contained +public key. If the given EINITTOKEN has the valid bit set, the CPU checks that +the token is valid (CMAC'd with the launch key). If the token is not valid, +the CPU will check whether the enclave is signed with a key matching to the +IA32_SGXLEPUBKEYHASHn MSRs. + +Swapping pages +-------------- + +Enclave pages can be swapped out with the *ENCLS(EWB)* instruction to the +unprotected memory. In addition to the EPC page, ENCLS(EWB) takes in a VA page +and address for PCMD structure (Page Crypto MetaData) as input. The VA page will +seal a version number for the page. PCMD is 128-byte structure that contains +tracking information for the page, most importantly its MAC. With these +structures the enclave is sealed and rollback protected while it resides in the +unprotected memory. + +Before the page can be swapped out it must not have any active TLB references. +The *ENCLS(EBLOCK)* instruction moves a page to the *blocked* state, which means +that no new TLB entries can be created to it by the hardware threads. + +After this a shootdown sequence is started with the *ENCLS(ETRACK)* instruction, +which sets an increased counter value to the entering hardware threads. +ENCLS(EWB) will return *SGX_NOT_TRACKED* error while there are still threads +with the earlier counter value because that means that there might be hardware +threads inside the enclave with TLB entries to pages that are to be swapped. + +Kernel internals +================ + +Requirements +------------ + +Because SGX has an ever evolving and expanding feature set, it's possible for +a BIOS or VMM to configure a system in such a way that not all CPUs are equal, +e.g. where Launch Control is only enabled on a subset of CPUs. Linux does +*not* support such a heterogeneous system configuration, nor does it even +attempt to play nice in the face of a misconfigured system. With the exception +of Launch Control's hash MSRs, which can vary per CPU, Linux assumes that all +CPUs have a configuration that is identical to the boot CPU. + + +Roles and responsibilities +-------------------------- + +SGX introduces system resources, e.g. EPC memory, that must be accessible to +multiple entities, e.g. the native kernel driver (to expose SGX to userspace) +and KVM (to expose SGX to VMs), ideally without introducing any dependencies +between each SGX entity. To that end, the kernel owns and manages the shared +system resources, i.e. the EPC and Launch Control MSRs, and defines functions +that provide appropriate access to the shared resources. SGX support for +user space and VMs is left to the SGX platform driver and KVM respectively. + +Launching enclaves +------------------ + +The current kernel implementation supports only writable MSRs. The launch is +performed by setting the MSRs to the hash of the public key modulus of the +enclave signer and a token with the valid bit set to zero. + +EPC management +-------------- + +Due to the unique requirements for swapping EPC pages, and because EPC pages +(currently) do not have associated page structures, management of the EPC is +not handled by the standard Linux swapper. SGX directly handles swapping +of EPC pages, including a kthread to initiate reclaim and a rudimentary LRU +mechanism. The consumers of EPC pages, e.g. the SGX driver, are required to +implement function callbacks that can be invoked by the kernel to age, +swap, and/or forcefully reclaim a target EPC page. In effect, the kernel +controls what happens and when, while the consumers (driver, KVM, etc..) do +the actual work. + +Exception handling +------------------ + +The PF_SGX bit is set if and only if the #PF is detected by the SGX Enclave Page +Cache Map (EPCM). The EPCM is a hardware-managed table that enforces accesses to +an enclave's EPC pages in addition to the software-managed kernel page tables, +i.e. the effective permissions for an EPC page are a logical AND of the kernel's +page tables and the corresponding EPCM entry. + +The EPCM is consulted only after an access walks the kernel's page tables, i.e.: + +1. the access was allowed by the kernel +2. the kernel's tables have become less restrictive than the EPCM +3. the kernel cannot fixup the cause of the fault + +Notably, (2) implies that either the kernel has botched the EPC mappings or the +EPCM has been invalidated (see below). Regardless of why the fault occurred, +userspace needs to be alerted so that it can take appropriate action, e.g. +restart the enclave. This is reinforced by (3) as the kernel doesn't really +have any other reasonable option, i.e. signalling SIGSEGV is actually the least +severe action possible. + +Although the primary purpose of the EPCM is to prevent a malicious or +compromised kernel from attacking an enclave, e.g. by modifying the enclave's +page tables, do not WARN on a #PF with PF_SGX set. The SGX architecture +effectively allows the CPU to invalidate all EPCM entries at will and requires +that software be prepared to handle an EPCM fault at any time. The architecture +defines this behavior because the EPCM is encrypted with an ephemeral key that +isn't exposed to software. As such, the EPCM entries cannot be preserved across +transitions that result in a new key being used, e.g. CPU power down as part of +an S3 transition or when a VM is live migrated to a new physical system. + +SGX UAPI +======== + +.. kernel-doc:: drivers/platform/x86/intel_sgx/sgx_ioctl.c + :functions: sgx_ioc_enclave_create + sgx_ioc_enclave_add_page + sgx_ioc_enclave_init + +.. kernel-doc:: arch/x86/include/uapi/asm/sgx.h + +References +========== + +* A Memory Encryption Engine Suitable for General Purpose Processors + +* System Programming Manual: 39.1.4 IntelĀ® SGX Launch Control Configuration From patchwork Fri Dec 21 23:11:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741131 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 C2BDA1399 for ; Fri, 21 Dec 2018 23:16:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AFC6328618 for ; Fri, 21 Dec 2018 23:16:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A3605286B6; Fri, 21 Dec 2018 23:16:02 +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 AD67D286B3 for ; Fri, 21 Dec 2018 23:16:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732694AbeLUXQB (ORCPT ); Fri, 21 Dec 2018 18:16:01 -0500 Received: from mga14.intel.com ([192.55.52.115]:13797 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731892AbeLUXQB (ORCPT ); Fri, 21 Dec 2018 18:16:01 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:15:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338772" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:15:44 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 24/25] selftests/x86: Add a selftest for SGX Date: Sat, 22 Dec 2018 01:11:53 +0200 Message-Id: <20181221231154.6120-25-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Add a selftest for SGX. It is a trivial test where a simple enclave copies one 64-bit word of memory between two memory locations given to the enclave as arguments. Signed-off-by: Jarkko Sakkinen --- tools/testing/selftests/x86/Makefile | 10 + tools/testing/selftests/x86/sgx/Makefile | 47 ++ tools/testing/selftests/x86/sgx/encl.c | 20 + tools/testing/selftests/x86/sgx/encl.lds | 33 ++ .../selftests/x86/sgx/encl_bootstrap.S | 94 ++++ tools/testing/selftests/x86/sgx/encl_piggy.S | 18 + tools/testing/selftests/x86/sgx/encl_piggy.h | 14 + tools/testing/selftests/x86/sgx/main.c | 155 ++++++ tools/testing/selftests/x86/sgx/sgx_arch.h | 109 ++++ tools/testing/selftests/x86/sgx/sgx_call.S | 20 + tools/testing/selftests/x86/sgx/sgx_uapi.h | 100 ++++ tools/testing/selftests/x86/sgx/sgxsign.c | 503 ++++++++++++++++++ .../testing/selftests/x86/sgx/signing_key.pem | 39 ++ 13 files changed, 1162 insertions(+) create mode 100644 tools/testing/selftests/x86/sgx/Makefile create mode 100644 tools/testing/selftests/x86/sgx/encl.c create mode 100644 tools/testing/selftests/x86/sgx/encl.lds create mode 100644 tools/testing/selftests/x86/sgx/encl_bootstrap.S create mode 100644 tools/testing/selftests/x86/sgx/encl_piggy.S create mode 100644 tools/testing/selftests/x86/sgx/encl_piggy.h create mode 100644 tools/testing/selftests/x86/sgx/main.c create mode 100644 tools/testing/selftests/x86/sgx/sgx_arch.h create mode 100644 tools/testing/selftests/x86/sgx/sgx_call.S create mode 100644 tools/testing/selftests/x86/sgx/sgx_uapi.h create mode 100644 tools/testing/selftests/x86/sgx/sgxsign.c create mode 100644 tools/testing/selftests/x86/sgx/signing_key.pem diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 186520198de7..4fc9a42f56ea 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -1,4 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 + +SUBDIRS_64 := sgx + all: include ../lib.mk @@ -67,6 +70,13 @@ all_32: $(BINARIES_32) all_64: $(BINARIES_64) +all_64: $(SUBDIRS_64) + @for DIR in $(SUBDIRS_64); do \ + BUILD_TARGET=$(OUTPUT)/$$DIR; \ + mkdir $$BUILD_TARGET -p; \ + make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \ + done + EXTRA_CLEAN := $(BINARIES_32) $(BINARIES_64) $(BINARIES_32): $(OUTPUT)/%_32: %.c diff --git a/tools/testing/selftests/x86/sgx/Makefile b/tools/testing/selftests/x86/sgx/Makefile new file mode 100644 index 000000000000..6c260e2eb08d --- /dev/null +++ b/tools/testing/selftests/x86/sgx/Makefile @@ -0,0 +1,47 @@ +top_srcdir = ../../../../.. + +include ../../lib.mk + +HOST_CFLAGS := -Wall -Werror -g +ENCL_CFLAGS := -Wall -Werror -static -nostdlib -nostartfiles -fPIC \ + -fno-stack-protector -mrdrnd + +TEST_CUSTOM_PROGS := $(OUTPUT)/test_sgx +all_64: $(TEST_CUSTOM_PROGS) + +$(TEST_CUSTOM_PROGS): $(OUTPUT)/main.o $(OUTPUT)/sgx_call.o \ + $(OUTPUT)/encl_piggy.o + $(CC) $(HOST_CFLAGS) -o $@ $^ + +$(OUTPUT)/main.o: main.c + $(CC) $(HOST_CFLAGS) -c $< -o $@ + +$(OUTPUT)/sgx_call.o: sgx_call.S + $(CC) $(HOST_CFLAGS) -c $< -o $@ + +$(OUTPUT)/encl_piggy.o: $(OUTPUT)/encl.bin $(OUTPUT)/encl.ss + +$(OUTPUT)/encl.bin: $(OUTPUT)/encl.elf $(OUTPUT)/sgxsign + objcopy --remove-section=.got.plt -O binary $< $@ + +$(OUTPUT)/encl.elf: $(OUTPUT)/encl.o $(OUTPUT)/encl_bootstrap.o + $(CC) $(ENCL_CFLAGS) -T encl.lds -o $@ $^ + +$(OUTPUT)/encl.o: encl.c + $(CC) $(ENCL_CFLAGS) -c $< -o $@ + +$(OUTPUT)/encl_bootstrap.o: encl_bootstrap.S + $(CC) $(ENCL_CFLAGS) -c $< -o $@ + +$(OUTPUT)/encl.ss: $(OUTPUT)/encl.bin $(OUTPUT)/sgxsign + $(OUTPUT)/sgxsign signing_key.pem $(OUTPUT)/encl.bin $(OUTPUT)/encl.ss + +$(OUTPUT)/sgxsign: sgxsign.c + $(CC) -o $@ $< -lcrypto + +EXTRA_CLEAN := $(OUTPUT)/sgx-selftest $(OUTPUT)/sgx-selftest.o \ + $(OUTPUT)/sgx_call.o $(OUTPUT)/encl.bin $(OUTPUT)/encl.ss \ + $(OUTPUT)/encl.elf $(OUTPUT)/encl.o $(OUTPUT)/encl_bootstrap.o \ + $(OUTPUT)/sgxsign + +.PHONY: clean diff --git a/tools/testing/selftests/x86/sgx/encl.c b/tools/testing/selftests/x86/sgx/encl.c new file mode 100644 index 000000000000..eb6aa318d3f1 --- /dev/null +++ b/tools/testing/selftests/x86/sgx/encl.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include "sgx_arch.h" + +static void *memcpy(void *dest, const void *src, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) + ((char *)dest)[i] = ((char *)src)[i]; + + return dest; +} + +void encl_body(void *rdi, void *rsi) +{ + memcpy(rsi, rdi, 8); +} diff --git a/tools/testing/selftests/x86/sgx/encl.lds b/tools/testing/selftests/x86/sgx/encl.lds new file mode 100644 index 000000000000..2ee01ac3ec79 --- /dev/null +++ b/tools/testing/selftests/x86/sgx/encl.lds @@ -0,0 +1,33 @@ +OUTPUT_FORMAT(elf64-x86-64) + +SECTIONS +{ + . = 0; + .tcs : { + *(.tcs*) + } + + . = ALIGN(4096); + .text : { + *(.text*) + *(.rodata*) + } + + . = ALIGN(4096); + .data : { + *(.data*) + } + + /DISCARD/ : { + *(.data*) + *(.comment*) + *(.note*) + *(.debug*) + *(.eh_frame*) + } +} + +ASSERT(!DEFINED(.altinstructions), "ALTERNATIVES are not supported in enclaves") +ASSERT(!DEFINED(.altinstr_replacement), "ALTERNATIVES are not supported in enclaves") +ASSERT(!DEFINED(.discard.retpoline_safe), "RETPOLINE ALTERNATIVES are not supported in enclaves") +ASSERT(!DEFINED(.discard.nospec), "RETPOLINE ALTERNATIVES are not supported in enclaves") diff --git a/tools/testing/selftests/x86/sgx/encl_bootstrap.S b/tools/testing/selftests/x86/sgx/encl_bootstrap.S new file mode 100644 index 000000000000..d07f970ccdf9 --- /dev/null +++ b/tools/testing/selftests/x86/sgx/encl_bootstrap.S @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright(c) 2016-18 Intel Corporation. + */ + + .macro ENCLU + .byte 0x0f, 0x01, 0xd7 + .endm + + .section ".tcs", "a" + .balign 4096 + + .fill 1, 8, 0 # STATE (set by CPU) + .fill 1, 8, 0 # FLAGS + .quad encl_ssa # OSSA + .fill 1, 4, 0 # CSSA (set by CPU) + .fill 1, 4, 1 # NSSA + .quad encl_entry # OENTRY + .fill 1, 8, 0 # AEP (set by EENTER and ERESUME) + .fill 1, 8, 0 # OFSBASE + .fill 1, 8, 0 # OGSBASE + .fill 1, 4, 0xFFFFFFFF # FSLIMIT + .fill 1, 4, 0xFFFFFFFF # GSLIMIT + .fill 4024, 1, 0 # Reserved + + .text + +encl_entry: + # RBX contains the base address for TCS, which is also the first address + # inside the enclave. By adding the value of le_stack_end to it, we get + # the absolute address for the stack. + lea (encl_stack)(%rbx), %rax + xchg %rsp, %rax + push %rax + + push %rcx # push the address after EENTER + push %rbx # push the enclave base address + + call encl_body + + pop %rbx # pop the enclave base address + + # Restore XSAVE registers to a synthetic state. + mov $0xFFFFFFFF, %rax + mov $0xFFFFFFFF, %rdx + lea (xsave_area)(%rbx), %rdi + fxrstor (%rdi) + + # Clear GPRs. + xor %rcx, %rcx + xor %rdx, %rdx + xor %rdi, %rdi + xor %rsi, %rsi + xor %r8, %r8 + xor %r9, %r9 + xor %r10, %r10 + xor %r11, %r11 + xor %r12, %r12 + xor %r13, %r13 + xor %r14, %r14 + xor %r15, %r15 + + # Reset status flags. + add %rdx, %rdx # OF = SF = AF = CF = 0; ZF = PF = 1 + + # Prepare EEXIT target by popping the address of the instruction after + # EENTER to RBX. + pop %rbx + + # Restore the caller stack. + pop %rax + mov %rax, %rsp + + # EEXIT + mov $4, %rax + enclu + + .section ".data", "aw" + +encl_ssa: + .space 4096 + +xsave_area: + .fill 1, 4, 0x037F # FCW + .fill 5, 4, 0 + .fill 1, 4, 0x1F80 # MXCSR + .fill 1, 4, 0xFFFF # MXCSR_MASK + .fill 123, 4, 0 + .fill 1, 4, 0x80000000 # XCOMP_BV[63] = 1, compaction mode + .fill 12, 4, 0 + + .balign 4096 + .space 8192 +encl_stack: diff --git a/tools/testing/selftests/x86/sgx/encl_piggy.S b/tools/testing/selftests/x86/sgx/encl_piggy.S new file mode 100644 index 000000000000..542001658afb --- /dev/null +++ b/tools/testing/selftests/x86/sgx/encl_piggy.S @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright(c) 2016-18 Intel Corporation. + */ + + .section ".rodata", "a" + +encl_bin: + .globl encl_bin + .incbin "encl.bin" +encl_bin_end: + .globl encl_bin_end + +encl_ss: + .globl encl_ss + .incbin "encl.ss" +encl_ss_end: + .globl encl_ss_end diff --git a/tools/testing/selftests/x86/sgx/encl_piggy.h b/tools/testing/selftests/x86/sgx/encl_piggy.h new file mode 100644 index 000000000000..ee8224f8cc8d --- /dev/null +++ b/tools/testing/selftests/x86/sgx/encl_piggy.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright(c) 2016-18 Intel Corporation. + */ + +#ifndef ENCL_PIGGY_H +#define ENCL_PIGGY_H + +extern unsigned char encl_bin[]; +extern unsigned char encl_bin_end[]; +extern unsigned char encl_ss[]; +extern unsigned char encl_ss_end[]; + +#endif /* ENCL_PIGGY_H */ diff --git a/tools/testing/selftests/x86/sgx/main.c b/tools/testing/selftests/x86/sgx/main.c new file mode 100644 index 000000000000..0bc33f8d4be3 --- /dev/null +++ b/tools/testing/selftests/x86/sgx/main.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "encl_piggy.h" +#include "sgx_arch.h" +#include "sgx_uapi.h" + +static const uint64_t MAGIC = 0x1122334455667788ULL; + +static bool encl_create(int dev_fd, unsigned long bin_size, + struct sgx_secs *secs) +{ + struct sgx_enclave_create ioc; + void *base; + int rc; + + memset(secs, 0, sizeof(*secs)); + secs->ssaframesize = 1; + secs->attributes = SGX_ATTR_MODE64BIT; + secs->xfrm = 3; + + for (secs->size = 4096; secs->size < bin_size; ) + secs->size <<= 1; + + base = mmap(NULL, secs->size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_SHARED, dev_fd, 0); + if (base == MAP_FAILED) { + perror("mmap"); + return false; + } + + secs->base = (uint64_t)base; + + ioc.src = (unsigned long)secs; + rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_CREATE, &ioc); + if (rc) { + fprintf(stderr, "ECREATE failed rc=%d.\n", rc); + munmap(base, secs->size); + return false; + } + + return true; +} + +static bool encl_add_page(int dev_fd, unsigned long addr, void *data, + uint64_t flags) +{ + struct sgx_enclave_add_page ioc; + struct sgx_secinfo secinfo; + int rc; + + memset(&secinfo, 0, sizeof(secinfo)); + secinfo.flags = flags; + + ioc.secinfo = (unsigned long)&secinfo; + ioc.mrmask = 0xFFFF; + ioc.addr = addr; + ioc.src = (uint64_t)data; + + rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_ADD_PAGE, &ioc); + if (rc) { + fprintf(stderr, "EADD failed rc=%d.\n", rc); + return false; + } + + return true; +} + +static bool encl_load(struct sgx_secs *secs, unsigned long bin_size) +{ + struct sgx_enclave_init ioc; + uint64_t offset; + uint64_t flags; + int dev_fd; + int rc; + + dev_fd = open("/dev/sgx", O_RDWR); + if (dev_fd < 0) { + fprintf(stderr, "Unable to open /dev/sgx\n"); + return false; + } + + if (!encl_create(dev_fd, bin_size, secs)) + goto out_dev_fd; + + for (offset = 0; offset < bin_size; offset += 0x1000) { + if (!offset) + flags = SGX_SECINFO_TCS; + else + flags = SGX_SECINFO_REG | SGX_SECINFO_R | + SGX_SECINFO_W | SGX_SECINFO_X; + + if (!encl_add_page(dev_fd, secs->base + offset, + encl_bin + offset, flags)) + goto out_map; + } + + ioc.addr = secs->base; + ioc.sigstruct = (uint64_t)&encl_ss; + rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_INIT, &ioc); + if (rc) { + printf("EINIT failed rc=%d\n", rc); + goto out_map; + } + + close(dev_fd); + return true; +out_map: + munmap((void *)secs->base, secs->size); +out_dev_fd: + close(dev_fd); + return false; +} + +void sgx_call(void *rdi, void *rsi, void *entry); + +int main(int argc, char **argv) +{ + unsigned long bin_size = encl_bin_end - encl_bin; + unsigned long ss_size = encl_ss_end - encl_ss; + struct sgx_secs secs; + uint64_t result = 0; + + printf("Binary size %lu (0x%lx), SIGSTRUCT size %lu\n", bin_size, + bin_size, ss_size); + if (ss_size != sizeof(struct sgx_sigstruct)) { + fprintf(stderr, "The size of SIGSTRUCT should be %lu\n", + sizeof(struct sgx_sigstruct)); + exit(1); + } + + printf("Loading the enclave.\n"); + if (!encl_load(&secs, bin_size)) + exit(1); + + printf("Input: 0x%lx\n", MAGIC); + sgx_call((void *)&MAGIC, &result, (void *)secs.base); + if (result != MAGIC) { + fprintf(stderr, "0x%lx != 0x%lx\n", result, MAGIC); + exit(1); + } + + printf("Output: 0x%lx\n", result); + exit(0); +} diff --git a/tools/testing/selftests/x86/sgx/sgx_arch.h b/tools/testing/selftests/x86/sgx/sgx_arch.h new file mode 100644 index 000000000000..7711a1be8ad4 --- /dev/null +++ b/tools/testing/selftests/x86/sgx/sgx_arch.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright(c) 2016-18 Intel Corporation. + */ + +#ifndef SGX_ARCH_H +#define SGX_ARCH_H + +#include + +enum sgx_attribute { + SGX_ATTR_DEBUG = 0x02, + SGX_ATTR_MODE64BIT = 0x04, + SGX_ATTR_PROVISIONKEY = 0x10, + SGX_ATTR_EINITTOKENKEY = 0x20, +}; + +#define SGX_ATTR_RESERVED_MASK 0xFFFFFFFFFFFFFFC9L + +#define SGX_SECS_RESERVED1_SIZE 24 +#define SGX_SECS_RESERVED2_SIZE 32 +#define SGX_SECS_RESERVED3_SIZE 96 +#define SGX_SECS_RESERVED4_SIZE 3836 + +struct sgx_secs { + uint64_t size; + uint64_t base; + uint32_t ssaframesize; + uint32_t miscselect; + uint8_t reserved1[SGX_SECS_RESERVED1_SIZE]; + uint64_t attributes; + uint64_t xfrm; + uint32_t mrenclave[8]; + uint8_t reserved2[SGX_SECS_RESERVED2_SIZE]; + uint32_t mrsigner[8]; + uint8_t reserved3[SGX_SECS_RESERVED3_SIZE]; + uint16_t isvvprodid; + uint16_t isvsvn; + uint8_t reserved4[SGX_SECS_RESERVED4_SIZE]; +}; + +#define SGX_SECINFO_PERMISSION_MASK 0x0000000000000007L +#define SGX_SECINFO_PAGE_TYPE_MASK 0x000000000000FF00L +#define SGX_SECINFO_RESERVED_MASK 0xFFFFFFFFFFFF00F8L + +enum sgx_page_type { + SGX_PAGE_TYPE_SECS = 0x00, + SGX_PAGE_TYPE_TCS = 0x01, + SGX_PAGE_TYPE_REG = 0x02, + SGX_PAGE_TYPE_VA = 0x03, + SGX_PAGE_TYPE_TRIM = 0x04, +}; + +enum sgx_secinfo_flags { + SGX_SECINFO_R = 0x01, + SGX_SECINFO_W = 0x02, + SGX_SECINFO_X = 0x04, + SGX_SECINFO_SECS = (SGX_PAGE_TYPE_SECS << 8), + SGX_SECINFO_TCS = (SGX_PAGE_TYPE_TCS << 8), + SGX_SECINFO_REG = (SGX_PAGE_TYPE_REG << 8), + SGX_SECINFO_TRIM = (SGX_PAGE_TYPE_TRIM << 8), +}; + +struct sgx_secinfo { + uint64_t flags; + uint64_t reserved[7]; +} __attribute__((aligned(64))); + +#define SGX_MODULUS_SIZE 384 + +struct sgx_sigstruct_header { + uint64_t header1[2]; + uint32_t vendor; + uint32_t date; + uint64_t header2[2]; + uint32_t swdefined; + uint8_t reserved1[84]; +}; + +struct sgx_sigstruct_body { + uint32_t miscselect; + uint32_t miscmask; + uint8_t reserved2[20]; + uint64_t attributes; + uint64_t xfrm; + uint8_t attributemask[16]; + uint8_t mrenclave[32]; + uint8_t reserved3[32]; + uint16_t isvprodid; + uint16_t isvsvn; +} __attribute__((__packed__)); + +struct sgx_sigstruct { + struct sgx_sigstruct_header header; + uint8_t modulus[SGX_MODULUS_SIZE]; + uint32_t exponent; + uint8_t signature[SGX_MODULUS_SIZE]; + struct sgx_sigstruct_body body; + uint8_t reserved4[12]; + uint8_t q1[SGX_MODULUS_SIZE]; + uint8_t q2[SGX_MODULUS_SIZE]; +}; + +struct sgx_sigstruct_payload { + struct sgx_sigstruct_header header; + struct sgx_sigstruct_body body; +}; + +#endif /* SGX_ARCH_H */ diff --git a/tools/testing/selftests/x86/sgx/sgx_call.S b/tools/testing/selftests/x86/sgx/sgx_call.S new file mode 100644 index 000000000000..b841d7345533 --- /dev/null +++ b/tools/testing/selftests/x86/sgx/sgx_call.S @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/** +* Copyright(c) 2016-18 Intel Corporation. +*/ +.macro ENCLU +.byte 0x0f, 0x01, 0xd7 +.endm + + .text + + .global sgx_call +sgx_call: + push %rbx + mov $0x02, %rax + mov %rdx, %rbx + lea sgx_async_exit(%rip), %rcx +sgx_async_exit: + ENCLU + pop %rbx + ret diff --git a/tools/testing/selftests/x86/sgx/sgx_uapi.h b/tools/testing/selftests/x86/sgx/sgx_uapi.h new file mode 100644 index 000000000000..ef19f1c013d1 --- /dev/null +++ b/tools/testing/selftests/x86/sgx/sgx_uapi.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright(c) 2016-18 Intel Corporation. + */ + +#ifndef _UAPI_ASM_X86_SGX_H +#define _UAPI_ASM_X86_SGX_H + +#include +#include + +#define SGX_MAGIC 0xA4 + +#define SGX_IOC_ENCLAVE_CREATE \ + _IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create) +#define SGX_IOC_ENCLAVE_ADD_PAGE \ + _IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page) +#define SGX_IOC_ENCLAVE_INIT \ + _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) +#define SGX_IOC_ENCLAVE_REMOVE_PAGES \ + _IOW(SGX_MAGIC, 0x03, struct sgx_enclave_remove_pages) +#define SGX_IOC_ENCLAVE_MODIFY_PAGES \ + _IOW(SGX_MAGIC, 0x04, struct sgx_enclave_modify_pages) + +/* IOCTL return values */ +#define SGX_POWER_LOST_ENCLAVE 0x40000000 + +/** + * struct sgx_enclave_create - parameter structure for the + * %SGX_IOC_ENCLAVE_CREATE ioctl + * @src: address for the SECS page data + */ +struct sgx_enclave_create { + __u64 src; +}; + +/** + * struct sgx_enclave_add_page - parameter structure for the + * %SGX_IOC_ENCLAVE_ADD_PAGE ioctl + * @addr: address within the ELRANGE + * @src: address for the page data + * @secinfo: address for the SECINFO data + * @mrmask: bitmask for the measured 256 byte chunks + */ +struct sgx_enclave_add_page { + __u64 addr; + __u64 src; + __u64 secinfo; + __u16 mrmask; +} __attribute__((__packed__)); + + +/** + * struct sgx_enclave_init - parameter structure for the + * %SGX_IOC_ENCLAVE_INIT ioctl + * @addr: address within the ELRANGE + * @sigstruct: address for the SIGSTRUCT data + */ +struct sgx_enclave_init { + __u64 addr; + __u64 sigstruct; +}; + +/** + * struct sgx_enclave_remove_pages - parameter structure for the + * %SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl + * @addr: address in the ELRANGE for the first page + * @length: length of the address range (must be multiple of the page size) + */ +struct sgx_enclave_remove_pages { + __u64 addr; + __u64 length; +} __packed; + +/** + * enum sgx_enclave_modify_ops - page modification operations + * @SGX_ENCLAVE_MODIFY_PERMISSIONS: change page permissions + * @SGX_ENCLAVE_MODIFY_TYPES: change page type + */ +enum sgx_enclave_modify_ops { + SGX_ENCLAVE_MODIFY_PERMISSIONS = 0, + SGX_ENCLAVE_MODIFY_TYPES = 1, +}; + +/** + * struct sgx_enclave_modify_pages - parameter structure for the + * %SGX_IOC_ENCLAVE_MOD_PAGES ioctl + * @addr: address in the ELRANGE for the first page + * @length: length of the address range (must be multiple of the page size) + * @secinfo: address of the new SECINFO data + * @op: a value of &sgx_enclave_modify_ops + */ +struct sgx_enclave_modify_pages { + __u64 addr; + __u64 length; + __u64 secinfo; + __u8 op; +} __attribute__((__packed__)); + +#endif /* _UAPI_ASM_X86_SGX_H */ diff --git a/tools/testing/selftests/x86/sgx/sgxsign.c b/tools/testing/selftests/x86/sgx/sgxsign.c new file mode 100644 index 000000000000..a670aa186dba --- /dev/null +++ b/tools/testing/selftests/x86/sgx/sgxsign.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sgx_arch.h" + +static const char *sign_key_pass; + +static bool check_crypto_errors(void) +{ + int err; + bool had_errors = false; + const char *filename; + int line; + char str[256]; + + for ( ; ; ) { + if (ERR_peek_error() == 0) + break; + + had_errors = true; + err = ERR_get_error_line(&filename, &line); + ERR_error_string_n(err, str, sizeof(str)); + fprintf(stderr, "crypto: %s: %s:%d\n", str, filename, line); + } + + return had_errors; +} + +static void exit_usage(const char *program) +{ + fprintf(stderr, + "Usage: %s/sign-le \n", program); + exit(1); +} + +static int pem_passwd_cb(char *buf, int size, int rwflag, void *u) +{ + if (!sign_key_pass) + return -1; + + strncpy(buf, sign_key_pass, size); + /* no retry */ + sign_key_pass = NULL; + + return strlen(buf) >= size ? size - 1 : strlen(buf); +} + +static inline const BIGNUM *get_modulus(RSA *key) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + return key->n; +#else + const BIGNUM *n; + + RSA_get0_key(key, &n, NULL, NULL); + return n; +#endif +} + +static RSA *load_sign_key(const char *path) +{ + FILE *f; + RSA *key; + + f = fopen(path, "rb"); + if (!f) { + fprintf(stderr, "Unable to open %s\n", path); + return NULL; + } + key = RSA_new(); + if (!PEM_read_RSAPrivateKey(f, &key, pem_passwd_cb, NULL)) + return NULL; + fclose(f); + + if (BN_num_bytes(get_modulus(key)) != SGX_MODULUS_SIZE) { + fprintf(stderr, "Invalid key size %d\n", + BN_num_bytes(get_modulus(key))); + RSA_free(key); + return NULL; + } + + return key; +} + +static void reverse_bytes(void *data, int length) +{ + int i = 0; + int j = length - 1; + uint8_t temp; + uint8_t *ptr = data; + + while (i < j) { + temp = ptr[i]; + ptr[i] = ptr[j]; + ptr[j] = temp; + i++; + j--; + } +} + +enum mrtags { + MRECREATE = 0x0045544145524345, + MREADD = 0x0000000044444145, + MREEXTEND = 0x00444E4554584545, +}; + +static bool mrenclave_update(EVP_MD_CTX *ctx, const void *data) +{ + if (!EVP_DigestUpdate(ctx, data, 64)) { + fprintf(stderr, "digest update failed\n"); + return false; + } + + return true; +} + +static bool mrenclave_commit(EVP_MD_CTX *ctx, uint8_t *mrenclave) +{ + unsigned int size; + + if (!EVP_DigestFinal_ex(ctx, (unsigned char *)mrenclave, &size)) { + fprintf(stderr, "digest commit failed\n"); + return false; + } + + if (size != 32) { + fprintf(stderr, "invalid digest size = %u\n", size); + return false; + } + + return true; +} + +struct mrecreate { + uint64_t tag; + uint32_t ssaframesize; + uint64_t size; + uint8_t reserved[44]; +} __attribute__((__packed__)); + + +static bool mrenclave_ecreate(EVP_MD_CTX *ctx, uint64_t blob_size) +{ + struct mrecreate mrecreate; + uint64_t encl_size; + + for (encl_size = 0x1000; encl_size < blob_size; ) + encl_size <<= 1; + + memset(&mrecreate, 0, sizeof(mrecreate)); + mrecreate.tag = MRECREATE; + mrecreate.ssaframesize = 1; + mrecreate.size = encl_size; + + if (!EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)) + return false; + + return mrenclave_update(ctx, &mrecreate); +} + +struct mreadd { + uint64_t tag; + uint64_t offset; + uint64_t flags; /* SECINFO flags */ + uint8_t reserved[40]; +} __attribute__((__packed__)); + +static bool mrenclave_eadd(EVP_MD_CTX *ctx, uint64_t offset, uint64_t flags) +{ + struct mreadd mreadd; + + memset(&mreadd, 0, sizeof(mreadd)); + mreadd.tag = MREADD; + mreadd.offset = offset; + mreadd.flags = flags; + + return mrenclave_update(ctx, &mreadd); +} + +struct mreextend { + uint64_t tag; + uint64_t offset; + uint8_t reserved[48]; +} __attribute__((__packed__)); + +static bool mrenclave_eextend(EVP_MD_CTX *ctx, uint64_t offset, uint8_t *data) +{ + struct mreextend mreextend; + int i; + + for (i = 0; i < 0x1000; i += 0x100) { + memset(&mreextend, 0, sizeof(mreextend)); + mreextend.tag = MREEXTEND; + mreextend.offset = offset + i; + + if (!mrenclave_update(ctx, &mreextend)) + return false; + + if (!mrenclave_update(ctx, &data[i + 0x00])) + return false; + + if (!mrenclave_update(ctx, &data[i + 0x40])) + return false; + + if (!mrenclave_update(ctx, &data[i + 0x80])) + return false; + + if (!mrenclave_update(ctx, &data[i + 0xC0])) + return false; + } + + return true; +} + +/** + * measure_encl - measure enclave + * @path: path to the enclave + * @mrenclave: measurement + * + * Calculates MRENCLAVE. Assumes that the very first page is a TCS page and + * following pages are regular pages. Does not measure the contents of the + * enclave as the signing tool is used at the moment only for the launch + * enclave, which is pass-through (everything gets a token). + */ +static bool measure_encl(const char *path, uint8_t *mrenclave) +{ + FILE *file; + struct stat sb; + EVP_MD_CTX *ctx; + uint64_t flags; + uint64_t offset; + uint8_t data[0x1000]; + int rc; + + ctx = EVP_MD_CTX_create(); + if (!ctx) + return false; + + file = fopen(path, "rb"); + if (!file) { + perror("fopen"); + EVP_MD_CTX_destroy(ctx); + return false; + } + + rc = stat(path, &sb); + if (rc) { + perror("stat"); + goto out; + } + + if (!sb.st_size || sb.st_size & 0xfff) { + fprintf(stderr, "Invalid blob size %lu\n", sb.st_size); + goto out; + } + + if (!mrenclave_ecreate(ctx, sb.st_size)) + goto out; + + for (offset = 0; offset < sb.st_size; offset += 0x1000) { + if (!offset) + flags = SGX_SECINFO_TCS; + else + flags = SGX_SECINFO_REG | SGX_SECINFO_R | + SGX_SECINFO_W | SGX_SECINFO_X; + + if (!mrenclave_eadd(ctx, offset, flags)) + goto out; + + rc = fread(data, 1, 0x1000, file); + if (!rc) + break; + if (rc < 0x1000) + goto out; + + if (!mrenclave_eextend(ctx, offset, data)) + goto out; + } + + if (!mrenclave_commit(ctx, mrenclave)) + goto out; + + fclose(file); + EVP_MD_CTX_destroy(ctx); + return true; +out: + fclose(file); + EVP_MD_CTX_destroy(ctx); + return false; +} + +/** + * sign_encl - sign enclave + * @sigstruct: pointer to SIGSTRUCT + * @key: 3072-bit RSA key + * @signature: byte array for the signature + * + * Calculates EMSA-PKCSv1.5 signature for the given SIGSTRUCT. The result is + * stored in big-endian format so that it can be further passed to OpenSSL + * libcrypto functions. + */ +static bool sign_encl(const struct sgx_sigstruct *sigstruct, RSA *key, + uint8_t *signature) +{ + struct sgx_sigstruct_payload payload; + unsigned int siglen; + uint8_t digest[SHA256_DIGEST_LENGTH]; + bool ret; + + memcpy(&payload.header, &sigstruct->header, sizeof(sigstruct->header)); + memcpy(&payload.body, &sigstruct->body, sizeof(sigstruct->body)); + + SHA256((unsigned char *)&payload, sizeof(payload), digest); + + ret = RSA_sign(NID_sha256, digest, SHA256_DIGEST_LENGTH, signature, + &siglen, key); + + return ret; +} + +struct q1q2_ctx { + BN_CTX *bn_ctx; + BIGNUM *m; + BIGNUM *s; + BIGNUM *q1; + BIGNUM *qr; + BIGNUM *q2; +}; + +static void free_q1q2_ctx(struct q1q2_ctx *ctx) +{ + BN_CTX_free(ctx->bn_ctx); + BN_free(ctx->m); + BN_free(ctx->s); + BN_free(ctx->q1); + BN_free(ctx->qr); + BN_free(ctx->q2); +} + +static bool alloc_q1q2_ctx(const uint8_t *s, const uint8_t *m, + struct q1q2_ctx *ctx) +{ + ctx->bn_ctx = BN_CTX_new(); + ctx->s = BN_bin2bn(s, SGX_MODULUS_SIZE, NULL); + ctx->m = BN_bin2bn(m, SGX_MODULUS_SIZE, NULL); + ctx->q1 = BN_new(); + ctx->qr = BN_new(); + ctx->q2 = BN_new(); + + if (!ctx->bn_ctx || !ctx->s || !ctx->m || !ctx->q1 || !ctx->qr || + !ctx->q2) { + free_q1q2_ctx(ctx); + return false; + } + + return true; +} + +static bool calc_q1q2(const uint8_t *s, const uint8_t *m, uint8_t *q1, + uint8_t *q2) +{ + struct q1q2_ctx ctx; + + if (!alloc_q1q2_ctx(s, m, &ctx)) { + fprintf(stderr, "Not enough memory for Q1Q2 calculation\n"); + return false; + } + + if (!BN_mul(ctx.q1, ctx.s, ctx.s, ctx.bn_ctx)) + goto out; + + if (!BN_div(ctx.q1, ctx.qr, ctx.q1, ctx.m, ctx.bn_ctx)) + goto out; + + if (BN_num_bytes(ctx.q1) > SGX_MODULUS_SIZE) { + fprintf(stderr, "Too large Q1 %d bytes\n", + BN_num_bytes(ctx.q1)); + goto out; + } + + if (!BN_mul(ctx.q2, ctx.s, ctx.qr, ctx.bn_ctx)) + goto out; + + if (!BN_div(ctx.q2, NULL, ctx.q2, ctx.m, ctx.bn_ctx)) + goto out; + + if (BN_num_bytes(ctx.q2) > SGX_MODULUS_SIZE) { + fprintf(stderr, "Too large Q2 %d bytes\n", + BN_num_bytes(ctx.q2)); + goto out; + } + + BN_bn2bin(ctx.q1, q1); + BN_bn2bin(ctx.q2, q2); + + free_q1q2_ctx(&ctx); + return true; +out: + free_q1q2_ctx(&ctx); + return false; +} + +static bool save_sigstruct(const struct sgx_sigstruct *sigstruct, + const char *path) +{ + FILE *f = fopen(path, "wb"); + + if (!f) { + fprintf(stderr, "Unable to open %s\n", path); + return false; + } + + fwrite(sigstruct, sizeof(*sigstruct), 1, f); + fclose(f); + return true; +} + +int main(int argc, char **argv) +{ + uint64_t header1[2] = {0x000000E100000006, 0x0000000000010000}; + uint64_t header2[2] = {0x0000006000000101, 0x0000000100000060}; + struct sgx_sigstruct ss; + const char *program; + int opt; + RSA *sign_key; + + memset(&ss, 0, sizeof(ss)); + ss.header.header1[0] = header1[0]; + ss.header.header1[1] = header1[1]; + ss.header.header2[0] = header2[0]; + ss.header.header2[1] = header2[1]; + ss.exponent = 3; + +#ifndef CONFIG_EINITTOKENKEY + ss.body.attributes = SGX_ATTR_MODE64BIT; +#else + ss.body.attributes = SGX_ATTR_MODE64BIT | SGX_ATTR_EINITTOKENKEY; +#endif + ss.body.xfrm = 3, + + sign_key_pass = getenv("KBUILD_SGX_SIGN_PIN"); + program = argv[0]; + + do { + opt = getopt(argc, argv, ""); + switch (opt) { + case -1: + break; + default: + exit_usage(program); + } + } while (opt != -1); + + argc -= optind; + argv += optind; + + if (argc < 3) + exit_usage(program); + + /* sanity check only */ + if (check_crypto_errors()) + exit(1); + + sign_key = load_sign_key(argv[0]); + if (!sign_key) + goto out; + + BN_bn2bin(get_modulus(sign_key), ss.modulus); + + if (!measure_encl(argv[1], ss.body.mrenclave)) + goto out; + + if (!sign_encl(&ss, sign_key, ss.signature)) + goto out; + + if (!calc_q1q2(ss.signature, ss.modulus, ss.q1, ss.q2)) + goto out; + + /* convert to little endian */ + reverse_bytes(ss.signature, SGX_MODULUS_SIZE); + reverse_bytes(ss.modulus, SGX_MODULUS_SIZE); + reverse_bytes(ss.q1, SGX_MODULUS_SIZE); + reverse_bytes(ss.q2, SGX_MODULUS_SIZE); + + if (!save_sigstruct(&ss, argv[2])) + goto out; + exit(0); +out: + check_crypto_errors(); + exit(1); +} diff --git a/tools/testing/selftests/x86/sgx/signing_key.pem b/tools/testing/selftests/x86/sgx/signing_key.pem new file mode 100644 index 000000000000..d76f21f19187 --- /dev/null +++ b/tools/testing/selftests/x86/sgx/signing_key.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG4wIBAAKCAYEApalGbq7Q+usM91CPtksu3D+b0Prc8gAFL6grM3mg85A5Bx8V +cfMXPgtrw8EYFwQxDAvzZWwl+9VfOX0ECrFRBkOHcOiG0SnADN8+FLj1UiNUQwbp +S6OzhNWuRcSbGraSOyUlVlV0yMQSvewyzGklOaXBe30AJqzIBc8QfdSxKuP8rs0Z +ga6k/Bl73osrYKByILJTUUeZqjLERsE6GebsdzbWgKn8qVqng4ZS4yMNg6LeRlH3 ++9CIPgg4jwpSLHcp7dq2qTIB9a0tGe9ayp+5FbucpB6U7ePold0EeRN6RlJGDF9k +L93v8P5ykz5G5gYZ2g0K1X2sHIWV4huxPgv5PXgdyQYbK+6olqj0d5rjYuwX57Ul +k6SroPS1U6UbdCjG5txM+BNGU0VpD0ZhrIRw0leQdnNcCO9sTJuInZrgYacSVJ7u +mtB+uCt+uzUesc+l+xPRYA+9e14lLkZp7AAmo9FvL816XDI09deehJ3i/LmHKCRN +tuqC5TprRjFwUr6dAgEDAoIBgG5w2Z8fNfycs0+LCnmHdJLVEotR6KFVWMpwHMz7 +wKJgJgS/Y6FMuilc8oKAuroCy11dTO5IGVKOP3uorVx2NgQtBPXwWeDGgAiU1A3Q +o4wXjYIEm4fCd63jyYPYZ2ckYXzDbjmOTdstYdPyzIhGGNEZK6eoqsRzMAPfYFPj +IMdCqHSIu6vJw1K7p+myHOsVoWshjODaZnF3LYSA0WaZ8vokjwBxUxuRxQJZjJds +s60XPtmL+qfgWtQFewoG4XL6GuD8FcXccynRRtzrLtFNPIl9BQfWfjBBhTC1/Te1 +0Z6XbZvpdUTD9OfLB7SbR2OUFNpKQgriO0iYVdbW3cr7uu38Zwp4W1TX73DPjoi6 +KNooP6SGWd4mRJW2+dUmSYS4QNG8eVVZswKcploEIXlAKRsOe4kzJJ1iETugIe85 +uX8nd1WYEp65xwoRUg8hqng0MeyveVbXqNKuJG6tzNDt9kgFYo+hmC/oouAW2Dtc +T9jdRAwKJXqA2Eg6OkgXCEv+kwKBwQDYaQiFMlFhsmLlqI+EzCUh7c941/cL7m6U +7j98+8ngl0HgCEcrc10iJVCKakQW3YbPzAx3XkKTaGjWazvvrFarXIGlOud64B8a +iWyQ7VdlnmZnNEdk+C83tI91OQeaTKqRLDGzKh29Ry/jL8Pcbazt+kDgxa0H7qJp +roADUanLQuNkYubpbhFBh3xpa2EExaVq6rF7nIVsD8W9TrbmPKA4LgH7z0iy544D +kVCNYsTjYDdUWP+WiSor8kCnnpjnN9sCgcEAw/eNezUD1UDf6OYFC9+5JZJFn4Tg +mZMyN93JKIb199ffwnjtHUSjcyiWeesXucpzwtGbTcwQnDisSW4oneYKLSEBlBaq +scqiUugyGZZOthFSCbdXYXMViK2vHrKlkse7GxVlROKcEhM/pRBrmjaGO8eWR+D4 +FO2wCXzVs3KgV6j779frw0vC54oHOxc9+Lu1rSHp4i+600koyvL/zF6U/5tZXIvN +YW2yoiQJnjCmVA1pwbwV6KAUTPDTMnBK+YjnAoHBAJBGBa4hi5Z27JkbCliIGMFJ +NPs6pLKe9GNJf6in2+sPgUAFhMeiPhbDiwbxgrnpBIqICE+ULGJFmzmc0p/IOceT +ARjR76dAFLxbnbXzj5kURETNhO36yiUjCk4mBRGIcbYddndxaSjaH+zKgpLzyJ6m +1esuc1qfFvEfAAI2cTIsl5hB70ZJYNZaUvDyQK3ZGPHxy6e9rkgKg9OJz0QoatAe +q/002yHvtAJg4F5B2JeVejg7VQ8GHB1MKxppu0TP5wKBwQCCpQj8zgKOKz/wmViy +lSYZDC5qWJW7t3bP6TDFr06lOpUsUJ4TgxeiGw778g/RMaKB4RIz3WBoJcgw9BsT +7rFza1ZiucchMcGMmswRDt8kC4wGejpA92Owc8oUdxkMhSdnY5jYlxK2t3/DYEe8 +JFl9L7mFQKVjSSAGUzkiTGrlG1Kf5UfXh9dFBq98uilQfSPIwUaWynyM23CHTKqI +Pw3/vOY9sojrnncWwrEUIG7is5vWfWPwargzSzd29YdRBe8CgcEAuRVewK/YeNOX +B7ZG6gKKsfsvrGtY7FPETzLZAHjoVXYNea4LVZ2kn4hBXXlvw/4HD+YqcTt4wmif +5JQlDvjNobUiKJZpzy7hklVhF7wZFl4pCF7Yh43q9iQ7gKTaeUG7MiaK+G8Zz8aY +HW9rsiihbdZkccMvnPfO9334XMxl3HtBRzLstjUlbLB7Sdh+7tZ3JQidCOFNs5pE +XyWwnASPu4tKfDahH1UUTp1uJcq/6716CSWg080avYxFcn75qqsb +-----END RSA PRIVATE KEY----- From patchwork Fri Dec 21 23:11:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 10741133 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 A8F0E1399 for ; Fri, 21 Dec 2018 23:16:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 99DC9286B3 for ; Fri, 21 Dec 2018 23:16:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 82BBB28726; Fri, 21 Dec 2018 23:16:03 +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 2DB3F286B3 for ; Fri, 21 Dec 2018 23:16:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733262AbeLUXQC (ORCPT ); Fri, 21 Dec 2018 18:16:02 -0500 Received: from mga14.intel.com ([192.55.52.115]:13797 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731892AbeLUXQC (ORCPT ); Fri, 21 Dec 2018 18:16:02 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Dec 2018 15:16:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,383,1539673200"; d="scan'208";a="120338809" Received: from ncanderx-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.238]) by FMSMGA003.fm.intel.com with ESMTP; 21 Dec 2018 15:15:54 -0800 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: akpm@linux-foundation.org, 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, bp@alien8.de, josh@joshtriplett.org, luto@kernel.org, Jarkko Sakkinen Subject: [PATCH v18 25/25] x86/sgx: Update MAINTAINERS Date: Sat, 22 Dec 2018 01:11:54 +0200 Message-Id: <20181221231154.6120-26-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181221231154.6120-1-jarkko.sakkinen@linux.intel.com> References: <20181221231154.6120-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 Add the maintainer information for the SGX subsystem. Signed-off-by: Jarkko Sakkinen --- MAINTAINERS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0abecc528dac..3d4144b5d831 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7676,6 +7676,18 @@ L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-intel-mid.c +INTEL SGX +M: Jarkko Sakkinen +M: Sean Christopherson +L: linux-sgx@vger.kernel.org +S: Maintained +Q: https://patchwork.kernel.org/project/intel-sgx/list/ +T: git https://github.com/jsakkine-intel/linux-sgx.git +F: arch/x86/include/asm/sgx.h +F: arch/x86/include/uapi/asm/sgx.h +F: arch/x86/kernel/cpu/sgx/* +K: \bSGX_ + INVENSENSE MPU-3050 GYROSCOPE DRIVER M: Linus Walleij L: linux-iio@vger.kernel.org