@@ -130,12 +130,12 @@ enum sgx_encl_flags {
SGX_ENCL_DEBUG = BIT(1),
SGX_ENCL_SECS_EVICTED = BIT(2),
SGX_ENCL_SUSPEND = BIT(3),
+ SGX_ENCL_DEAD = BIT(4),
};
struct sgx_encl {
unsigned int flags;
unsigned int secs_child_cnt;
- unsigned int vma_cnt;
struct mutex lock;
struct task_struct *owner;
struct mm_struct *mm;
@@ -255,7 +255,10 @@ static bool sgx_process_add_page_req(struct sgx_add_page_req *req)
mutex_lock(&encl->lock);
- if (!encl->vma_cnt || sgx_find_encl(encl->mm, encl_page->addr, &vma))
+ if (encl->flags & SGX_ENCL_DEAD)
+ goto out;
+
+ if (sgx_find_encl(encl->mm, encl_page->addr, &vma))
goto out;
backing = sgx_get_backing(encl, encl_page); @@ -317,7 +320,7 @@ static void sgx_add_page_worker(struct work_struct *work)
do {
schedule();
- if (encl->flags & SGX_ENCL_SUSPEND)
+ if (encl->flags & SGX_ENCL_DEAD)
skip_rest = true;
mutex_lock(&encl->lock);
@@ -578,7 +581,6 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd,
up_read(¤t->mm->mmap_sem);
goto out;
}
- encl->vma_cnt++;
vma->vm_private_data = encl;
up_read(¤t->mm->mmap_sem);
@@ -682,7 +684,7 @@ static int __encl_add_page(struct sgx_encl *encl,
mutex_lock(&encl->lock);
- if (encl->flags & SGX_ENCL_INITIALIZED) {
+ if (encl->flags & (SGX_ENCL_INITIALIZED | SGX_ENCL_DEAD)) {
ret = -EINVAL;
goto out;
}
@@ -135,21 +135,18 @@ void sgx_zap_tcs_ptes(struct sgx_encl *encl, struct vm_area_struct *vma)
bool sgx_pin_mm(struct sgx_encl *encl)
{
- if (encl->flags & SGX_ENCL_SUSPEND)
- return false;
-
mutex_lock(&encl->lock);
- if (encl->vma_cnt) {
- atomic_inc(&encl->mm->mm_count);
- } else {
+ if (encl->flags & SGX_ENCL_DEAD) {
mutex_unlock(&encl->lock);
return false;
}
+
+ atomic_inc(&encl->mm->mm_count);
mutex_unlock(&encl->lock);
down_read(&encl->mm->mmap_sem);
- if (!encl->vma_cnt) {
+ if (encl->flags & SGX_ENCL_DEAD) {
sgx_unpin_mm(encl);
return false;
}
@@ -177,7 +174,7 @@ void sgx_invalidate(struct sgx_encl *encl)
break;
}
- encl->vma_cnt = 0;
+ encl->flags |= SGX_ENCL_DEAD;
}
int sgx_find_encl(struct mm_struct *mm, unsigned long addr, diff --git a/drivers/platform/x86/intel_sgx_vma.c b/drivers/platform/x86/intel_sgx_vma.c
@@ -70,48 +70,41 @@
static void sgx_vma_open(struct vm_area_struct *vma) {
- struct sgx_encl *encl;
-
- /* Was vm_private_data nullified as a result of the previous fork? */
- encl = vma->vm_private_data;
- if (!encl)
- goto out_fork;
+ struct sgx_encl *encl = vma->vm_private_data;
- /* Was the process forked? mm_struct changes when the process is
- * forked.
+ /* When forking for the second time vm_private_data is already set to
+ * NULL.
*/
+ if (!encl) {
+ zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start);
+ return;
+ }
+
+ /* Invalidate enclave when the process has been forked. */
mutex_lock(&encl->lock);
if (encl->mm != vma->vm_mm) {
- mutex_unlock(&encl->lock);
- goto out_fork;
+ sgx_invalidate(encl);
+ vma->vm_private_data = NULL;
}
- encl->vma_cnt++;
mutex_unlock(&encl->lock);
- kref_get(&encl->refcount);
- return;
-out_fork:
- zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start);
- vma->vm_private_data = NULL;
+ if (vma->vm_private_data)
+ kref_get(&encl->refcount);
}
static void sgx_vma_close(struct vm_area_struct *vma) {
struct sgx_encl *encl = vma->vm_private_data;
- /* If process was forked, VMA is still there but
- * vm_private_data is set to NULL.
+ /* When forking for the second time vm_private_data is already set to
+ * NULL.
*/
if (!encl)
return;
mutex_lock(&encl->lock);
- encl->vma_cnt--;
- vma->vm_private_data = NULL;
-
- sgx_zap_tcs_ptes(encl, vma);
zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start);
-
+ encl->flags |= SGX_ENCL_DEAD;
mutex_unlock(&encl->lock);
kref_put(&encl->refcount, sgx_encl_release); @@ -187,7 +180,7 @@ static struct sgx_encl_page *sgx_vma_do_fault(struct vm_area_struct *vma,
mutex_lock(&encl->lock);