lkml.org 
[lkml]   [2020]   [Aug]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    From
    SubjectRe: [PATCH v36 12/24] x86/sgx: Add SGX_IOC_ENCLAVE_CREATE
    Date
    On Thursday, 2020-07-16 at 16:52:51 +03, Jarkko Sakkinen wrote:
    > Add an ioctl that performs ENCLS[ECREATE], which creates SGX Enclave
    > Control Structure for the enclave. SECS contains attributes about the
    > enclave that are used by the hardware and cannot be directly accessed by
    > software, as SECS resides in the EPC.
    >
    > One essential field in SECS is a field that stores the SHA256 of the
    > measured enclave pages. This field, MRENCLAVE, is initialized by the
    > ECREATE instruction and updated by every EADD and EEXTEND operation.
    > Finally, EINIT locks down the value.
    >
    > Acked-by: Jethro Beekman <jethro@fortanix.com>
    > Tested-by: Jethro Beekman <jethro@fortanix.com>
    > Tested-by: Haitao Huang <haitao.huang@linux.intel.com>
    > Tested-by: Chunyang Hui <sanqian.hcy@antfin.com>
    > Tested-by: Jordan Hand <jorhand@linux.microsoft.com>
    > Tested-by: Nathaniel McCallum <npmccallum@redhat.com>
    > Tested-by: Seth Moore <sethmo@google.com>

    Tested-by: Darren Kenny <darren.kenny@oracle.com>
    Reviewed-by: Darren Kenny <darren.kenny@oracle.com>

    > Co-developed-by: Sean Christopherson <sean.j.christopherson@intel.com>
    > Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
    > Co-developed-by: Suresh Siddha <suresh.b.siddha@intel.com>
    > Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
    > Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
    > ---
    > .../userspace-api/ioctl/ioctl-number.rst | 1 +
    > arch/x86/include/uapi/asm/sgx.h | 25 ++
    > arch/x86/kernel/cpu/sgx/Makefile | 1 +
    > arch/x86/kernel/cpu/sgx/driver.c | 12 +
    > arch/x86/kernel/cpu/sgx/driver.h | 1 +
    > arch/x86/kernel/cpu/sgx/ioctl.c | 226 ++++++++++++++++++
    > 6 files changed, 266 insertions(+)
    > create mode 100644 arch/x86/include/uapi/asm/sgx.h
    > create mode 100644 arch/x86/kernel/cpu/sgx/ioctl.c
    >
    > diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
    > index 59472cd6a11d..35f713e3a267 100644
    > --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
    > +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
    > @@ -323,6 +323,7 @@ Code Seq# Include File Comments
    > <mailto:tlewis@mindspring.com>
    > 0xA3 90-9F linux/dtlk.h
    > 0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem
    > +0xA4 00-1F uapi/asm/sgx.h Intel SGX subsystem (a legit conflict as TEE and SGX do not co-exist)
    > 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/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
    > new file mode 100644
    > index 000000000000..3787d278e84b
    > --- /dev/null
    > +++ b/arch/x86/include/uapi/asm/sgx.h
    > @@ -0,0 +1,25 @@
    > +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) WITH Linux-syscall-note */
    > +/*
    > + * Copyright(c) 2016-19 Intel Corporation.
    > + */
    > +#ifndef _UAPI_ASM_X86_SGX_H
    > +#define _UAPI_ASM_X86_SGX_H
    > +
    > +#include <linux/types.h>
    > +#include <linux/ioctl.h>
    > +
    > +#define SGX_MAGIC 0xA4
    > +
    > +#define SGX_IOC_ENCLAVE_CREATE \
    > + _IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create)
    > +
    > +/**
    > + * 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;
    > +};
    > +
    > +#endif /* _UAPI_ASM_X86_SGX_H */
    > diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makefile
    > index 3fc451120735..91d3dc784a29 100644
    > --- a/arch/x86/kernel/cpu/sgx/Makefile
    > +++ b/arch/x86/kernel/cpu/sgx/Makefile
    > @@ -1,4 +1,5 @@
    > obj-y += \
    > driver.o \
    > encl.o \
    > + ioctl.o \
    > main.o
    > diff --git a/arch/x86/kernel/cpu/sgx/driver.c b/arch/x86/kernel/cpu/sgx/driver.c
    > index b52520407f5b..5559bc18de41 100644
    > --- a/arch/x86/kernel/cpu/sgx/driver.c
    > +++ b/arch/x86/kernel/cpu/sgx/driver.c
    > @@ -118,10 +118,22 @@ static unsigned long sgx_get_unmapped_area(struct file *file,
    > return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
    > }
    >
    > +#ifdef CONFIG_COMPAT
    > +static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
    > + unsigned long arg)
    > +{
    > + return sgx_ioctl(filep, cmd, arg);
    > +}
    > +#endif
    > +
    > static const struct file_operations sgx_encl_fops = {
    > .owner = THIS_MODULE,
    > .open = sgx_open,
    > .release = sgx_release,
    > + .unlocked_ioctl = sgx_ioctl,
    > +#ifdef CONFIG_COMPAT
    > + .compat_ioctl = sgx_compat_ioctl,
    > +#endif
    > .mmap = sgx_mmap,
    > .get_unmapped_area = sgx_get_unmapped_area,
    > };
    > diff --git a/arch/x86/kernel/cpu/sgx/driver.h b/arch/x86/kernel/cpu/sgx/driver.h
    > index f7ce40dedc91..e4063923115b 100644
    > --- a/arch/x86/kernel/cpu/sgx/driver.h
    > +++ b/arch/x86/kernel/cpu/sgx/driver.h
    > @@ -9,6 +9,7 @@
    > #include <linux/rwsem.h>
    > #include <linux/sched.h>
    > #include <linux/workqueue.h>
    > +#include <uapi/asm/sgx.h>
    > #include "sgx.h"
    >
    > #define SGX_EINIT_SPIN_COUNT 20
    > diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
    > new file mode 100644
    > index 000000000000..7981c411b05a
    > --- /dev/null
    > +++ b/arch/x86/kernel/cpu/sgx/ioctl.c
    > @@ -0,0 +1,226 @@
    > +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
    > +// Copyright(c) 2016-19 Intel Corporation.
    > +
    > +#include <asm/mman.h>
    > +#include <linux/mman.h>
    > +#include <linux/delay.h>
    > +#include <linux/file.h>
    > +#include <linux/hashtable.h>
    > +#include <linux/highmem.h>
    > +#include <linux/ratelimit.h>
    > +#include <linux/sched/signal.h>
    > +#include <linux/shmem_fs.h>
    > +#include <linux/slab.h>
    > +#include <linux/suspend.h>
    > +#include "driver.h"
    > +#include "encl.h"
    > +#include "encls.h"
    > +
    > +static u32 sgx_calc_ssa_frame_size(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)
    > +{
    > + u64 max_size = (secs->attributes & SGX_ATTR_MODE64BIT) ?
    > + sgx_encl_size_max_64 : sgx_encl_size_max_32;
    > +
    > + if (secs->size < (2 * PAGE_SIZE) || !is_power_of_2(secs->size))
    > + return -EINVAL;
    > +
    > + if (secs->base & (secs->size - 1))
    > + return -EINVAL;
    > +
    > + if (secs->miscselect & sgx_misc_reserved_mask ||
    > + secs->attributes & sgx_attributes_reserved_mask ||
    > + secs->xfrm & sgx_xfrm_reserved_mask)
    > + return -EINVAL;
    > +
    > + if (secs->size >= max_size)
    > + return -EINVAL;
    > +
    > + if (!(secs->xfrm & XFEATURE_MASK_FP) ||
    > + !(secs->xfrm & XFEATURE_MASK_SSE) ||
    > + (((secs->xfrm >> XFEATURE_BNDREGS) & 1) !=
    > + ((secs->xfrm >> XFEATURE_BNDCSR) & 1)))
    > + return -EINVAL;
    > +
    > + if (!secs->ssa_frame_size)
    > + return -EINVAL;
    > +
    > + if (sgx_calc_ssa_frame_size(secs->miscselect, secs->xfrm) >
    > + secs->ssa_frame_size)
    > + return -EINVAL;
    > +
    > + if (memchr_inv(secs->reserved1, 0, sizeof(secs->reserved1)) ||
    > + memchr_inv(secs->reserved2, 0, sizeof(secs->reserved2)) ||
    > + memchr_inv(secs->reserved3, 0, sizeof(secs->reserved3)) ||
    > + memchr_inv(secs->reserved4, 0, sizeof(secs->reserved4)))
    > + return -EINVAL;
    > +
    > + return 0;
    > +}
    > +
    > +static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
    > +{
    > + unsigned long encl_size = secs->size + PAGE_SIZE;
    > + struct sgx_epc_page *secs_epc;
    > + struct sgx_pageinfo pginfo;
    > + struct sgx_secinfo secinfo;
    > + struct file *backing;
    > + long ret;
    > +
    > + if (sgx_validate_secs(secs)) {
    > + pr_debug("invalid SECS\n");
    > + return -EINVAL;
    > + }
    > +
    > + backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
    > + VM_NORESERVE);
    > + if (IS_ERR(backing))
    > + return PTR_ERR(backing);
    > +
    > + encl->backing = backing;
    > +
    > + secs_epc = __sgx_alloc_epc_page();
    > + if (IS_ERR(secs_epc)) {
    > + ret = PTR_ERR(secs_epc);
    > + goto err_out_backing;
    > + }
    > +
    > + encl->secs.epc_page = secs_epc;
    > +
    > + 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_get_epc_addr(secs_epc));
    > + if (ret) {
    > + pr_debug("ECREATE returned %ld\n", ret);
    > + goto err_out;
    > + }
    > +
    > + if (secs->attributes & SGX_ATTR_DEBUG)
    > + atomic_or(SGX_ENCL_DEBUG, &encl->flags);
    > +
    > + encl->secs.encl = encl;
    > + encl->secs_attributes = secs->attributes;
    > + encl->allowed_attributes |= SGX_ATTR_ALLOWED_MASK;
    > + encl->base = secs->base;
    > + encl->size = secs->size;
    > + encl->ssaframesize = secs->ssa_frame_size;
    > +
    > + /*
    > + * Set SGX_ENCL_CREATED only after the enclave is fully prepped. This
    > + * allows setting and checking enclave creation without having to take
    > + * encl->lock.
    > + */
    > + atomic_or(SGX_ENCL_CREATED, &encl->flags);
    > +
    > + return 0;
    > +
    > +err_out:
    > + sgx_free_epc_page(encl->secs.epc_page);
    > + encl->secs.epc_page = NULL;
    > +
    > +err_out_backing:
    > + fput(encl->backing);
    > + encl->backing = NULL;
    > +
    > + return ret;
    > +}
    > +
    > +/**
    > + * sgx_ioc_enclave_create - handler for %SGX_IOC_ENCLAVE_CREATE
    > + * @filep: open file to /dev/sgx
    > + * @arg: userspace pointer to a struct sgx_enclave_create instance
    > + *
    > + * Allocate kernel data structures for a new enclave and execute ECREATE after
    > + * verifying the correctness of the provided SECS.
    > + *
    > + * Note, enforcement of restricted and disallowed attributes is deferred until
    > + * sgx_ioc_enclave_init(), only the architectural correctness of the SECS is
    > + * checked by sgx_ioc_enclave_create().
    > + *
    > + * Return:
    > + * 0 on success,
    > + * -errno otherwise
    > + */
    > +static long sgx_ioc_enclave_create(struct sgx_encl *encl, void __user *arg)
    > +{
    > + struct sgx_enclave_create ecreate;
    > + struct page *secs_page;
    > + struct sgx_secs *secs;
    > + int ret;
    > +
    > + if (atomic_read(&encl->flags) & SGX_ENCL_CREATED)
    > + return -EINVAL;
    > +
    > + if (copy_from_user(&ecreate, arg, sizeof(ecreate)))
    > + return -EFAULT;
    > +
    > + secs_page = alloc_page(GFP_KERNEL);
    > + if (!secs_page)
    > + return -ENOMEM;
    > +
    > + secs = kmap(secs_page);
    > + if (copy_from_user(secs, (void __user *)ecreate.src, sizeof(*secs))) {
    > + ret = -EFAULT;
    > + goto out;
    > + }
    > +
    > + ret = sgx_encl_create(encl, secs);
    > +
    > +out:
    > + kunmap(secs_page);
    > + __free_page(secs_page);
    > + return ret;
    > +}
    > +
    > +long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
    > +{
    > + struct sgx_encl *encl = filep->private_data;
    > + int ret, encl_flags;
    > +
    > + encl_flags = atomic_fetch_or(SGX_ENCL_IOCTL, &encl->flags);
    > + if (encl_flags & SGX_ENCL_IOCTL)
    > + return -EBUSY;
    > +
    > + if (encl_flags & SGX_ENCL_DEAD) {
    > + ret = -EFAULT;
    > + goto out;
    > + }
    > +
    > + switch (cmd) {
    > + case SGX_IOC_ENCLAVE_CREATE:
    > + ret = sgx_ioc_enclave_create(encl, (void __user *)arg);
    > + break;
    > + default:
    > + ret = -ENOIOCTLCMD;
    > + break;
    > + }
    > +
    > +out:
    > + atomic_andnot(SGX_ENCL_IOCTL, &encl->flags);
    > + return ret;
    > +}
    > --
    > 2.25.1

    \
     
     \ /
      Last update: 2020-08-06 22:26    [W:3.133 / U:0.152 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site