summarylogtreecommitdiffstats
path: root/0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch
diff options
context:
space:
mode:
authorJarkko Sakkinen2022-04-14 14:02:33 +0300
committerJarkko Sakkinen2022-04-14 14:02:33 +0300
commitafec2440fe350fd8bff0a63df600a8ad1ed9d507 (patch)
tree3cee74af9df4a0e2242b7a453b6aca6409ae22f6 /0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch
parent9e595612af76514fe6b9fecdc384a33473c7fe08 (diff)
downloadaur-afec2440fe350fd8bff0a63df600a8ad1ed9d507.tar.gz
build: update v4 of sgx2 patches
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@iki.fi>
Diffstat (limited to '0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch')
-rw-r--r--0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch327
1 files changed, 327 insertions, 0 deletions
diff --git a/0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch b/0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch
new file mode 100644
index 000000000000..1efe9f470ce2
--- /dev/null
+++ b/0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch
@@ -0,0 +1,327 @@
+From 8ff9ec59a55ea1ccc5f17f8053e747a963efc327 Mon Sep 17 00:00:00 2001
+From: Reinette Chatre <reinette.chatre@intel.com>
+Date: Wed, 13 Apr 2022 14:10:15 -0700
+Subject: [PATCH 15/31] x86/sgx: Support restricting of enclave page
+ permissions
+
+In the initial (SGX1) version of SGX, pages in an enclave need to be
+created with permissions that support all usages of the pages, from the
+time the enclave is initialized until it is unloaded. For example,
+pages used by a JIT compiler or when code needs to otherwise be
+relocated need to always have RWX permissions.
+
+SGX2 includes a new function ENCLS[EMODPR] that is run from the kernel
+and can be used to restrict the EPCM permissions of regular enclave
+pages within an initialized enclave.
+
+Introduce ioctl() SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS to support
+restricting EPCM permissions. With this ioctl() the user specifies
+a page range and the EPCM permissions to be applied to all pages in
+the provided range. ENCLS[EMODPR] is run to restrict the EPCM
+permissions followed by the ENCLS[ETRACK] flow that will ensure
+no cached linear-to-physical address mappings to the changed
+pages remain.
+
+It is possible for the permission change request to fail on any
+page within the provided range, either with an error encountered
+by the kernel or by the SGX hardware while running
+ENCLS[EMODPR]. To support partial success the ioctl() returns an
+error code based on failures encountered by the kernel as well
+as two result output parameters: one for the number of pages
+that were successfully changed and one for the SGX return code.
+
+The page table entry permissions are not impacted by the EPCM
+permission changes. VMAs and PTEs will continue to allow the
+maximum vetted permissions determined at the time the pages
+are added to the enclave. The SGX error code in a page fault
+will indicate if it was an EPCM permission check that prevented
+an access attempt.
+
+No checking is done to ensure that the permissions are actually
+being restricted. This is because the enclave may have relaxed
+the EPCM permissions from within the enclave without the kernel
+knowing. An attempt to relax permissions using this call will
+be ignored by the hardware.
+
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+---
+ arch/x86/include/uapi/asm/sgx.h | 21 ++++
+ arch/x86/kernel/cpu/sgx/ioctl.c | 216 ++++++++++++++++++++++++++++++++
+ 2 files changed, 237 insertions(+)
+
+diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
+index f4b81587e90b..82648c006470 100644
+--- a/arch/x86/include/uapi/asm/sgx.h
++++ b/arch/x86/include/uapi/asm/sgx.h
+@@ -29,6 +29,8 @@ enum sgx_page_flags {
+ _IOW(SGX_MAGIC, 0x03, struct sgx_enclave_provision)
+ #define SGX_IOC_VEPC_REMOVE_ALL \
+ _IO(SGX_MAGIC, 0x04)
++#define SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS \
++ _IOWR(SGX_MAGIC, 0x05, struct sgx_enclave_restrict_permissions)
+
+ /**
+ * struct sgx_enclave_create - parameter structure for the
+@@ -76,6 +78,25 @@ struct sgx_enclave_provision {
+ __u64 fd;
+ };
+
++/**
++ * struct sgx_enclave_restrict_permissions - parameters for ioctl
++ * %SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS
++ * @offset: starting page offset (page aligned relative to enclave base
++ * address defined in SECS)
++ * @length: length of memory (multiple of the page size)
++ * @permissions:new permission bits for pages in range described by @offset
++ * and @length
++ * @result: (output) SGX result code of ENCLS[EMODPR] function
++ * @count: (output) bytes successfully changed (multiple of page size)
++ */
++struct sgx_enclave_restrict_permissions {
++ __u64 offset;
++ __u64 length;
++ __u64 permissions;
++ __u64 result;
++ __u64 count;
++};
++
+ struct sgx_enclave_run;
+
+ /**
+diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
+index 5d41aa204761..395b4e58a295 100644
+--- a/arch/x86/kernel/cpu/sgx/ioctl.c
++++ b/arch/x86/kernel/cpu/sgx/ioctl.c
+@@ -660,6 +660,218 @@ static long sgx_ioc_enclave_provision(struct sgx_encl *encl, void __user *arg)
+ return sgx_set_attribute(&encl->attributes_mask, params.fd);
+ }
+
++/*
++ * Ensure enclave is ready for SGX2 functions. Readiness is checked
++ * by ensuring the hardware supports SGX2 and the enclave is initialized
++ * and thus able to handle requests to modify pages within it.
++ */
++static int sgx_ioc_sgx2_ready(struct sgx_encl *encl)
++{
++ if (!(cpu_feature_enabled(X86_FEATURE_SGX2)))
++ return -ENODEV;
++
++ if (!test_bit(SGX_ENCL_INITIALIZED, &encl->flags))
++ return -EINVAL;
++
++ return 0;
++}
++
++/*
++ * Some SGX functions require that no cached linear-to-physical address
++ * mappings are present before they can succeed. Collaborate with
++ * hardware via ENCLS[ETRACK] to ensure that all cached
++ * linear-to-physical address mappings belonging to all threads of
++ * the enclave are cleared. See sgx_encl_cpumask() for details.
++ *
++ * Must be called with enclave's mutex held from the time the
++ * SGX function requiring that no cached linear-to-physical mappings
++ * are present is executed until this ETRACK flow is complete.
++ */
++static int sgx_enclave_etrack(struct sgx_encl *encl)
++{
++ void *epc_virt;
++ int ret;
++
++ epc_virt = sgx_get_epc_virt_addr(encl->secs.epc_page);
++ ret = __etrack(epc_virt);
++ if (ret) {
++ /*
++ * ETRACK only fails when there is an OS issue. For
++ * example, two consecutive ETRACK was sent without
++ * completed IPI between.
++ */
++ pr_err_once("ETRACK returned %d (0x%x)", ret, ret);
++ /*
++ * Send IPIs to kick CPUs out of the enclave and
++ * try ETRACK again.
++ */
++ on_each_cpu_mask(sgx_encl_cpumask(encl), sgx_ipi_cb, NULL, 1);
++ ret = __etrack(epc_virt);
++ if (ret) {
++ pr_err_once("ETRACK repeat returned %d (0x%x)",
++ ret, ret);
++ return -EFAULT;
++ }
++ }
++ on_each_cpu_mask(sgx_encl_cpumask(encl), sgx_ipi_cb, NULL, 1);
++
++ return 0;
++}
++
++/**
++ * sgx_enclave_restrict_permissions() - Restrict EPCM permissions
++ * @encl: Enclave to which the pages belong.
++ * @modp: Checked parameters from user on which pages need modifying and
++ * their new permissions.
++ *
++ * Return:
++ * - 0: Success.
++ * - -errno: Otherwise.
++ */
++static long
++sgx_enclave_restrict_permissions(struct sgx_encl *encl,
++ struct sgx_enclave_restrict_permissions *modp)
++{
++ struct sgx_encl_page *entry;
++ struct sgx_secinfo secinfo;
++ unsigned long addr;
++ unsigned long c;
++ void *epc_virt;
++ int ret;
++
++ memset(&secinfo, 0, sizeof(secinfo));
++ secinfo.flags = modp->permissions & SGX_SECINFO_PERMISSION_MASK;
++
++ for (c = 0 ; c < modp->length; c += PAGE_SIZE) {
++ addr = encl->base + modp->offset + c;
++
++ mutex_lock(&encl->lock);
++
++ entry = sgx_encl_load_page(encl, addr);
++ if (IS_ERR(entry)) {
++ ret = PTR_ERR(entry) == -EBUSY ? -EAGAIN : -EFAULT;
++ goto out_unlock;
++ }
++
++ /*
++ * Changing EPCM permissions is only supported on regular
++ * SGX pages. Attempting this change on other pages will
++ * result in #PF.
++ */
++ if (entry->type != SGX_PAGE_TYPE_REG) {
++ ret = -EINVAL;
++ goto out_unlock;
++ }
++
++ /*
++ * Apart from ensuring that read-access remains, do not verify
++ * the permission bits requested. Kernel has no control over
++ * how EPCM permissions can be relaxed from within the enclave.
++ * ENCLS[EMODPR] can only remove existing EPCM permissions,
++ * attempting to set new permissions will be ignored by the
++ * hardware.
++ */
++
++ /* Change EPCM permissions. */
++ epc_virt = sgx_get_epc_virt_addr(entry->epc_page);
++ ret = __emodpr(&secinfo, epc_virt);
++ if (encls_faulted(ret)) {
++ /*
++ * All possible faults should be avoidable:
++ * parameters have been checked, will only change
++ * permissions of a regular page, and no concurrent
++ * SGX1/SGX2 ENCLS instructions since these
++ * are protected with mutex.
++ */
++ pr_err_once("EMODPR encountered exception %d\n",
++ ENCLS_TRAPNR(ret));
++ ret = -EFAULT;
++ goto out_unlock;
++ }
++ if (encls_failed(ret)) {
++ modp->result = ret;
++ ret = -EFAULT;
++ goto out_unlock;
++ }
++
++ ret = sgx_enclave_etrack(encl);
++ if (ret) {
++ ret = -EFAULT;
++ goto out_unlock;
++ }
++
++ mutex_unlock(&encl->lock);
++ }
++
++ ret = 0;
++ goto out;
++
++out_unlock:
++ mutex_unlock(&encl->lock);
++out:
++ modp->count = c;
++
++ return ret;
++}
++
++/**
++ * sgx_ioc_enclave_restrict_permissions() - handler for
++ * %SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS
++ * @encl: an enclave pointer
++ * @arg: userspace pointer to a &struct sgx_enclave_restrict_permissions
++ * instance
++ *
++ * SGX2 distinguishes between relaxing and restricting the enclave page
++ * permissions maintained by the hardware (EPCM permissions) of pages
++ * belonging to an initialized enclave (after SGX_IOC_ENCLAVE_INIT).
++ *
++ * EPCM permissions cannot be restricted from within the enclave, the enclave
++ * requires the kernel to run the privileged level 0 instructions ENCLS[EMODPR]
++ * and ENCLS[ETRACK]. An attempt to relax EPCM permissions with this call
++ * will be ignored by the hardware.
++ *
++ * Return:
++ * - 0: Success
++ * - -errno: Otherwise
++ */
++static long sgx_ioc_enclave_restrict_permissions(struct sgx_encl *encl,
++ void __user *arg)
++{
++ struct sgx_enclave_restrict_permissions params;
++ long ret;
++
++ ret = sgx_ioc_sgx2_ready(encl);
++ if (ret)
++ return ret;
++
++ if (copy_from_user(&params, arg, sizeof(params)))
++ return -EFAULT;
++
++ if (sgx_validate_offset_length(encl, params.offset, params.length))
++ return -EINVAL;
++
++ if (params.permissions & ~SGX_SECINFO_PERMISSION_MASK)
++ return -EINVAL;
++
++ /*
++ * Read access is required for the enclave to be able to use the page.
++ * SGX instructions like ENCLU[EMODPE] and ENCLU[EACCEPT] require
++ * read access.
++ */
++ if (!(params.permissions & SGX_SECINFO_R))
++ return -EINVAL;
++
++ if (params.result || params.count)
++ return -EINVAL;
++
++ ret = sgx_enclave_restrict_permissions(encl, &params);
++
++ if (copy_to_user(arg, &params, sizeof(params)))
++ return -EFAULT;
++
++ return ret;
++}
++
+ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+ {
+ struct sgx_encl *encl = filep->private_data;
+@@ -681,6 +893,10 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+ case SGX_IOC_ENCLAVE_PROVISION:
+ ret = sgx_ioc_enclave_provision(encl, (void __user *)arg);
+ break;
++ case SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS:
++ ret = sgx_ioc_enclave_restrict_permissions(encl,
++ (void __user *)arg);
++ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+--
+2.35.2
+