summarylogtreecommitdiffstats
path: root/0023-x86-sgx-Support-complete-page-removal.patch
diff options
context:
space:
mode:
Diffstat (limited to '0023-x86-sgx-Support-complete-page-removal.patch')
-rw-r--r--0023-x86-sgx-Support-complete-page-removal.patch244
1 files changed, 244 insertions, 0 deletions
diff --git a/0023-x86-sgx-Support-complete-page-removal.patch b/0023-x86-sgx-Support-complete-page-removal.patch
new file mode 100644
index 000000000000..57ab38265d99
--- /dev/null
+++ b/0023-x86-sgx-Support-complete-page-removal.patch
@@ -0,0 +1,244 @@
+From e8450696982167257dffebfbd8983e8d7b9bc235 Mon Sep 17 00:00:00 2001
+From: Reinette Chatre <reinette.chatre@intel.com>
+Date: Mon, 7 Feb 2022 16:45:45 -0800
+Subject: [PATCH 23/34] x86/sgx: Support complete page removal
+
+The SGX2 page removal flow was introduced in previous patch and is
+as follows:
+1) Change the type of the pages to be removed to SGX_PAGE_TYPE_TRIM
+ using the ioctl() SGX_IOC_ENCLAVE_MODIFY_TYPE introduced in
+ previous patch.
+2) Approve the page removal by running ENCLU[EACCEPT] from within
+ the enclave.
+3) Initiate actual page removal using the ioctl()
+ SGX_IOC_ENCLAVE_REMOVE_PAGES introduced here.
+
+Support the final step of the SGX2 page removal flow with ioctl()
+SGX_IOC_ENCLAVE_REMOVE_PAGES. With this ioctl() the user specifies
+a page range that should be removed. All pages in the provided
+range should have the SGX_PAGE_TYPE_TRIM page type and the request
+will fail with EPERM (Operation not permitted) if a page that does
+not have the correct type is encountered. Page removal can fail
+on any page within the provided range. Support partial success by
+returning the number of pages that were successfully removed.
+
+Since actual page removal will succeed even if ENCLU[EACCEPT] was not
+run from within the enclave the ENCLU[EMODPR] instruction with RWX
+permissions is used as a no-op mechanism to ensure ENCLU[EACCEPT] was
+successfully run from within the enclave before the enclave page is
+removed.
+
+If the user omits running SGX_IOC_ENCLAVE_REMOVE_PAGES the pages will
+still be removed when the enclave is unloaded.
+
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+---
+ arch/x86/include/uapi/asm/sgx.h | 21 +++++
+ arch/x86/kernel/cpu/sgx/ioctl.c | 145 ++++++++++++++++++++++++++++++++
+ 2 files changed, 166 insertions(+)
+
+diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
+index 1df91517b612..db969a2a1874 100644
+--- a/arch/x86/include/uapi/asm/sgx.h
++++ b/arch/x86/include/uapi/asm/sgx.h
+@@ -35,6 +35,8 @@ enum sgx_page_flags {
+ _IOWR(SGX_MAGIC, 0x06, struct sgx_enclave_restrict_perm)
+ #define SGX_IOC_ENCLAVE_MODIFY_TYPE \
+ _IOWR(SGX_MAGIC, 0x07, struct sgx_enclave_modt)
++#define SGX_IOC_ENCLAVE_REMOVE_PAGES \
++ _IOWR(SGX_MAGIC, 0x08, struct sgx_enclave_remove_pages)
+
+ /**
+ * struct sgx_enclave_create - parameter structure for the
+@@ -136,6 +138,25 @@ struct sgx_enclave_modt {
+ __u64 count;
+ };
+
++/**
++ * struct sgx_enclave_remove_pages - %SGX_IOC_ENCLAVE_REMOVE_PAGES parameters
++ * @offset: starting page offset (page aligned relative to enclave base
++ * address defined in SECS)
++ * @length: length of memory (multiple of the page size)
++ * @count: (output) bytes successfully changed (multiple of page size)
++ *
++ * Regular (PT_REG) or TCS (PT_TCS) can be removed from an initialized
++ * enclave if the system supports SGX2. First, the %SGX_IOC_ENCLAVE_MODIFY_TYPE
++ * ioctl() should be used to change the page type to PT_TRIM. After that
++ * succeeds ENCLU[EACCEPT] should be run from within the enclave and then
++ * %SGX_IOC_ENCLAVE_REMOVE_PAGES can be used to complete the page removal.
++ */
++struct sgx_enclave_remove_pages {
++ __u64 offset;
++ __u64 length;
++ __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 3f59920184c4..0ffb07095a80 100644
+--- a/arch/x86/kernel/cpu/sgx/ioctl.c
++++ b/arch/x86/kernel/cpu/sgx/ioctl.c
+@@ -1329,6 +1329,148 @@ static long sgx_ioc_enclave_modt(struct sgx_encl *encl, void __user *arg)
+ return ret;
+ }
+
++/**
++ * sgx_encl_remove_pages() - Remove trimmed pages from SGX enclave
++ * @encl: Enclave to which the pages belong
++ * @params: Checked parameters from user on which pages need to be removed
++ *
++ * Return:
++ * - 0: Success.
++ * - -errno: Otherwise.
++ */
++static long sgx_encl_remove_pages(struct sgx_encl *encl,
++ struct sgx_enclave_remove_pages *params)
++{
++ 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 = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_X;
++
++ for (c = 0 ; c < params->length; c += PAGE_SIZE) {
++ addr = encl->base + params->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;
++ }
++
++ if (entry->type != SGX_PAGE_TYPE_TRIM) {
++ ret = -EPERM;
++ goto out_unlock;
++ }
++
++ /*
++ * ENCLS[EMODPR] is a no-op instruction used to inform if
++ * ENCLU[EACCEPT] was run from within the enclave. If
++ * ENCLS[EMODPR] is run with RWX on a trimmed page that is
++ * not yet accepted then it will return
++ * %SGX_PAGE_NOT_MODIFIABLE, after the trimmed page is
++ * accepted the instruction will encounter a page fault.
++ */
++ epc_virt = sgx_get_epc_virt_addr(entry->epc_page);
++ ret = __emodpr(&secinfo, epc_virt);
++ if (!encls_faulted(ret) || ENCLS_TRAPNR(ret) != X86_TRAP_PF) {
++ ret = -EPERM;
++ goto out_unlock;
++ }
++
++ if (sgx_unmark_page_reclaimable(entry->epc_page)) {
++ ret = -EBUSY;
++ goto out_unlock;
++ }
++
++ /*
++ * Do not keep encl->lock because of dependency on
++ * mmap_lock acquired in sgx_zap_enclave_ptes().
++ */
++ mutex_unlock(&encl->lock);
++
++ sgx_zap_enclave_ptes(encl, addr);
++
++ mutex_lock(&encl->lock);
++
++ sgx_encl_free_epc_page(entry->epc_page);
++ encl->secs_child_cnt--;
++ entry->epc_page = NULL;
++ xa_erase(&encl->page_array, PFN_DOWN(entry->desc));
++ sgx_encl_shrink(encl, NULL);
++ kfree(entry);
++
++ mutex_unlock(&encl->lock);
++ }
++
++ ret = 0;
++ goto out;
++
++out_unlock:
++ mutex_unlock(&encl->lock);
++out:
++ params->count = c;
++
++ return ret;
++}
++
++/**
++ * sgx_ioc_enclave_remove_pages() - handler for %SGX_IOC_ENCLAVE_REMOVE_PAGES
++ * @encl: an enclave pointer
++ * @arg: userspace pointer to &struct sgx_enclave_remove_pages instance
++ *
++ * Final step of the flow removing pages from an initialized enclave. The
++ * complete flow is:
++ *
++ * 1) User changes the type of the pages to be removed to %SGX_PAGE_TYPE_TRIM
++ * using the %SGX_IOC_ENCLAVE_MODIFY_TYPE ioctl().
++ * 2) User approves the page removal by running ENCLU[EACCEPT] from within
++ * the enclave.
++ * 3) User initiates actual page removal using the
++ * %SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl() that is handled here.
++ *
++ * First remove any page table entries pointing to the page and then proceed
++ * with the actual removal of the enclave page and data in support of it.
++ *
++ * VA pages are not affected by this removal. It is thus possible that the
++ * enclave may end up with more VA pages than needed to support all its
++ * pages.
++ *
++ * Return:
++ * - 0: Success
++ * - -errno: Otherwise
++ */
++static long sgx_ioc_enclave_remove_pages(struct sgx_encl *encl,
++ void __user *arg)
++{
++ struct sgx_enclave_remove_pages 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.count)
++ return -EINVAL;
++
++ ret = sgx_encl_remove_pages(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;
+@@ -1359,6 +1501,9 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+ case SGX_IOC_ENCLAVE_MODIFY_TYPE:
+ ret = sgx_ioc_enclave_modt(encl, (void __user *)arg);
+ break;
++ case SGX_IOC_ENCLAVE_REMOVE_PAGES:
++ ret = sgx_ioc_enclave_remove_pages(encl, (void __user *)arg);
++ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+--
+2.35.1
+