[RFC PATCH v4 03/26] x86/sgx: Wipe out EREMOVE from sgx_free_epc_page()

Kai Huang
2021-02-08T10:59:04Z

From: Jarkko Sakkinen <jarkko@kernel.org>

Encapsulate the snippet in sgx_free_epc_page() concerning EREMOVE to
sgx_reset_epc_page(), which is a static helper function for
sgx_encl_release(). It's the only function existing, which deals with
initialized pages.

Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Kai Huang <kai.huang@intel.com>
---
v3->v4:

- Moved WARN() on SGX_EPC_PAGE_RECLAIMER_TRACKED flag to sgx_reset_epc_page(),
since the patch to remove the WARN() in v3 was removed. Dave and Sean were
not convinced, and Sean "tripped more than once in the past during one of
the many rebases of the virtual EPC and EPC cgroup branches".
- Added a comment in sgx_reset_epc_page() to explain sgx_free_epc_page() now
won't do EREMOVE and is expecting EPC page already in clean slate, per Dave.

---
arch/x86/kernel/cpu/sgx/encl.c | 20 ++++++++++++++++++++
arch/x86/kernel/cpu/sgx/main.c | 12 ++++--------
2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c
index 20a2dd5ba2b4..a758c7870f06 100644
--- a/arch/x86/kernel/cpu/sgx/encl.c
+++ b/arch/x86/kernel/cpu/sgx/encl.c
@@ -381,6 +381,23 @@ const struct vm_operations_struct sgx_vm_ops = {
.access = sgx_vma_access,
};

+
+/*
+ * Place the page in uninitialized state. Called by in sgx_encl_release()
+ * before sgx_free_epc_page(), which requires EPC page is already in clean
+ * slate.
+ */
+static void sgx_reset_epc_page(struct sgx_epc_page *epc_page)
+{
+ int ret;
+
+ WARN_ON_ONCE(epc_page->flags & SGX_EPC_PAGE_RECLAIMER_TRACKED);
+
+ ret = __eremove(sgx_get_epc_virt_addr(epc_page));
+ if (WARN_ONCE(ret, "EREMOVE returned %d (0x%x)", ret, ret))
+ return;
+}
+
/**
* sgx_encl_release - Destroy an enclave instance
* @kref: address of a kref inside &sgx_encl
@@ -404,6 +421,7 @@ void sgx_encl_release(struct kref *ref)
if (sgx_unmark_page_reclaimable(entry->epc_page))
continue;

+ sgx_reset_epc_page(entry->epc_page);
sgx_free_epc_page(entry->epc_page);
encl->secs_child_cnt--;
entry->epc_page = NULL;
@@ -415,6 +433,7 @@ void sgx_encl_release(struct kref *ref)
xa_destroy(&encl->page_array);

if (!encl->secs_child_cnt && encl->secs.epc_page) {
+ sgx_reset_epc_page(encl->secs.epc_page);
sgx_free_epc_page(encl->secs.epc_page);
encl->secs.epc_page = NULL;
}
@@ -423,6 +442,7 @@ void sgx_encl_release(struct kref *ref)
va_page = list_first_entry(&encl->va_pages, struct sgx_va_page,
list);
list_del(&va_page->list);
+ sgx_reset_epc_page(va_page->epc_page);
sgx_free_epc_page(va_page->epc_page);
kfree(va_page);
}
diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c
index 8df81a3ed945..21c2ffa13870 100644
--- a/arch/x86/kernel/cpu/sgx/main.c
+++ b/arch/x86/kernel/cpu/sgx/main.c
@@ -598,18 +598,14 @@ struct sgx_epc_page *sgx_alloc_epc_page(void *owner, bool reclaim)
* sgx_free_epc_page() - Free an EPC page
* @page: an EPC page
*
- * Call EREMOVE for an EPC page and insert it back to the list of free pages.
+ * Put the EPC page back to the list of free pages. It's the callers
+ * responsibility to make sure that the page is in uninitialized state In other
+ * words, do EREMOVE, EWB or whatever operation is necessary before calling
+ * this function.
*/
void sgx_free_epc_page(struct sgx_epc_page *page)
{
struct sgx_epc_section *section = &sgx_epc_sections[page->section];
- int ret;
-
- WARN_ON_ONCE(page->flags & SGX_EPC_PAGE_RECLAIMER_TRACKED);
-
- ret = __eremove(sgx_get_epc_virt_addr(page));
- if (WARN_ONCE(ret, "EREMOVE returned %d (0x%x)", ret, ret))
- return;

spin_lock(&section->lock);
list_add_tail(&page->list, &section->page_list);
--
2.29.2