[intel-sgx-kernel-dev,4/4] intel_sgx: Kill enclave if vm_insert_pfn fails
diff mbox

Message ID 1484081758-20302-5-git-send-email-sean.j.christopherson@intel.com
State New
Headers show

Commit Message

Sean Christopherson Jan. 10, 2017, 8:55 p.m. UTC
Log a warning and kill the enclave if vm_insert_pfn fails while handling
a page fault.  Removing the page from the EPC via EREMOVE can result in
kernel panics as EREMOVE will fail if there are active threads in the
enclave.  Retrying vm_insert_pfn at a later date won't succeed as calls
to vm_insert_pfn are protected by encl->lock, i.e. there are no valid
scenarios where EBUSY can be returned, failure indicates a driver bug.

Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
 drivers/platform/x86/intel_sgx_vma.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

Patch
diff mbox

diff --git a/drivers/platform/x86/intel_sgx_vma.c b/drivers/platform/x86/intel_sgx_vma.c
index e670405..67a51ee 100644
--- a/drivers/platform/x86/intel_sgx_vma.c
+++ b/drivers/platform/x86/intel_sgx_vma.c
@@ -160,7 +160,6 @@  static struct sgx_encl_page *sgx_vma_do_fault(struct vm_area_struct *vma,
 	struct sgx_epc_page *epc_page = NULL;
 	struct sgx_epc_page *secs_epc_page = NULL;
 	struct page *backing;
-	unsigned int free_flags = SGX_FREE_SKIP_EREMOVE;
 	int rc;
 
 	/* If process was forked, VMA is still there but vm_private_data is set
@@ -253,8 +252,11 @@  static struct sgx_encl_page *sgx_vma_do_fault(struct vm_area_struct *vma,
 	rc = vm_insert_pfn(vma, entry->addr, PFN_DOWN(epc_page->pa));
 	sgx_put_backing(backing, 0);
 
+	/* failure to insert a pfn after ELDU is fatal to the enclave */
 	if (rc) {
-		free_flags = 0;
+		sgx_warn(encl, "vm_insert_pfn in fault returned %d\n", rc);
+		zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start);
+		encl->flags |= SGX_ENCL_DEAD;
 		entry = ERR_PTR(rc);
 		goto out;
 	}
@@ -274,7 +276,7 @@  static struct sgx_encl_page *sgx_vma_do_fault(struct vm_area_struct *vma,
 out:
 	mutex_unlock(&encl->lock);
 	if (epc_page)
-		sgx_free_page(epc_page, encl, free_flags);
+		sgx_free_page(epc_page, encl, SGX_FREE_SKIP_EREMOVE);
 	if (secs_epc_page)
 		sgx_free_page(secs_epc_page, encl, SGX_FREE_SKIP_EREMOVE);
 	return entry;