Message ID | 20201104145430.300542-4-jarkko.sakkinen@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Intel SGX foundations | expand |
On Wed, Nov 04, 2020 at 04:54:09PM +0200, Jarkko Sakkinen wrote: > +static void __init sgx_init(void) > +{ > + int i; > + > + if (!boot_cpu_has(X86_FEATURE_SGX)) Guys, you need to build-test *every* *single* patch - otherwise we break bisectability and that is a no-no: arch/x86/kernel/cpu/sgx/main.c: In function ‘sgx_init’: arch/x86/kernel/cpu/sgx/main.c:172:20: error: ‘X86_FEATURE_SGX’ undeclared (first use in this function); did you mean ‘X86_FEATURE_SMX’? 172 | if (!boot_cpu_has(X86_FEATURE_SGX)) | ^~~~~~~~~~~~~~~ ./arch/x86/include/asm/cpufeature.h:118:24: note: in definition of macro ‘cpu_has’ 118 | (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ | ^~~ arch/x86/kernel/cpu/sgx/main.c:172:7: note: in expansion of macro ‘boot_cpu_has’ 172 | if (!boot_cpu_has(X86_FEATURE_SGX)) | ^~~~~~~~~~~~ arch/x86/kernel/cpu/sgx/main.c:172:20: note: each undeclared identifier is reported only once for each function it appears in 172 | if (!boot_cpu_has(X86_FEATURE_SGX)) | ^~~~~~~~~~~~~~~ ./arch/x86/include/asm/cpufeature.h:118:24: note: in definition of macro ‘cpu_has’ 118 | (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ | ^~~ arch/x86/kernel/cpu/sgx/main.c:172:7: note: in expansion of macro ‘boot_cpu_has’ 172 | if (!boot_cpu_has(X86_FEATURE_SGX)) | ^~~~~~~~~~~~ make[4]: *** [scripts/Makefile.build:283: arch/x86/kernel/cpu/sgx/main.o] Error 1 make[3]: *** [scripts/Makefile.build:500: arch/x86/kernel/cpu/sgx] Error 2 make[2]: *** [scripts/Makefile.build:500: arch/x86/kernel/cpu] Error 2 make[2]: *** Waiting for unfinished jobs.... make[1]: *** [scripts/Makefile.build:500: arch/x86/kernel] Error 2 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1799: arch/x86] Error 2 make: *** Waiting for unfinished jobs....
On Wed, Nov 04, 2020 at 07:21:29PM +0100, Borislav Petkov wrote: > On Wed, Nov 04, 2020 at 04:54:09PM +0200, Jarkko Sakkinen wrote: > > +static void __init sgx_init(void) > > +{ > > + int i; > > + > > + if (!boot_cpu_has(X86_FEATURE_SGX)) > > Guys, you need to build-test *every* *single* patch - otherwise we break > bisectability and that is a no-no: I've done it quite a few times (every time I've rebased my tree). I did today too before sending but forgot to redo git format-patch again (was the very last thing). In my tree the order is: e987eb0c95dd (HEAD -> master, origin/master, origin/HEAD) x86/sgx: Update MAINTAINERS 90dc0ee37f44 docs: x86/sgx: Document SGX kernel architecture 1c2e9bdab128 x86/sgx: Add ptrace() support for the SGX driver 05ce4345fb5f x86/sgx: Add a page reclaimer 94c1f778fa09 selftests/x86: Add a selftest for SGX 741b631d197b x86/vdso: Implement a vDSO for Intel SGX enclave call 5744b02641ff x86/traps: Attempt to fixup exceptions in vDSO before signaling e957c7e79dd0 x86/fault: Add helper function to sanitize error code 96cc520b2bc9 x86/vdso: Add support for exception fixup in vDSO functions 4aff9d81b2fe x86/sgx: Add SGX_IOC_ENCLAVE_PROVISION ea9bc917c469 x86/sgx: Add SGX_IOC_ENCLAVE_INIT 6e61e843291d x86/sgx: Add SGX_IOC_ENCLAVE_ADD_PAGES 4235ce22235e x86/sgx: Add SGX_IOC_ENCLAVE_CREATE 681299401c91 x86/sgx: Add SGX misc driver interface fbd69fd9acf4 mm: Add 'mprotect' hook to struct vm_operations_struct 93b27a8908aa x86/sgx: Add SGX page allocator functions 5984a2ca130c x86/cpu/intel: Add nosgx kernel parameter e131efe5ba06 x86/cpu/intel: Detect SGX support b0bacb54d36c x86/mm: x86/sgx: Signal SIGSEGV with PF_SGX 0c64b4c07298 x86/sgx: Initialize metadata for Enclave Page Cache (EPC) sections 358d17098c4c x86/cpufeatures: x86/msr: Add Intel SGX Launch Control hardware bits 8f7ab60e5458 x86/cpufeatures: x86/msr: Add Intel SGX hardware bits 0fb18ca935cf x86/sgx: Add wrappers for ENCLS functions 3dbc95582baf x86/sgx: Add SGX architectural data structures I always do this before I send the patch set (or rebase my tree): for x in {23..0} do git checkout master~$x git clean -f -d -x make tinyconfig && cat >> .config <<EOF CONFIG_64BIT=y CONFIG_CRYPTO=y CONFIG_CRYPTO_SHA256=y CONFIG_X86_SGX=y CONFIG_DEBUG_INFO=y EOF yes '' | make oldconfig && make CC="ccache gcc" -j$(nproc) || break git --no-pager log --oneline -1 >> success.txt done The order is the only difference between the patch set and my tree (i.e. diff's do not conflict between the orderings). > arch/x86/kernel/cpu/sgx/main.c: In function ‘sgx_init’: > arch/x86/kernel/cpu/sgx/main.c:172:20: error: ‘X86_FEATURE_SGX’ undeclared (first use in this function); did you mean ‘X86_FEATURE_SMX’? > 172 | if (!boot_cpu_has(X86_FEATURE_SGX)) > | ^~~~~~~~~~~~~~~ > ./arch/x86/include/asm/cpufeature.h:118:24: note: in definition of macro ‘cpu_has’ > 118 | (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ > | ^~~ > arch/x86/kernel/cpu/sgx/main.c:172:7: note: in expansion of macro ‘boot_cpu_has’ > 172 | if (!boot_cpu_has(X86_FEATURE_SGX)) > | ^~~~~~~~~~~~ > arch/x86/kernel/cpu/sgx/main.c:172:20: note: each undeclared identifier is reported only once for each function it appears in > 172 | if (!boot_cpu_has(X86_FEATURE_SGX)) > | ^~~~~~~~~~~~~~~ > ./arch/x86/include/asm/cpufeature.h:118:24: note: in definition of macro ‘cpu_has’ > 118 | (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ > | ^~~ > arch/x86/kernel/cpu/sgx/main.c:172:7: note: in expansion of macro ‘boot_cpu_has’ > 172 | if (!boot_cpu_has(X86_FEATURE_SGX)) > | ^~~~~~~~~~~~ > make[4]: *** [scripts/Makefile.build:283: arch/x86/kernel/cpu/sgx/main.o] Error 1 > make[3]: *** [scripts/Makefile.build:500: arch/x86/kernel/cpu/sgx] Error 2 > make[2]: *** [scripts/Makefile.build:500: arch/x86/kernel/cpu] Error 2 > make[2]: *** Waiting for unfinished jobs.... > make[1]: *** [scripts/Makefile.build:500: arch/x86/kernel] Error 2 > make[1]: *** Waiting for unfinished jobs.... > make: *** [Makefile:1799: arch/x86] Error 2 > make: *** Waiting for unfinished jobs.... > > -- > Regards/Gruss, > Boris. > > https://people.kernel.org/tglx/notes-about-netiquette /Jarkko
On Wed, Nov 04, 2020 at 09:04:52PM +0200, Jarkko Sakkinen wrote: > On Wed, Nov 04, 2020 at 07:21:29PM +0100, Borislav Petkov wrote: > > On Wed, Nov 04, 2020 at 04:54:09PM +0200, Jarkko Sakkinen wrote: > > > +static void __init sgx_init(void) > > > +{ > > > + int i; > > > + > > > + if (!boot_cpu_has(X86_FEATURE_SGX)) > > > > Guys, you need to build-test *every* *single* patch - otherwise we break > > bisectability and that is a no-no: > > I've done it quite a few times (every time I've rebased my tree). I did > today too before sending but forgot to redo git format-patch again (was > the very last thing). In my tree the order is: If you want, I can do a resend of this version same time underlining that this the only difference and I do have a framework to check this thing in place. > e987eb0c95dd (HEAD -> master, origin/master, origin/HEAD) x86/sgx: Update MAINTAINERS > 90dc0ee37f44 docs: x86/sgx: Document SGX kernel architecture > 1c2e9bdab128 x86/sgx: Add ptrace() support for the SGX driver > 05ce4345fb5f x86/sgx: Add a page reclaimer > 94c1f778fa09 selftests/x86: Add a selftest for SGX > 741b631d197b x86/vdso: Implement a vDSO for Intel SGX enclave call > 5744b02641ff x86/traps: Attempt to fixup exceptions in vDSO before signaling > e957c7e79dd0 x86/fault: Add helper function to sanitize error code > 96cc520b2bc9 x86/vdso: Add support for exception fixup in vDSO functions > 4aff9d81b2fe x86/sgx: Add SGX_IOC_ENCLAVE_PROVISION > ea9bc917c469 x86/sgx: Add SGX_IOC_ENCLAVE_INIT > 6e61e843291d x86/sgx: Add SGX_IOC_ENCLAVE_ADD_PAGES > 4235ce22235e x86/sgx: Add SGX_IOC_ENCLAVE_CREATE > 681299401c91 x86/sgx: Add SGX misc driver interface > fbd69fd9acf4 mm: Add 'mprotect' hook to struct vm_operations_struct > 93b27a8908aa x86/sgx: Add SGX page allocator functions > 5984a2ca130c x86/cpu/intel: Add nosgx kernel parameter > e131efe5ba06 x86/cpu/intel: Detect SGX support > b0bacb54d36c x86/mm: x86/sgx: Signal SIGSEGV with PF_SGX > 0c64b4c07298 x86/sgx: Initialize metadata for Enclave Page Cache (EPC) sections > 358d17098c4c x86/cpufeatures: x86/msr: Add Intel SGX Launch Control hardware bits > 8f7ab60e5458 x86/cpufeatures: x86/msr: Add Intel SGX hardware bits > 0fb18ca935cf x86/sgx: Add wrappers for ENCLS functions > 3dbc95582baf x86/sgx: Add SGX architectural data structures > > I always do this before I send the patch set (or rebase my tree): > > for x in {23..0} > do > git checkout master~$x > git clean -f -d -x > make tinyconfig && cat >> .config <<EOF > CONFIG_64BIT=y > CONFIG_CRYPTO=y > CONFIG_CRYPTO_SHA256=y > CONFIG_X86_SGX=y > CONFIG_DEBUG_INFO=y > EOF > yes '' | make oldconfig && make CC="ccache gcc" -j$(nproc) || break > git --no-pager log --oneline -1 >> success.txt > done > > The order is the only difference between the patch set and my tree (i.e. > diff's do not conflict between the orderings). /Jarkko
On Wed, Nov 04, 2020 at 09:09:03PM +0200, Jarkko Sakkinen wrote: > If you want, I can do a resend of this version same time underlining > that this the only difference and I do have a framework to check this > thing in place. No need - I'll simply reorder them here and see how far I'd get. Thx.
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f6946b81f74a..618d1aabccb8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1930,6 +1930,23 @@ config X86_INTEL_TSX_MODE_AUTO side channel attacks- equals the tsx=auto command line parameter. endchoice +config X86_SGX + bool "Software Guard eXtensions (SGX)" + depends on X86_64 && CPU_SUP_INTEL + depends on CRYPTO=y + depends on CRYPTO_SHA256=y + select SRCU + select MMU_NOTIFIER + help + Intel(R) Software Guard eXtensions (SGX) is a set of CPU instructions + that can be used by applications to set aside private regions of code + and data, referred to as enclaves. An enclave's private memory can + only be accessed by code running within the enclave. Accesses from + outside the enclave, including other enclaves, are disallowed by + hardware. + + If unsure, say N. + config EFI bool "EFI runtime service support" depends on ACPI diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 93792b457b81..637b499450d1 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_X86_MCE) += mce/ obj-$(CONFIG_MTRR) += mtrr/ obj-$(CONFIG_MICROCODE) += microcode/ obj-$(CONFIG_X86_CPU_RESCTRL) += resctrl/ +obj-$(CONFIG_X86_SGX) += sgx/ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makefile new file mode 100644 index 000000000000..79510ce01b3b --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/Makefile @@ -0,0 +1,2 @@ +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..956055a0eff6 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2016-20 Intel Corporation. */ + +#include <linux/freezer.h> +#include <linux/highmem.h> +#include <linux/kthread.h> +#include <linux/pagemap.h> +#include <linux/ratelimit.h> +#include <linux/sched/mm.h> +#include <linux/sched/signal.h> +#include <linux/slab.h> +#include "encls.h" + +struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; +static int sgx_nr_epc_sections; +static struct task_struct *ksgxswapd_tsk; + +/* + * Reset dirty EPC pages to uninitialized state. Laundry can be left with SECS + * pages whose child pages blocked EREMOVE. + */ +static void sgx_sanitize_section(struct sgx_epc_section *section) +{ + struct sgx_epc_page *page; + LIST_HEAD(dirty); + int ret; + + while (!list_empty(§ion->laundry_list)) { + if (kthread_should_stop()) + return; + + spin_lock(§ion->lock); + + page = list_first_entry(§ion->laundry_list, + struct sgx_epc_page, list); + + ret = __eremove(sgx_get_epc_virt_addr(page)); + if (!ret) + list_move(&page->list, §ion->page_list); + else + list_move_tail(&page->list, &dirty); + + spin_unlock(§ion->lock); + + cond_resched(); + } + + list_splice(&dirty, §ion->laundry_list); +} + +static int ksgxswapd(void *p) +{ + int i; + + set_freezable(); + + /* + * Sanitize pages in order to recover from kexec(). The 2nd pass is + * required for SECS pages, whose child pages blocked EREMOVE. + */ + for (i = 0; i < sgx_nr_epc_sections; i++) + sgx_sanitize_section(&sgx_epc_sections[i]); + + for (i = 0; i < sgx_nr_epc_sections; i++) { + sgx_sanitize_section(&sgx_epc_sections[i]); + + /* Should never happen. */ + if (!list_empty(&sgx_epc_sections[i].laundry_list)) + WARN(1, "EPC section %d has unsanitized pages.\n", i); + } + + return 0; +} + +static bool __init sgx_page_reclaimer_init(void) +{ + struct task_struct *tsk; + + tsk = kthread_run(ksgxswapd, NULL, "ksgxswapd"); + if (IS_ERR(tsk)) + return false; + + ksgxswapd_tsk = tsk; + + return true; +} + +static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size, + unsigned long index, + struct sgx_epc_section *section) +{ + unsigned long nr_pages = size >> PAGE_SHIFT; + unsigned long i; + + section->virt_addr = memremap(phys_addr, size, MEMREMAP_WB); + if (!section->virt_addr) + return false; + + section->pages = vmalloc(nr_pages * sizeof(struct sgx_epc_page)); + if (!section->pages) { + memunmap(section->virt_addr); + return false; + } + + section->phys_addr = phys_addr; + spin_lock_init(§ion->lock); + INIT_LIST_HEAD(§ion->page_list); + INIT_LIST_HEAD(§ion->laundry_list); + + for (i = 0; i < nr_pages; i++) { + section->pages[i].section = index; + list_add_tail(§ion->pages[i].list, §ion->laundry_list); + } + + return true; +} + +/** + * 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 __init sgx_calc_section_metric(u64 low, u64 high) +{ + return (low & GENMASK_ULL(31, 12)) + + ((high & GENMASK_ULL(19, 0)) << 32); +} + +static bool __init sgx_page_cache_init(void) +{ + u32 eax, ebx, ecx, edx, type; + u64 pa, size; + int i; + + for (i = 0; i < ARRAY_SIZE(sgx_epc_sections); i++) { + cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC, &eax, &ebx, &ecx, &edx); + + type = eax & SGX_CPUID_EPC_MASK; + if (type == SGX_CPUID_EPC_INVALID) + break; + + if (type != SGX_CPUID_EPC_SECTION) { + pr_err_once("Unknown EPC section type: %u\n", type); + break; + } + + pa = sgx_calc_section_metric(eax, ebx); + size = sgx_calc_section_metric(ecx, edx); + + pr_info("EPC section 0x%llx-0x%llx\n", pa, pa + size - 1); + + if (!sgx_setup_epc_section(pa, size, i, &sgx_epc_sections[i])) { + pr_err("No free memory for an EPC section\n"); + break; + } + + sgx_nr_epc_sections++; + } + + if (!sgx_nr_epc_sections) { + pr_err("There are zero EPC sections.\n"); + return false; + } + + return true; +} + +static void __init sgx_init(void) +{ + int i; + + if (!boot_cpu_has(X86_FEATURE_SGX)) + return; + + if (!sgx_page_cache_init()) + return; + + if (!sgx_page_reclaimer_init()) + goto err_page_cache; + + return; + +err_page_cache: + for (i = 0; i < sgx_nr_epc_sections; i++) { + vfree(sgx_epc_sections[i].pages); + memunmap(sgx_epc_sections[i].virt_addr); + } +} + +device_initcall(sgx_init); diff --git a/arch/x86/kernel/cpu/sgx/sgx.h b/arch/x86/kernel/cpu/sgx/sgx.h new file mode 100644 index 000000000000..02afa84dd8fd --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/sgx.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _X86_SGX_H +#define _X86_SGX_H + +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/rwsem.h> +#include <linux/types.h> +#include <asm/asm.h> +#include "arch.h" + +#undef pr_fmt +#define pr_fmt(fmt) "sgx: " fmt + +#define SGX_MAX_EPC_SECTIONS 8 + +struct sgx_epc_page { + unsigned int section; + struct list_head list; +}; + +/* + * 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 phys_addr; + void *virt_addr; + struct list_head page_list; + struct list_head laundry_list; + struct sgx_epc_page *pages; + spinlock_t lock; +}; + +extern struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; + +static inline unsigned long sgx_get_epc_phys_addr(struct sgx_epc_page *page) +{ + struct sgx_epc_section *section = &sgx_epc_sections[page->section]; + unsigned long index; + + index = ((unsigned long)page - (unsigned long)section->pages) / sizeof(*page); + + return section->phys_addr + index * PAGE_SIZE; +} + +static inline void *sgx_get_epc_virt_addr(struct sgx_epc_page *page) +{ + struct sgx_epc_section *section = &sgx_epc_sections[page->section]; + unsigned long index; + + index = ((unsigned long)page - (unsigned long)section->pages) / sizeof(*page); + + return section->virt_addr + index * PAGE_SIZE; +} + +#endif /* _X86_SGX_H */