[intel-sgx-kernel-dev,v7,7/9] intel_sgx: invalidate enclave when the user threads cease to exist
diff mbox

Message ID 20161207130045.22615-8-jarkko.sakkinen@linux.intel.com
State New
Headers show

Commit Message

Jarkko Sakkinen Dec. 7, 2016, 1 p.m. UTC
Page table should not be manipulated after all user processes cease
to exist. This can result page table inconsistency errors:

BUG: non-zero nr_ptes on freeing mm: 1

This commit fixes the issue by invalidating the enclave after all
user processes have been died.

Reported-by: Sean Christopherson <sean.j.christopherson@intel.com>
Suggested-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/platform/x86/Kconfig                |  1 +
 drivers/platform/x86/intel_sgx.h            |  2 ++
 drivers/platform/x86/intel_sgx_ioctl.c      | 23 +++++++++++++++++++++++
 drivers/platform/x86/intel_sgx_page_cache.c |  3 ++-
 drivers/platform/x86/intel_sgx_util.c       |  4 ++++
 5 files changed, 32 insertions(+), 1 deletion(-)

Patch
diff mbox

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index b8db914..f53a759 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1031,6 +1031,7 @@  config INTEL_SGX
 	tristate "Intel(R) SGX Driver"
 	default n
 	depends on X86
+	select MMU_NOTIFIER
 	---help---
 	Intel(R) SGX is a set of CPU instructions that can be used by
 	applications to set aside private regions of code and data.  The code
diff --git a/drivers/platform/x86/intel_sgx.h b/drivers/platform/x86/intel_sgx.h
index 35c03fc..add3565 100644
--- a/drivers/platform/x86/intel_sgx.h
+++ b/drivers/platform/x86/intel_sgx.h
@@ -67,6 +67,7 @@ 
 #include <linux/rwsem.h>
 #include <linux/sched.h>
 #include <linux/workqueue.h>
+#include <linux/mmu_notifier.h>
 
 #define SGX_EINIT_SPIN_COUNT	20
 #define SGX_EINIT_SLEEP_COUNT	50
@@ -152,6 +153,7 @@  struct sgx_encl {
 	struct sgx_encl_page secs_page;
 	struct sgx_tgid_ctx *tgid_ctx;
 	struct list_head encl_list;
+	struct mmu_notifier mmu_notifier;
 };
 
 extern struct workqueue_struct *sgx_add_page_wq;
diff --git a/drivers/platform/x86/intel_sgx_ioctl.c b/drivers/platform/x86/intel_sgx_ioctl.c
index 0c3fd29..ab0a4a3 100644
--- a/drivers/platform/x86/intel_sgx_ioctl.c
+++ b/drivers/platform/x86/intel_sgx_ioctl.c
@@ -471,6 +471,21 @@  static int sgx_init_page(struct sgx_encl *encl,
 	return 0;
 }
 
+static void sgx_mmu_notifier_release(struct mmu_notifier *mn,
+				     struct mm_struct *mm)
+{
+	struct sgx_encl *encl =
+		container_of(mn, struct sgx_encl, mmu_notifier);
+
+	mutex_lock(&encl->lock);
+	encl->flags |= SGX_ENCL_INVALIDATED;
+	mutex_unlock(&encl->lock);
+}
+
+static const struct mmu_notifier_ops sgx_mmu_notifier_ops = {
+	.release	= sgx_mmu_notifier_release,
+};
+
 /**
  * sgx_ioc_enclave_create - handler for SGX_IOC_ENCLAVE_CREATE
  *
@@ -572,6 +587,14 @@  static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd,
 	if (secs->flags & SGX_SECS_A_DEBUG)
 		encl->flags |= SGX_ENCL_DEBUG;
 
+
+	encl->mmu_notifier.ops = &sgx_mmu_notifier_ops;
+	ret = mmu_notifier_register(&encl->mmu_notifier, encl->mm);
+	if (ret) {
+		encl->mmu_notifier.ops = NULL;
+		goto out;
+	}
+
 	down_read(&current->mm->mmap_sem);
 	vma = find_vma(current->mm, secs->base);
 	if (!vma || vma->vm_ops != &sgx_vm_ops ||
diff --git a/drivers/platform/x86/intel_sgx_page_cache.c b/drivers/platform/x86/intel_sgx_page_cache.c
index f2a2ed1..49dd664 100644
--- a/drivers/platform/x86/intel_sgx_page_cache.c
+++ b/drivers/platform/x86/intel_sgx_page_cache.c
@@ -227,12 +227,13 @@  static bool sgx_ewb(struct sgx_encl *encl,
 {
 	int ret = __sgx_ewb(encl, entry, backing);
 
-	/* Only kick out threads with an IPI if needed. */
+	/* fast path */
 	if (ret == SGX_NOT_TRACKED) {
 		smp_call_function(sgx_ipi_cb, NULL, 1);
 		ret = __sgx_ewb(encl, entry, backing);
 	}
 
+	/* slow path */
 	if (ret) {
 		/* Make enclave inaccessible. */
 		sgx_invalidate(encl);
diff --git a/drivers/platform/x86/intel_sgx_util.c b/drivers/platform/x86/intel_sgx_util.c
index 41ccc18..5c96834 100644
--- a/drivers/platform/x86/intel_sgx_util.c
+++ b/drivers/platform/x86/intel_sgx_util.c
@@ -237,6 +237,10 @@  void sgx_encl_release(struct kref *ref)
 
 	mutex_unlock(&sgx_tgid_ctx_mutex);
 
+	if (encl->mmu_notifier.ops)
+		mmu_notifier_unregister_no_release(&encl->mmu_notifier,
+						   encl->mm);
+
 	rb1 = rb_first(&encl->encl_rb);
 	while (rb1) {
 		entry = container_of(rb1, struct sgx_encl_page, node);