diff mbox

[intel-sgx-kernel-dev,v5,7/8] intel_sgx: invalidate enclave when the user threads cease to exist

Message ID 20161202200018.25552-8-jarkko.sakkinen@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jarkko Sakkinen Dec. 2, 2016, 8 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 | 21 +++++++++++++++++++++
 drivers/platform/x86/intel_sgx_util.c  |  4 ++++
 4 files changed, 28 insertions(+)
diff mbox

Patch

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 4430012..fc52a6f 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..3bceebd 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,12 @@  static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd,
 	if (secs->flags & SGX_SECS_A_DEBUG)
 		encl->flags |= SGX_ENCL_DEBUG;
 
+	ret = mmu_notifier_register(&encl->mmu_notifier, encl->mm);
+	if (ret)
+		goto out;
+
+	encl->mmu_notifier.ops = &sgx_mmu_notifier_ops;
+
 	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_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);