2020-09-16 00:55:33

by Jarkko Sakkinen

[permalink] [raw]
Subject: [PATCH v38 12/24] x86/sgx: Add SGX_IOC_ENCLAVE_CREATE

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 <[email protected]>
Tested-by: Jethro Beekman <[email protected]>
Tested-by: Haitao Huang <[email protected]>
Tested-by: Chunyang Hui <[email protected]>
Tested-by: Jordan Hand <[email protected]>
Tested-by: Nathaniel McCallum <[email protected]>
Tested-by: Seth Moore <[email protected]>
Tested-by: Darren Kenny <[email protected]>
Reviewed-by: Darren Kenny <[email protected]>
Co-developed-by: Sean Christopherson <[email protected]>
Signed-off-by: Sean Christopherson <[email protected]>
Co-developed-by: Suresh Siddha <[email protected]>
Signed-off-by: Suresh Siddha <[email protected]>
Signed-off-by: Jarkko Sakkinen <[email protected]>
---
.../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 | 220 ++++++++++++++++++
6 files changed, 260 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 2a198838fca9..a89e1c46a25a 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:[email protected]>
0xA3 90-9F linux/dtlk.h
0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem
+0xA4 00-1F uapi/asm/sgx.h <mailto:[email protected]>
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..c75b375f3770
--- /dev/null
+++ b/arch/x86/include/uapi/asm/sgx.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) */
+/*
+ * 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 f54da5f19c2b..7bdb49dfcca6 100644
--- a/arch/x86/kernel/cpu/sgx/driver.c
+++ b/arch/x86/kernel/cpu/sgx/driver.c
@@ -114,10 +114,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..352a3c461812
--- /dev/null
+++ b/arch/x86/kernel/cpu/sgx/ioctl.c
@@ -0,0 +1,220 @@
+// 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->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.
+ *
+ * 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


2020-09-21 10:05:31

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH v38 12/24] x86/sgx: Add SGX_IOC_ENCLAVE_CREATE

On Tue, Sep 15, 2020 at 02:28:30PM +0300, Jarkko Sakkinen wrote:
> +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)))

Let that last line stick out so that you have each statement on a single line.

> + return -EINVAL;
> +
> + if (!secs->ssa_frame_size)
> + return -EINVAL;
> +
> + if (sgx_calc_ssa_frame_size(secs->miscselect, secs->xfrm) >
> + secs->ssa_frame_size)

Let that stick out.

> + 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;

You're still using secs->size before validation. I know, we will return
early if sgx_validate_secs() fails but pls move that addition after the
validation call.

...

> +/**
> + * sgx_ioc_enclave_create - handler for %SGX_IOC_ENCLAVE_CREATE
> + * @filep: open file to /dev/sgx

Dammit, how many times do I have to type this comment here?!

"That's

@encl: enclave pointer

or so."

There's no filep - there is an encl!


> + * @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.

... which is done in sgx_validate_secs()."

Yes, spell it out, otherwise one has to wonder where that validation is
happening in the function *below* because the comment is over it - not
over sgx_validate_secs().

And yes, you need to spell stuff like that out because this SGX crap is
complex and it better be properly documented!

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2020-09-21 12:32:50

by Jarkko Sakkinen

[permalink] [raw]
Subject: Re: [PATCH v38 12/24] x86/sgx: Add SGX_IOC_ENCLAVE_CREATE

On Mon, Sep 21, 2020 at 12:03:56PM +0200, Borislav Petkov wrote:
> On Tue, Sep 15, 2020 at 02:28:30PM +0300, Jarkko Sakkinen wrote:
> > +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)))
>
> Let that last line stick out so that you have each statement on a single line.
>
> > + return -EINVAL;
> > +
> > + if (!secs->ssa_frame_size)
> > + return -EINVAL;
> > +
> > + if (sgx_calc_ssa_frame_size(secs->miscselect, secs->xfrm) >
> > + secs->ssa_frame_size)
>
> Let that stick out.
>
> > + 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;
>
> You're still using secs->size before validation. I know, we will return
> early if sgx_validate_secs() fails but pls move that addition after the
> validation call.

Is this appropriate:

/* The extra page in swap space goes to SECS. */
encl_size = secs->size + PAGE_SIZE;

backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
VM_NORESERVE);
if (IS_ERR(backing)) {
ret = PTR_ERR(backing);
goto err_out_shrink;
}

> ...
>
> > +/**
> > + * sgx_ioc_enclave_create - handler for %SGX_IOC_ENCLAVE_CREATE
> > + * @filep: open file to /dev/sgx
>
> Dammit, how many times do I have to type this comment here?!
>
> "That's
>
> @encl: enclave pointer
>
> or so."
>
> There's no filep - there is an encl!

I'm not actually sure what has happened. As you can easily grep, the
rename is done in five other sites. I also see a similar problem in
EINIT, which I will fix.

git grep "enclave pointer" arch/x86/kernel/cpu/sgx/ | wc -l
5

> > + * @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.
>
> ... which is done in sgx_validate_secs()."
>
> Yes, spell it out, otherwise one has to wonder where that validation is
> happening in the function *below* because the comment is over it - not
> over sgx_validate_secs().
>
> And yes, you need to spell stuff like that out because this SGX crap is
> complex and it better be properly documented!

I agree with this but I also think it would make sense to rephrase
"verifying the correctness of the provided SECS" with something more
informative.

I would rephrase as:

"... after checking that the provided data for SECS meets the expectations
of ENCLS[ECREATE] for an unitialized enclave and size of the address
space does not surpass the platform expectations. This validation is
executed by sgx_validate_secs()."

Is this sufficient for you, or do you have further suggestions?

> --
> Regards/Gruss,
> Boris.
>
> https://people.kernel.org/tglx/notes-about-netiquette

/Jarkko

2020-09-21 13:54:40

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH v38 12/24] x86/sgx: Add SGX_IOC_ENCLAVE_CREATE

On Mon, Sep 21, 2020 at 03:28:23PM +0300, Jarkko Sakkinen wrote:
> Is this appropriate:
>
> /* The extra page in swap space goes to SECS. */
> encl_size = secs->size + PAGE_SIZE;
>
> backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
> VM_NORESERVE);
> if (IS_ERR(backing)) {
> ret = PTR_ERR(backing);
> goto err_out_shrink;
> }
>

Yap, thanks.

> I agree with this but I also think it would make sense to rephrase
> "verifying the correctness of the provided SECS" with something more
> informative.
>
> I would rephrase as:
>
> "... after checking that the provided data for SECS meets the expectations
> of ENCLS[ECREATE] for an unitialized enclave and size of the address
> space does not surpass the platform expectations. This validation is
> executed by sgx_validate_secs()."

s/executed/done/

> Is this sufficient for you, or do you have further suggestions?

Yes, no further suggestions.

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2020-09-21 19:31:20

by Jarkko Sakkinen

[permalink] [raw]
Subject: Re: [PATCH v38 12/24] x86/sgx: Add SGX_IOC_ENCLAVE_CREATE

On Mon, Sep 21, 2020 at 03:51:07PM +0200, Borislav Petkov wrote:
> > "... after checking that the provided data for SECS meets the expectations
> > of ENCLS[ECREATE] for an unitialized enclave and size of the address

There is a typo (should be uninitialized).

> > Is this sufficient for you, or do you have further suggestions?
>
> Yes, no further suggestions.
>
> Thx.


Great, thank you.

> --
> Regards/Gruss,
> Boris.
>
> https://people.kernel.org/tglx/notes-about-netiquette

/Jarkko

2020-10-03 00:27:15

by Haitao Huang

[permalink] [raw]
Subject: Re: [PATCH v38 12/24] x86/sgx: Add SGX_IOC_ENCLAVE_CREATE

On Tue, 15 Sep 2020 06:28:30 -0500, Jarkko Sakkinen
<[email protected]> 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 <[email protected]>
> Tested-by: Jethro Beekman <[email protected]>
> Tested-by: Haitao Huang <[email protected]>
> Tested-by: Chunyang Hui <[email protected]>
> Tested-by: Jordan Hand <[email protected]>
> Tested-by: Nathaniel McCallum <[email protected]>
> Tested-by: Seth Moore <[email protected]>
> Tested-by: Darren Kenny <[email protected]>
> Reviewed-by: Darren Kenny <[email protected]>
> Co-developed-by: Sean Christopherson <[email protected]>
> Signed-off-by: Sean Christopherson <[email protected]>
> Co-developed-by: Suresh Siddha <[email protected]>
> Signed-off-by: Suresh Siddha <[email protected]>
> Signed-off-by: Jarkko Sakkinen <[email protected]>
> ---
> .../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 | 220 ++++++++++++++++++
> 6 files changed, 260 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 2a198838fca9..a89e1c46a25a 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:[email protected]>
> 0xA3 90-9F linux/dtlk.h
> 0xA4 00-1F uapi/linux/tee.h
> Generic TEE subsystem
> +0xA4 00-1F uapi/asm/sgx.h
> <mailto:[email protected]>
> 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..c75b375f3770
> --- /dev/null
> +++ b/arch/x86/include/uapi/asm/sgx.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR
> BSD-3-Clause) */
> +/*
> + * 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 f54da5f19c2b..7bdb49dfcca6 100644
> --- a/arch/x86/kernel/cpu/sgx/driver.c
> +++ b/arch/x86/kernel/cpu/sgx/driver.c
> @@ -114,10 +114,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..352a3c461812
> --- /dev/null
> +++ b/arch/x86/kernel/cpu/sgx/ioctl.c
> @@ -0,0 +1,220 @@
> +// 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;
> +

Attributes should not be enforced against what's available on platform but
checked and enforced against the mask for enforcement in sigstruct. For
example an enclave could opt to sign with AVX bit in xfrm, but still be
loadable on a platform without it if the sigstruct->body.attributes_mask
does not turn that bit on.

Suggest to remove the above check,and do following during EINIt in
sgx_encl_init:

- /* Check that the required attributes have been authorized. */
+ /* Check that the requested attributes have been authorized. */
if (encl->secs_attributes & ~encl->allowed_attributes)
return -EACCES;

+ /* Check that mandatory features are supported. */
+ if (sigstruct->body.attributes & sigstruct->body.attributes_mask &
+ sgx_attributes_reserved_mask)
+ return -EINVAL;
+ if (sigstruct->body.miscselect & sigstruct->body.misc_mask &
+ sgx_misc_reserved_mask)
+ return -EINVAL;
+ if (sigstruct->body.xfrm & sigstruct->body.xfrm_mask &
+ sgx_xfrm_reserved_mask)
+ return -EINVAL;
+
ret = sgx_get_key_hash(sigstruct->modulus, mrsigner);

Haitao

2020-10-03 03:26:27

by Jarkko Sakkinen

[permalink] [raw]
Subject: Re: [PATCH v38 12/24] x86/sgx: Add SGX_IOC_ENCLAVE_CREATE

On Fri, Oct 02, 2020 at 07:23:55PM -0500, Haitao Huang wrote:
> On Tue, 15 Sep 2020 06:28:30 -0500, Jarkko Sakkinen
> <[email protected]> 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 <[email protected]>
> > Tested-by: Jethro Beekman <[email protected]>
> > Tested-by: Haitao Huang <[email protected]>
> > Tested-by: Chunyang Hui <[email protected]>
> > Tested-by: Jordan Hand <[email protected]>
> > Tested-by: Nathaniel McCallum <[email protected]>
> > Tested-by: Seth Moore <[email protected]>
> > Tested-by: Darren Kenny <[email protected]>
> > Reviewed-by: Darren Kenny <[email protected]>
> > Co-developed-by: Sean Christopherson <[email protected]>
> > Signed-off-by: Sean Christopherson <[email protected]>
> > Co-developed-by: Suresh Siddha <[email protected]>
> > Signed-off-by: Suresh Siddha <[email protected]>
> > Signed-off-by: Jarkko Sakkinen <[email protected]>
> > ---
> > .../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 | 220 ++++++++++++++++++
> > 6 files changed, 260 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 2a198838fca9..a89e1c46a25a 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:[email protected]>
> > 0xA3 90-9F linux/dtlk.h
> > 0xA4 00-1F uapi/linux/tee.h
> > Generic TEE subsystem
> > +0xA4 00-1F uapi/asm/sgx.h
> > <mailto:[email protected]>
> > 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..c75b375f3770
> > --- /dev/null
> > +++ b/arch/x86/include/uapi/asm/sgx.h
> > @@ -0,0 +1,25 @@
> > +/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR
> > BSD-3-Clause) */
> > +/*
> > + * 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 f54da5f19c2b..7bdb49dfcca6 100644
> > --- a/arch/x86/kernel/cpu/sgx/driver.c
> > +++ b/arch/x86/kernel/cpu/sgx/driver.c
> > @@ -114,10 +114,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..352a3c461812
> > --- /dev/null
> > +++ b/arch/x86/kernel/cpu/sgx/ioctl.c
> > @@ -0,0 +1,220 @@
> > +// 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;
> > +
>
> Attributes should not be enforced against what's available on platform but
> checked and enforced against the mask for enforcement in sigstruct. For
> example an enclave could opt to sign with AVX bit in xfrm, but still be
> loadable on a platform without it if the sigstruct->body.attributes_mask
> does not turn that bit on.
>
> Suggest to remove the above check,and do following during EINIt in
> sgx_encl_init:
>
> - /* Check that the required attributes have been authorized. */
> + /* Check that the requested attributes have been authorized. */

This is as bad and useless comment as the existing was. In the paragraph
you wrote above you state the things that are useful.

So: I'll take the code change and put the response above here instead
because it is says the right things :-) (maybe with very minor edit)

> if (encl->secs_attributes & ~encl->allowed_attributes)
> return -EACCES;
>
> + /* Check that mandatory features are supported. */
> + if (sigstruct->body.attributes & sigstruct->body.attributes_mask &
> + sgx_attributes_reserved_mask)
> + return -EINVAL;
> + if (sigstruct->body.miscselect & sigstruct->body.misc_mask &
> + sgx_misc_reserved_mask)
> + return -EINVAL;
> + if (sigstruct->body.xfrm & sigstruct->body.xfrm_mask &
> + sgx_xfrm_reserved_mask)
> + return -EINVAL;
> +
> ret = sgx_get_key_hash(sigstruct->modulus, mrsigner);
>
> Haitao

Thanks a lot!

/Jarkko