mirror of
https://github.com/intel/linux-sgx-driver
synced 2026-06-08 14:49:53 +00:00
7490f2e8c9
Signed-off-by: Angie Chinchilla <angie.v.chinchilla@intel.com>
1077 lines
30 KiB
Diff
1077 lines
30 KiB
Diff
From fc0cb151466bc6197506ab7e6dc5e3f516ca8d7a Mon Sep 17 00:00:00 2001
|
|
From: Angie Chinchilla <angie.v.chinchilla@intel.com>
|
|
Date: Mon, 27 Nov 2017 00:15:00 -0500
|
|
Subject: [PATCH] SGX 2.0 Implementation
|
|
|
|
Rebased 2.0 patch applies to linux-sgx-driver:master
|
|
commit-id 03435d33de0bcca6c5777f23ac161249b9158f1e
|
|
|
|
Authors:
|
|
Serge Ayoun <serge.ayoun@intel.com>
|
|
Angie Chinchilla <angie.v.chinchilla@intel.com>
|
|
Shay Katz-zamir <shay.katz-zamir@intel.com>
|
|
Cedric Xing <cedric.xing@intel.com>
|
|
|
|
Signed-off-by: Angie Chinchilla <angie.v.chinchilla@intel.com>
|
|
---
|
|
Makefile | 3 +-
|
|
sgx.h | 29 +++-
|
|
sgx_arch.h | 2 +
|
|
sgx_encl.c | 30 ++--
|
|
sgx_encl2.c | 446 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
sgx_ioctl.c | 134 ++++++++++++++++-
|
|
sgx_main.c | 5 +-
|
|
sgx_page_cache.c | 2 +-
|
|
sgx_user.h | 25 ++++
|
|
sgx_util.c | 40 +++--
|
|
sgx_vma.c | 10 +-
|
|
11 files changed, 698 insertions(+), 28 deletions(-)
|
|
create mode 100644 sgx_encl2.c
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index 4b5edaf..c88f38c 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -5,7 +5,8 @@ ifneq ($(KERNELRELEASE),)
|
|
sgx_ioctl.o \
|
|
sgx_vma.o \
|
|
sgx_util.o\
|
|
- sgx_encl.o
|
|
+ sgx_encl.o \
|
|
+ sgx_encl2.o
|
|
obj-m += isgx.o
|
|
else
|
|
KDIR := /lib/modules/$(shell uname -r)/build
|
|
diff --git a/sgx.h b/sgx.h
|
|
index bfc24c0..46dfc0f 100644
|
|
--- a/sgx.h
|
|
+++ b/sgx.h
|
|
@@ -69,12 +69,14 @@
|
|
#include <linux/workqueue.h>
|
|
#include <linux/mmu_notifier.h>
|
|
#include <linux/radix-tree.h>
|
|
+#include <linux/mm.h>
|
|
#include "sgx_arch.h"
|
|
#include "sgx_user.h"
|
|
|
|
#define SGX_EINIT_SPIN_COUNT 20
|
|
#define SGX_EINIT_SLEEP_COUNT 50
|
|
#define SGX_EINIT_SLEEP_TIME 20
|
|
+#define SGX_EDMM_SPIN_COUNT 20
|
|
|
|
#define SGX_VA_SLOT_COUNT 512
|
|
|
|
@@ -110,9 +112,21 @@ static inline void sgx_free_va_slot(struct sgx_va_page *page,
|
|
clear_bit(offset >> 3, page->slots);
|
|
}
|
|
|
|
+static inline bool sgx_va_slots_empty(struct sgx_va_page *page)
|
|
+{
|
|
+ int slot = find_first_bit(page->slots, SGX_VA_SLOT_COUNT);
|
|
+
|
|
+ if (slot == SGX_VA_SLOT_COUNT)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
enum sgx_encl_page_flags {
|
|
SGX_ENCL_PAGE_TCS = BIT(0),
|
|
SGX_ENCL_PAGE_RESERVED = BIT(1),
|
|
+ SGX_ENCL_PAGE_TRIM = BIT(2),
|
|
+ SGX_ENCL_PAGE_ADDED = BIT(3),
|
|
};
|
|
|
|
struct sgx_encl_page {
|
|
@@ -160,6 +174,7 @@ struct sgx_encl {
|
|
struct sgx_tgid_ctx *tgid_ctx;
|
|
struct list_head encl_list;
|
|
struct mmu_notifier mmu_notifier;
|
|
+ unsigned int shadow_epoch;
|
|
};
|
|
|
|
struct sgx_epc_bank {
|
|
@@ -178,6 +193,7 @@ extern u64 sgx_encl_size_max_64;
|
|
extern u64 sgx_xfrm_mask;
|
|
extern u32 sgx_misc_reserved;
|
|
extern u32 sgx_xsave_size_tbl[64];
|
|
+extern bool sgx_has_sgx2;
|
|
|
|
extern const struct vm_operations_struct sgx_vm_ops;
|
|
|
|
@@ -205,6 +221,8 @@ int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr, void *data,
|
|
struct sgx_secinfo *secinfo, unsigned int mrmask);
|
|
int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct,
|
|
struct sgx_einittoken *einittoken);
|
|
+struct sgx_encl_page *sgx_encl_augment(struct vm_area_struct *vma,
|
|
+ unsigned long addr, bool write);
|
|
void sgx_encl_release(struct kref *ref);
|
|
|
|
long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
|
@@ -234,7 +252,8 @@ enum sgx_fault_flags {
|
|
|
|
struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma,
|
|
unsigned long addr,
|
|
- unsigned int flags);
|
|
+ unsigned int flags,
|
|
+ struct vm_fault *vmf);
|
|
|
|
|
|
extern struct mutex sgx_tgid_ctx_mutex;
|
|
@@ -249,6 +268,12 @@ void sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl);
|
|
void *sgx_get_page(struct sgx_epc_page *entry);
|
|
void sgx_put_page(void *epc_page_vaddr);
|
|
void sgx_eblock(struct sgx_encl *encl, struct sgx_epc_page *epc_page);
|
|
-void sgx_etrack(struct sgx_encl *encl);
|
|
+void sgx_etrack(struct sgx_encl *encl, unsigned int epoch);
|
|
+void sgx_ipi_cb(void *info);
|
|
+int sgx_eldu(struct sgx_encl *encl, struct sgx_encl_page *encl_page,
|
|
+ struct sgx_epc_page *epc_page, bool is_secs);
|
|
+long modify_range(struct sgx_range *rg, unsigned long flags);
|
|
+int remove_page(struct sgx_encl *encl, unsigned long address, bool trim);
|
|
+int sgx_get_encl(unsigned long addr, struct sgx_encl **encl);
|
|
|
|
#endif /* __ARCH_X86_INTEL_SGX_H__ */
|
|
diff --git a/sgx_arch.h b/sgx_arch.h
|
|
index dcb620e..a609fd6 100644
|
|
--- a/sgx_arch.h
|
|
+++ b/sgx_arch.h
|
|
@@ -139,6 +139,7 @@ enum sgx_page_type {
|
|
SGX_PAGE_TYPE_TCS = 0x01,
|
|
SGX_PAGE_TYPE_REG = 0x02,
|
|
SGX_PAGE_TYPE_VA = 0x03,
|
|
+ SGX_PAGE_TYPE_TRIM = 0x04,
|
|
};
|
|
|
|
enum sgx_secinfo_flags {
|
|
@@ -148,6 +149,7 @@ enum sgx_secinfo_flags {
|
|
SGX_SECINFO_SECS = (SGX_PAGE_TYPE_SECS << 8),
|
|
SGX_SECINFO_TCS = (SGX_PAGE_TYPE_TCS << 8),
|
|
SGX_SECINFO_REG = (SGX_PAGE_TYPE_REG << 8),
|
|
+ SGX_SECINFO_TRIM = (SGX_PAGE_TYPE_TRIM << 8),
|
|
};
|
|
|
|
struct sgx_secinfo {
|
|
diff --git a/sgx_encl.c b/sgx_encl.c
|
|
index 2669509..ccab446 100644
|
|
--- a/sgx_encl.c
|
|
+++ b/sgx_encl.c
|
|
@@ -279,6 +279,7 @@ static bool sgx_process_add_page_req(struct sgx_add_page_req *req,
|
|
encl_page->epc_page = epc_page;
|
|
sgx_test_and_clear_young(encl_page, encl);
|
|
list_add_tail(&epc_page->list, &encl->load_list);
|
|
+ encl_page->flags |= SGX_ENCL_PAGE_ADDED;
|
|
|
|
return true;
|
|
}
|
|
@@ -431,8 +432,9 @@ static const struct mmu_notifier_ops sgx_mmu_notifier_ops = {
|
|
.release = sgx_mmu_notifier_release,
|
|
};
|
|
|
|
-static int sgx_init_page(struct sgx_encl *encl, struct sgx_encl_page *entry,
|
|
- unsigned long addr, unsigned int alloc_flags)
|
|
+int sgx_init_page(struct sgx_encl *encl, struct sgx_encl_page *entry,
|
|
+ unsigned long addr, unsigned int alloc_flags,
|
|
+ struct sgx_epc_page **va_src, bool already_locked)
|
|
{
|
|
struct sgx_va_page *va_page;
|
|
struct sgx_epc_page *epc_page = NULL;
|
|
@@ -451,10 +453,15 @@ static int sgx_init_page(struct sgx_encl *encl, struct sgx_encl_page *entry,
|
|
if (!va_page)
|
|
return -ENOMEM;
|
|
|
|
- epc_page = sgx_alloc_page(alloc_flags);
|
|
- if (IS_ERR(epc_page)) {
|
|
- kfree(va_page);
|
|
- return PTR_ERR(epc_page);
|
|
+ if (va_src) {
|
|
+ epc_page = *va_src;
|
|
+ *va_src = NULL;
|
|
+ } else {
|
|
+ epc_page = sgx_alloc_page(alloc_flags);
|
|
+ if (IS_ERR(epc_page)) {
|
|
+ kfree(va_page);
|
|
+ return PTR_ERR(epc_page);
|
|
+ }
|
|
}
|
|
|
|
vaddr = sgx_get_page(epc_page);
|
|
@@ -481,9 +488,11 @@ static int sgx_init_page(struct sgx_encl *encl, struct sgx_encl_page *entry,
|
|
va_page->epc_page = epc_page;
|
|
va_offset = sgx_alloc_va_slot(va_page);
|
|
|
|
- mutex_lock(&encl->lock);
|
|
+ if (!already_locked)
|
|
+ mutex_lock(&encl->lock);
|
|
list_add(&va_page->list, &encl->va_pages);
|
|
- mutex_unlock(&encl->lock);
|
|
+ if (!already_locked)
|
|
+ mutex_unlock(&encl->lock);
|
|
}
|
|
|
|
entry->va_page = va_page;
|
|
@@ -596,7 +605,8 @@ int sgx_encl_create(struct sgx_secs *secs)
|
|
if (ret)
|
|
goto out;
|
|
|
|
- ret = sgx_init_page(encl, &encl->secs, encl->base + encl->size, 0);
|
|
+ ret = sgx_init_page(encl, &encl->secs, encl->base + encl->size, 0,
|
|
+ NULL, false);
|
|
if (ret)
|
|
goto out;
|
|
|
|
@@ -766,7 +776,7 @@ static int __sgx_encl_add_page(struct sgx_encl *encl,
|
|
return ret;
|
|
}
|
|
|
|
- ret = sgx_init_page(encl, encl_page, addr, 0);
|
|
+ ret = sgx_init_page(encl, encl_page, addr, 0, NULL, false);
|
|
if (ret)
|
|
return ret;
|
|
|
|
diff --git a/sgx_encl2.c b/sgx_encl2.c
|
|
new file mode 100644
|
|
index 0000000..6a5556d
|
|
--- /dev/null
|
|
+++ b/sgx_encl2.c
|
|
@@ -0,0 +1,446 @@
|
|
+/*
|
|
+ * This file is provided under a dual BSD/GPLv2 license. When using or
|
|
+ * redistributing this file, you may do so under either license.
|
|
+ *
|
|
+ * GPL LICENSE SUMMARY
|
|
+ *
|
|
+ * Copyright(c) 2016-2017 Intel Corporation.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of version 2 of the GNU General Public License as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful, but
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * General Public License for more details.
|
|
+ *
|
|
+ * Contact Information:
|
|
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
|
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
|
|
+ *
|
|
+ * BSD LICENSE
|
|
+ *
|
|
+ * Copyright(c) 2016-2017 Intel Corporation.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ *
|
|
+ * * Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * * Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in
|
|
+ * the documentation and/or other materials provided with the
|
|
+ * distribution.
|
|
+ * * Neither the name of Intel Corporation nor the names of its
|
|
+ * contributors may be used to endorse or promote products derived
|
|
+ * from this software without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * Authors:
|
|
+ *
|
|
+ * Serge Ayoun <serge.ayoun@intel.com>
|
|
+ * Angie Chinchilla <angie.v.chinchilla@intel.com>
|
|
+ * Shay Katz-zamir <shay.katz-zamir@intel.com>
|
|
+ * Cedric Xing <cedric.xing@intel.com>
|
|
+ */
|
|
+
|
|
+#include "sgx.h"
|
|
+#include <linux/ratelimit.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+#define SGX_NR_MOD_CHUNK_PAGES 16
|
|
+
|
|
+int sgx_init_page(struct sgx_encl *encl, struct sgx_encl_page *entry,
|
|
+ unsigned long addr, unsigned int alloc_flags,
|
|
+ struct sgx_epc_page **va_src, bool already_locked);
|
|
+/**
|
|
+ * sgx_encl_augment() - adds a page to an enclave
|
|
+ * @addr: virtual address where the page should be added
|
|
+ *
|
|
+ * the address is checked against the dynamic ranges defined for
|
|
+ * the enclave. If it matches one, a page is added at the
|
|
+ * corresponding location
|
|
+ *
|
|
+ * Note: Invoking function must already hold the encl->lock
|
|
+ */
|
|
+struct sgx_encl_page *sgx_encl_augment(struct vm_area_struct *vma,
|
|
+ unsigned long addr,
|
|
+ bool write)
|
|
+{
|
|
+ struct sgx_pageinfo pginfo;
|
|
+ struct sgx_epc_page *epc_page, *va_page = NULL;
|
|
+ struct sgx_epc_page *secs_epc_page = NULL;
|
|
+ struct sgx_encl_page *encl_page;
|
|
+ struct sgx_encl *encl = (struct sgx_encl *) vma->vm_private_data;
|
|
+ void *epc_va;
|
|
+ void *secs_va;
|
|
+ int ret = -EFAULT;
|
|
+
|
|
+ if (!sgx_has_sgx2)
|
|
+ return ERR_PTR(-EFAULT);
|
|
+
|
|
+ /* if vma area is not writable then we will not eaug */
|
|
+ if (unlikely(!(vma->vm_flags & VM_WRITE)))
|
|
+ return ERR_PTR(-EFAULT);
|
|
+
|
|
+ addr &= ~(PAGE_SIZE-1);
|
|
+
|
|
+ /* Note: Invoking function holds the encl->lock */
|
|
+
|
|
+ epc_page = sgx_alloc_page(SGX_ALLOC_ATOMIC);
|
|
+ if (IS_ERR(epc_page)) {
|
|
+ return ERR_PTR(PTR_ERR(epc_page));
|
|
+ }
|
|
+
|
|
+ va_page = sgx_alloc_page(SGX_ALLOC_ATOMIC);
|
|
+ if (IS_ERR(va_page)) {
|
|
+ sgx_free_page(epc_page, encl);
|
|
+ return ERR_PTR(PTR_ERR(va_page));
|
|
+ }
|
|
+
|
|
+ encl_page = kzalloc(sizeof(struct sgx_encl_page), GFP_KERNEL);
|
|
+ if (!encl_page) {
|
|
+ sgx_free_page(epc_page, encl);
|
|
+ sgx_free_page(va_page, encl);
|
|
+ return ERR_PTR(-EFAULT);
|
|
+ }
|
|
+
|
|
+ if (!(encl->flags & SGX_ENCL_INITIALIZED))
|
|
+ goto out;
|
|
+
|
|
+ if (encl->flags & (SGX_ENCL_SUSPEND | SGX_ENCL_DEAD))
|
|
+ goto out;
|
|
+
|
|
+ /*
|
|
+ if ((rg->rg_desc.flags & SGX_GROW_DOWN_FLAG) && !write)
|
|
+ goto out;
|
|
+ */
|
|
+
|
|
+ /* Start the augmenting process */
|
|
+ ret = sgx_init_page(encl, encl_page, addr, 0, &va_page, true);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+
|
|
+ /* If SECS is evicted then reload it first */
|
|
+ /* Same steps as in sgx_do_fault */
|
|
+ if (encl->flags & SGX_ENCL_SECS_EVICTED) {
|
|
+ secs_epc_page = sgx_alloc_page(SGX_ALLOC_ATOMIC);
|
|
+ if (IS_ERR(secs_epc_page)) {
|
|
+ ret = PTR_ERR(secs_epc_page);
|
|
+ secs_epc_page = NULL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = sgx_eldu(encl, &encl->secs, secs_epc_page, true);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+
|
|
+ encl->secs.epc_page = secs_epc_page;
|
|
+ encl->flags &= ~SGX_ENCL_SECS_EVICTED;
|
|
+
|
|
+ /* Do not free */
|
|
+ secs_epc_page = NULL;
|
|
+ }
|
|
+
|
|
+ secs_va = sgx_get_page(encl->secs.epc_page);
|
|
+ epc_va = sgx_get_page(epc_page);
|
|
+
|
|
+ pginfo.srcpge = 0;
|
|
+ pginfo.secinfo = 0;
|
|
+ pginfo.linaddr = addr;
|
|
+ pginfo.secs = (unsigned long) secs_va;
|
|
+
|
|
+ ret = __eaug(&pginfo, epc_va);
|
|
+ if (ret) {
|
|
+ pr_err("sgx: eaug failure with ret=%d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = vm_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa));
|
|
+ sgx_put_page(epc_va);
|
|
+ sgx_put_page(secs_va);
|
|
+ if (ret) {
|
|
+ pr_err("sgx: vm_insert_pfn failure with ret=%d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ epc_page->encl_page = encl_page;
|
|
+ encl_page->epc_page = epc_page;
|
|
+ encl->secs_child_cnt++;
|
|
+
|
|
+ ret = radix_tree_insert(&encl->page_tree, encl_page->addr >> PAGE_SHIFT,
|
|
+ encl_page);
|
|
+ if (ret) {
|
|
+ pr_err("sgx: radix_tree_insert failed with ret=%d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+ sgx_test_and_clear_young(encl_page, encl);
|
|
+ list_add_tail(&encl_page->epc_page->list, &encl->load_list);
|
|
+ encl_page->flags |= SGX_ENCL_PAGE_ADDED;
|
|
+
|
|
+ if (va_page)
|
|
+ sgx_free_page(va_page, encl);
|
|
+ if (secs_epc_page)
|
|
+ sgx_free_page(secs_epc_page, encl);
|
|
+
|
|
+ /*
|
|
+ * Write operation corresponds to stack extension
|
|
+ * In this case the #PF is caused by a write operation,
|
|
+ * most probably a push.
|
|
+ * We return SIGBUS such that the OS invokes the enclave's exception
|
|
+ * handler which will execute eaccept.
|
|
+ */
|
|
+ if (write)
|
|
+ return ERR_PTR(-EFAULT);
|
|
+
|
|
+ return encl_page;
|
|
+
|
|
+out:
|
|
+ if (encl_page->va_offset)
|
|
+ sgx_free_va_slot(encl_page->va_page, encl_page->va_offset);
|
|
+ sgx_free_page(epc_page, encl);
|
|
+ if (va_page)
|
|
+ sgx_free_page(va_page, encl);
|
|
+ kfree(encl_page);
|
|
+ if (secs_epc_page)
|
|
+ sgx_free_page(secs_epc_page, encl);
|
|
+
|
|
+ if ((ret == -EBUSY)||(ret == -ERESTARTSYS))
|
|
+ return ERR_PTR(ret);
|
|
+
|
|
+ return ERR_PTR(-EFAULT);
|
|
+}
|
|
+
|
|
+static int isolate_range(struct sgx_encl *encl,
|
|
+ struct sgx_range *rg, struct list_head *list)
|
|
+{
|
|
+ unsigned long address, end;
|
|
+ struct sgx_encl_page *encl_page;
|
|
+ struct vm_area_struct *vma;
|
|
+ int ret;
|
|
+
|
|
+ address = rg->start_addr;
|
|
+ end = address + rg->nr_pages * PAGE_SIZE;
|
|
+
|
|
+ ret = sgx_encl_find(encl->mm, address, &vma);
|
|
+ if (ret || encl != vma->vm_private_data)
|
|
+ return -EINVAL;
|
|
+
|
|
+ for (; address < end; address += PAGE_SIZE) {
|
|
+ encl_page = ERR_PTR(-EBUSY);
|
|
+ while (encl_page == ERR_PTR(-EBUSY))
|
|
+ /* bring back page in case it was evicted */
|
|
+ encl_page = sgx_fault_page(vma, address,
|
|
+ SGX_FAULT_RESERVE, NULL);
|
|
+
|
|
+ if (IS_ERR(encl_page)) {
|
|
+ sgx_err(encl, "sgx: No page found at address 0x%lx\n",
|
|
+ address);
|
|
+ return PTR_ERR(encl_page);
|
|
+ }
|
|
+
|
|
+ /* We do not need the reserved bit anymore as page
|
|
+ * is removed from the load list
|
|
+ */
|
|
+ mutex_lock(&encl->lock);
|
|
+ list_move_tail(&encl_page->epc_page->list, list);
|
|
+ encl_page->flags &= ~SGX_ENCL_PAGE_RESERVED;
|
|
+ mutex_unlock(&encl->lock);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __modify_range(struct sgx_encl *encl,
|
|
+ struct sgx_range *rg, struct sgx_secinfo *secinfo)
|
|
+{
|
|
+ struct sgx_encl_page *encl_page;
|
|
+ struct sgx_epc_page *epc_page, *tmp;
|
|
+ LIST_HEAD(list);
|
|
+ bool emodt = secinfo->flags & (SGX_SECINFO_TRIM | SGX_SECINFO_TCS);
|
|
+ unsigned int epoch = 0;
|
|
+ void *epc_va;
|
|
+ int ret = 0, cnt, status = 0;
|
|
+
|
|
+ ret = isolate_range(encl, rg, &list);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+
|
|
+ if (list_empty(&list))
|
|
+ goto out;
|
|
+
|
|
+ /* EMODT / EMODPR */
|
|
+ list_for_each_entry_safe(epc_page, tmp, &list, list) {
|
|
+ encl_page = epc_page->encl_page;
|
|
+ if (!emodt && (encl_page->flags & SGX_ENCL_PAGE_TCS)) {
|
|
+ sgx_err(encl, "sgx: illegal request: page at\
|
|
+ address=0x%lx is a TCS, req flags=0x%llx\n",
|
|
+ encl_page->addr, secinfo->flags);
|
|
+ ret = -EINVAL;
|
|
+ continue;
|
|
+ }
|
|
+ mutex_lock(&encl->lock);
|
|
+ epc_va = sgx_get_page(epc_page);
|
|
+ status = SGX_LOCKFAIL;
|
|
+ cnt = 0;
|
|
+ while (SGX_LOCKFAIL == status && cnt < SGX_EDMM_SPIN_COUNT) {
|
|
+ if (emodt) {
|
|
+ status = __emodt(secinfo, epc_va);
|
|
+ if (!status)
|
|
+ encl_page->flags |= SGX_ENCL_PAGE_TCS;
|
|
+ } else
|
|
+ status = __emodpr(secinfo, epc_va);
|
|
+ cnt++;
|
|
+ }
|
|
+
|
|
+ epoch = encl->shadow_epoch;
|
|
+ sgx_put_page(epc_va);
|
|
+ mutex_unlock(&encl->lock);
|
|
+
|
|
+ if (status) {
|
|
+ sgx_err(encl, "sgx: Page at address=0x%lx \
|
|
+ can't be modified err=%d req flags=0x%llx\n",
|
|
+ encl_page->addr, status, secinfo->flags);
|
|
+ ret = (ret) ? ret : status;
|
|
+ } else {
|
|
+ if (SGX_SECINFO_TRIM == secinfo->flags)
|
|
+ encl_page->flags |= SGX_ENCL_PAGE_TRIM;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* ETRACK */
|
|
+ mutex_lock(&encl->lock);
|
|
+ sgx_etrack(encl, epoch);
|
|
+ mutex_unlock(&encl->lock);
|
|
+
|
|
+ smp_call_function(sgx_ipi_cb, NULL, 1);
|
|
+
|
|
+out:
|
|
+ if (!list_empty(&list)) {
|
|
+ mutex_lock(&encl->lock);
|
|
+ list_splice(&list, &encl->load_list);
|
|
+ mutex_unlock(&encl->lock);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+long modify_range(struct sgx_range *rg, unsigned long flags)
|
|
+{
|
|
+ struct sgx_encl *encl;
|
|
+ struct sgx_secinfo secinfo;
|
|
+ struct sgx_range _rg;
|
|
+ unsigned long end = rg->start_addr + rg->nr_pages * PAGE_SIZE;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!sgx_has_sgx2)
|
|
+ return -ENOSYS;
|
|
+
|
|
+ if (rg->start_addr & (PAGE_SIZE - 1))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!rg->nr_pages)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ret = sgx_get_encl(rg->start_addr, &encl);
|
|
+ if (ret) {
|
|
+ pr_warn("sgx: No enclave found at start addr 0x%lx ret=%d\n",
|
|
+ rg->start_addr, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (end > encl->base + encl->size) {
|
|
+ ret = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ memset(&secinfo, 0, sizeof(secinfo));
|
|
+ secinfo.flags = flags;
|
|
+
|
|
+ /*
|
|
+ * Modifying the range by chunks of 16 pages:
|
|
+ * these pages are removed from the load list. Bigger chunks
|
|
+ * may empty EPC load lists and stall SGX.
|
|
+ */
|
|
+ for (_rg.start_addr = rg->start_addr;
|
|
+ _rg.start_addr < end;
|
|
+ rg->nr_pages -= SGX_NR_MOD_CHUNK_PAGES,
|
|
+ _rg.start_addr += SGX_NR_MOD_CHUNK_PAGES*PAGE_SIZE) {
|
|
+ _rg.nr_pages = rg->nr_pages > 0x10 ? 0x10 : rg->nr_pages;
|
|
+ ret = __modify_range(encl, &_rg, &secinfo);
|
|
+ if (ret)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ kref_put(&encl->refcount, sgx_encl_release);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int remove_page(struct sgx_encl *encl, unsigned long address, bool trim)
|
|
+{
|
|
+ struct sgx_encl_page *encl_page;
|
|
+ struct vm_area_struct *vma;
|
|
+ struct sgx_va_page *va_page;
|
|
+ int ret;
|
|
+
|
|
+ ret = sgx_encl_find(encl->mm, address, &vma);
|
|
+ if (ret || encl != vma->vm_private_data)
|
|
+ return -EINVAL;
|
|
+
|
|
+ encl_page = sgx_fault_page(vma, address, SGX_FAULT_RESERVE, NULL);
|
|
+ if (IS_ERR(encl_page))
|
|
+ return (PTR_ERR(encl_page) == -EBUSY) ? -EBUSY : -EINVAL;
|
|
+
|
|
+ if (trim && !(encl_page->flags & SGX_ENCL_PAGE_TRIM)) {
|
|
+ encl_page->flags &= ~SGX_ENCL_PAGE_RESERVED;
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (!(encl_page->flags & SGX_ENCL_PAGE_ADDED)) {
|
|
+ encl_page->flags &= ~SGX_ENCL_PAGE_RESERVED;
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ mutex_lock(&encl->lock);
|
|
+
|
|
+ radix_tree_delete(&encl->page_tree, encl_page->addr >> PAGE_SHIFT);
|
|
+ va_page = encl_page->va_page;
|
|
+
|
|
+ if (va_page) {
|
|
+ sgx_free_va_slot(va_page, encl_page->va_offset);
|
|
+
|
|
+ if (sgx_va_slots_empty(va_page)) {
|
|
+ list_del(&va_page->list);
|
|
+ sgx_free_page(va_page->epc_page, encl);
|
|
+ kfree(va_page);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (encl_page->epc_page) {
|
|
+ list_del(&encl_page->epc_page->list);
|
|
+ encl_page->epc_page->encl_page = NULL;
|
|
+ zap_vma_ptes(vma, encl_page->addr, PAGE_SIZE);
|
|
+ sgx_free_page(encl_page->epc_page, encl);
|
|
+ encl->secs_child_cnt--;
|
|
+ }
|
|
+
|
|
+ mutex_unlock(&encl->lock);
|
|
+
|
|
+ kfree(encl_page);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/sgx_ioctl.c b/sgx_ioctl.c
|
|
index f7540fc..0b3476d 100644
|
|
--- a/sgx_ioctl.c
|
|
+++ b/sgx_ioctl.c
|
|
@@ -73,7 +73,7 @@
|
|
#include <linux/hashtable.h>
|
|
#include <linux/shmem_fs.h>
|
|
|
|
-static int sgx_get_encl(unsigned long addr, struct sgx_encl **encl)
|
|
+int sgx_get_encl(unsigned long addr, struct sgx_encl **encl)
|
|
{
|
|
struct mm_struct *mm = current->mm;
|
|
struct vm_area_struct *vma;
|
|
@@ -251,6 +251,123 @@ out:
|
|
return ret;
|
|
}
|
|
|
|
+long sgx_ioc_page_modpr(struct file *filep, unsigned int cmd,
|
|
+ unsigned long arg)
|
|
+{
|
|
+ struct sgx_modification_param *p =
|
|
+ (struct sgx_modification_param *) arg;
|
|
+
|
|
+ /*
|
|
+ * Only RWX flags in mask are allowed
|
|
+ * Restricting WR w/o RD is not allowed
|
|
+ */
|
|
+ if (p->flags & ~(SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_X))
|
|
+ return -EINVAL;
|
|
+ if (!(p->flags & SGX_SECINFO_R) &&
|
|
+ (p->flags & SGX_SECINFO_W))
|
|
+ return -EINVAL;
|
|
+ return modify_range(&p->range, p->flags);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * sgx_ioc_page_to_tcs() - Pages defined in range are switched to TCS.
|
|
+ * These pages should be of type REG.
|
|
+ * eaccept needs to be invoked after return.
|
|
+ * @arg range address of pages to be switched
|
|
+ */
|
|
+long sgx_ioc_page_to_tcs(struct file *filep, unsigned int cmd,
|
|
+ unsigned long arg)
|
|
+{
|
|
+ return modify_range((struct sgx_range *)arg, SGX_SECINFO_TCS);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * sgx_ioc_trim_page() - Pages defined in range are being trimmed.
|
|
+ * These pages still belong to the enclave and can not be removed until
|
|
+ * eaccept has been invoked
|
|
+ * @arg range address of pages to be trimmed
|
|
+ */
|
|
+long sgx_ioc_trim_page(struct file *filep, unsigned int cmd,
|
|
+ unsigned long arg)
|
|
+{
|
|
+ return modify_range((struct sgx_range *)arg, SGX_SECINFO_TRIM);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * sgx_ioc_page_notify_accept() - Pages defined in range will be moved to
|
|
+ * the trimmed list, i.e. they can be freely removed from now. These pages
|
|
+ * should have PT_TRIM page type and should have been eaccepted priorly
|
|
+ * @arg range address of pages
|
|
+ */
|
|
+long sgx_ioc_page_notify_accept(struct file *filep, unsigned int cmd,
|
|
+ unsigned long arg)
|
|
+{
|
|
+ struct sgx_range *rg;
|
|
+ unsigned long address, end;
|
|
+ struct sgx_encl *encl;
|
|
+ int ret, tmp_ret = 0;
|
|
+
|
|
+ if (!sgx_has_sgx2)
|
|
+ return -ENOSYS;
|
|
+
|
|
+ rg = (struct sgx_range *)arg;
|
|
+
|
|
+ address = rg->start_addr;
|
|
+ address &= ~(PAGE_SIZE-1);
|
|
+ end = address + rg->nr_pages * PAGE_SIZE;
|
|
+
|
|
+ ret = sgx_get_encl(address, &encl);
|
|
+ if (ret) {
|
|
+ pr_warn("sgx: No enclave found at start address 0x%lx\n",
|
|
+ address);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ for (; address < end; address += PAGE_SIZE) {
|
|
+ tmp_ret = remove_page(encl, address, true);
|
|
+ if (tmp_ret) {
|
|
+ sgx_dbg(encl, "sgx: remove failed, addr=0x%lx ret=%d\n",
|
|
+ address, tmp_ret);
|
|
+ ret = tmp_ret;
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ kref_put(&encl->refcount, sgx_encl_release);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * sgx_ioc_page_remove() - Pages defined by address will be removed
|
|
+ * @arg address of page
|
|
+ */
|
|
+long sgx_ioc_page_remove(struct file *filep, unsigned int cmd,
|
|
+ unsigned long arg)
|
|
+{
|
|
+ struct sgx_encl *encl;
|
|
+ unsigned long address = *((unsigned long *) arg);
|
|
+ int ret;
|
|
+
|
|
+ if (!sgx_has_sgx2)
|
|
+ return -ENOSYS;
|
|
+
|
|
+ if (sgx_get_encl(address, &encl)) {
|
|
+ pr_warn("sgx: No enclave found at start address 0x%lx\n",
|
|
+ address);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = remove_page(encl, address, false);
|
|
+ if (ret) {
|
|
+ pr_warn("sgx: Failed to remove page, address=0x%lx ret=%d\n",
|
|
+ address, ret);
|
|
+ }
|
|
+
|
|
+ kref_put(&encl->refcount, sgx_encl_release);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
typedef long (*sgx_ioc_t)(struct file *filep, unsigned int cmd,
|
|
unsigned long arg);
|
|
|
|
@@ -270,6 +387,21 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
|
case SGX_IOC_ENCLAVE_INIT:
|
|
handler = sgx_ioc_enclave_init;
|
|
break;
|
|
+ case SGX_IOC_ENCLAVE_EMODPR:
|
|
+ handler = sgx_ioc_page_modpr;
|
|
+ break;
|
|
+ case SGX_IOC_ENCLAVE_MKTCS:
|
|
+ handler = sgx_ioc_page_to_tcs;
|
|
+ break;
|
|
+ case SGX_IOC_ENCLAVE_TRIM:
|
|
+ handler = sgx_ioc_trim_page;
|
|
+ break;
|
|
+ case SGX_IOC_ENCLAVE_NOTIFY_ACCEPT:
|
|
+ handler = sgx_ioc_page_notify_accept;
|
|
+ break;
|
|
+ case SGX_IOC_ENCLAVE_PAGE_REMOVE:
|
|
+ handler = sgx_ioc_page_remove;
|
|
+ break;
|
|
default:
|
|
return -ENOIOCTLCMD;
|
|
}
|
|
diff --git a/sgx_main.c b/sgx_main.c
|
|
index 7ff3864..7b7c384 100644
|
|
--- a/sgx_main.c
|
|
+++ b/sgx_main.c
|
|
@@ -71,7 +71,7 @@
|
|
#include <linux/platform_device.h>
|
|
|
|
#define DRV_DESCRIPTION "Intel SGX Driver"
|
|
-#define DRV_VERSION "0.10"
|
|
+#define DRV_VERSION "0.11"
|
|
|
|
MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
|
MODULE_AUTHOR("Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>");
|
|
@@ -95,6 +95,7 @@ u64 sgx_encl_size_max_64;
|
|
u64 sgx_xfrm_mask = 0x3;
|
|
u32 sgx_misc_reserved;
|
|
u32 sgx_xsave_size_tbl[64];
|
|
+bool sgx_has_sgx2;
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
long sgx_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
|
@@ -325,6 +326,8 @@ static int sgx_drv_probe(struct platform_device *pdev)
|
|
return -ENODEV;
|
|
}
|
|
|
|
+ sgx_has_sgx2 = (eax & 2) != 0;
|
|
+
|
|
return sgx_dev_init(&pdev->dev);
|
|
}
|
|
|
|
diff --git a/sgx_page_cache.c b/sgx_page_cache.c
|
|
index 8472037..b4bc985 100644
|
|
--- a/sgx_page_cache.c
|
|
+++ b/sgx_page_cache.c
|
|
@@ -335,7 +335,7 @@ static void sgx_write_pages(struct sgx_encl *encl, struct list_head *src)
|
|
}
|
|
|
|
/* ETRACK */
|
|
- sgx_etrack(encl);
|
|
+ sgx_etrack(encl, encl->shadow_epoch);
|
|
|
|
/* EWB */
|
|
while (!list_empty(src)) {
|
|
diff --git a/sgx_user.h b/sgx_user.h
|
|
index a15f87b..50f0931 100644
|
|
--- a/sgx_user.h
|
|
+++ b/sgx_user.h
|
|
@@ -69,6 +69,16 @@
|
|
_IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page)
|
|
#define SGX_IOC_ENCLAVE_INIT \
|
|
_IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init)
|
|
+#define SGX_IOC_ENCLAVE_EMODPR \
|
|
+ _IOW(SGX_MAGIC, 0x09, struct sgx_modification_param)
|
|
+#define SGX_IOC_ENCLAVE_MKTCS \
|
|
+ _IOW(SGX_MAGIC, 0x0a, struct sgx_range)
|
|
+#define SGX_IOC_ENCLAVE_TRIM \
|
|
+ _IOW(SGX_MAGIC, 0x0b, struct sgx_range)
|
|
+#define SGX_IOC_ENCLAVE_NOTIFY_ACCEPT \
|
|
+ _IOW(SGX_MAGIC, 0x0c, struct sgx_range)
|
|
+#define SGX_IOC_ENCLAVE_PAGE_REMOVE \
|
|
+ _IOW(SGX_MAGIC, 0x0d, unsigned long)
|
|
|
|
/* SGX leaf instruction return values */
|
|
#define SGX_SUCCESS 0
|
|
@@ -90,6 +100,7 @@
|
|
#define SGX_INVALID_EINITTOKEN 16
|
|
#define SGX_PREV_TRK_INCMPL 17
|
|
#define SGX_PG_IS_SECS 18
|
|
+#define SGX_PAGE_NOT_MODIFIABLE 20
|
|
#define SGX_INVALID_CPUSVN 32
|
|
#define SGX_INVALID_ISVSVN 64
|
|
#define SGX_UNMASKED_EVENT 128
|
|
@@ -136,4 +147,18 @@ struct sgx_enclave_init {
|
|
__u64 einittoken;
|
|
} __attribute__((__packed__));
|
|
|
|
+/*
|
|
+ * SGX2.0 definitions
|
|
+ */
|
|
+
|
|
+struct sgx_range {
|
|
+ unsigned long start_addr;
|
|
+ unsigned int nr_pages;
|
|
+};
|
|
+
|
|
+struct sgx_modification_param {
|
|
+ struct sgx_range range;
|
|
+ unsigned long flags;
|
|
+};
|
|
+
|
|
#endif /* _UAPI_ASM_X86_SGX_H */
|
|
diff --git a/sgx_util.c b/sgx_util.c
|
|
index ff0e40a..fd5022a 100644
|
|
--- a/sgx_util.c
|
|
+++ b/sgx_util.c
|
|
@@ -135,7 +135,7 @@ void sgx_invalidate(struct sgx_encl *encl, bool flush_cpus)
|
|
sgx_flush_cpus(encl);
|
|
}
|
|
|
|
-static void sgx_ipi_cb(void *info)
|
|
+void sgx_ipi_cb(void *info)
|
|
{
|
|
}
|
|
|
|
@@ -144,10 +144,10 @@ void sgx_flush_cpus(struct sgx_encl *encl)
|
|
on_each_cpu_mask(mm_cpumask(encl->mm), sgx_ipi_cb, NULL, 1);
|
|
}
|
|
|
|
-static int sgx_eldu(struct sgx_encl *encl,
|
|
- struct sgx_encl_page *encl_page,
|
|
- struct sgx_epc_page *epc_page,
|
|
- bool is_secs)
|
|
+int sgx_eldu(struct sgx_encl *encl,
|
|
+ struct sgx_encl_page *encl_page,
|
|
+ struct sgx_epc_page *epc_page,
|
|
+ bool is_secs)
|
|
{
|
|
struct page *backing;
|
|
struct page *pcmd;
|
|
@@ -212,7 +212,8 @@ out:
|
|
|
|
static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma,
|
|
unsigned long addr,
|
|
- unsigned int flags)
|
|
+ unsigned int flags,
|
|
+ struct vm_fault *vmf)
|
|
{
|
|
struct sgx_encl *encl = vma->vm_private_data;
|
|
struct sgx_encl_page *entry;
|
|
@@ -220,6 +221,7 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma,
|
|
struct sgx_epc_page *secs_epc_page = NULL;
|
|
bool reserve = (flags & SGX_FAULT_RESERVE) != 0;
|
|
int rc = 0;
|
|
+ bool write = (vmf) ? (FAULT_FLAG_WRITE & vmf->flags) : false;
|
|
|
|
/* If process was forked, VMA is still there but vm_private_data is set
|
|
* to NULL.
|
|
@@ -230,6 +232,14 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma,
|
|
mutex_lock(&encl->lock);
|
|
|
|
entry = radix_tree_lookup(&encl->page_tree, addr >> PAGE_SHIFT);
|
|
+ if (vmf && !entry) {
|
|
+ entry = sgx_encl_augment(vma, addr, write);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /* No entry found can not happen in 'reloading an evicted page'
|
|
+ * flow.
|
|
+ */
|
|
if (!entry) {
|
|
rc = -EFAULT;
|
|
goto out;
|
|
@@ -331,12 +341,13 @@ out:
|
|
|
|
struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma,
|
|
unsigned long addr,
|
|
- unsigned int flags)
|
|
+ unsigned int flags,
|
|
+ struct vm_fault *vmf)
|
|
{
|
|
struct sgx_encl_page *entry;
|
|
|
|
do {
|
|
- entry = sgx_do_fault(vma, addr, flags);
|
|
+ entry = sgx_do_fault(vma, addr, flags, vmf);
|
|
if (!(flags & SGX_FAULT_RESERVE))
|
|
break;
|
|
} while (PTR_ERR(entry) == -EBUSY);
|
|
@@ -360,16 +371,25 @@ void sgx_eblock(struct sgx_encl *encl, struct sgx_epc_page *epc_page)
|
|
|
|
}
|
|
|
|
-void sgx_etrack(struct sgx_encl *encl)
|
|
+void sgx_etrack(struct sgx_encl *encl, unsigned int epoch)
|
|
{
|
|
void *epc;
|
|
int ret;
|
|
|
|
+ /* If someone already called etrack in the meantime */
|
|
+ if (epoch < encl->shadow_epoch)
|
|
+ return;
|
|
+
|
|
epc = sgx_get_page(encl->secs.epc_page);
|
|
ret = __etrack(epc);
|
|
sgx_put_page(epc);
|
|
+ encl->shadow_epoch++;
|
|
|
|
- if (ret) {
|
|
+ if (ret == SGX_PREV_TRK_INCMPL) {
|
|
+ sgx_dbg(encl, "ETRACK returned %d\n", ret);
|
|
+ smp_call_function(sgx_ipi_cb, NULL, 1);
|
|
+ BUG_ON(__etrack(epc));
|
|
+ } else if (ret) {
|
|
sgx_crit(encl, "ETRACK returned %d\n", ret);
|
|
sgx_invalidate(encl, true);
|
|
}
|
|
diff --git a/sgx_vma.c b/sgx_vma.c
|
|
index dae9eb9..bcd1047 100644
|
|
--- a/sgx_vma.c
|
|
+++ b/sgx_vma.c
|
|
@@ -76,6 +76,12 @@ static void sgx_vma_open(struct vm_area_struct *vma)
|
|
if (!encl)
|
|
return;
|
|
|
|
+ /* protect from fork */
|
|
+ if (encl->mm != current->mm) {
|
|
+ vma->vm_private_data = NULL;
|
|
+ return;
|
|
+ }
|
|
+
|
|
/* kref cannot underflow because ECREATE ioctl checks that there is only
|
|
* one single VMA for the enclave before proceeding.
|
|
*/
|
|
@@ -113,7 +119,7 @@ static int sgx_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
#endif
|
|
struct sgx_encl_page *entry;
|
|
|
|
- entry = sgx_fault_page(vma, addr, 0);
|
|
+ entry = sgx_fault_page(vma, addr, 0, vmf);
|
|
|
|
if (!IS_ERR(entry) || PTR_ERR(entry) == -EBUSY)
|
|
return VM_FAULT_NOPAGE;
|
|
@@ -212,7 +218,7 @@ static int sgx_vma_access(struct vm_area_struct *vma, unsigned long addr,
|
|
entry->flags &= ~SGX_ENCL_PAGE_RESERVED;
|
|
|
|
entry = sgx_fault_page(vma, (addr + i) & PAGE_MASK,
|
|
- SGX_FAULT_RESERVE);
|
|
+ SGX_FAULT_RESERVE, NULL);
|
|
if (IS_ERR(entry)) {
|
|
ret = PTR_ERR(entry);
|
|
entry = NULL;
|
|
--
|
|
2.7.4
|
|
|