From 82413e8983a65638690f25d7d9c7565c3fbdfa1e Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Mon, 30 Oct 2017 16:18:40 -0400 Subject: [PATCH 01/50] Fix memory leak of SECS EPC page in error path. Signed-off-by: Angie Chinchilla --- sgx_ioctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sgx_ioctl.c b/sgx_ioctl.c index 69409d4..f2519a5 100644 --- a/sgx_ioctl.c +++ b/sgx_ioctl.c @@ -549,6 +549,8 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, goto out; } + encl->secs_page.epc_page = secs_epc; + ret = sgx_add_to_tgid_ctx(encl); if (ret) goto out; @@ -575,7 +577,6 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, goto out; } - encl->secs_page.epc_page = secs_epc; createp->src = (unsigned long)encl->base; if (secs->flags & SGX_SECS_A_DEBUG) From 24bd0ac2c443438695de82e446833e9b0a060b6f Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Mon, 5 Jun 2017 11:08:18 -0400 Subject: [PATCH 02/50] SGX 2.0 Implementation Authors: Serge Ayoun Angie Chinchilla Shay Katz-zamir Cedric Xing Signed-off-by: Angie Chinchilla --- Makefile | 2 +- README.md | 3 +- sgx.h | 28 ++- sgx_arch.h | 5 +- sgx_ioctl.c | 545 +++++++++++++++++++++++++++++++++++++++++++++-- sgx_main.c | 2 +- sgx_page_cache.c | 21 +- sgx_user.h | 29 +++ sgx_util.c | 28 ++- sgx_vma.c | 11 +- 10 files changed, 642 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 896d397..11f2927 100644 --- a/Makefile +++ b/Makefile @@ -20,4 +20,4 @@ install: default endif clean: - rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd + rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd .*.o.d diff --git a/README.md b/README.md index a8b2b04..61946c4 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Contributing ------- Starting from 05/2017, we are importing the sgx driver code from the in-kernel sgx repository located at git-hub: https://github.com/jsakkine-intel/linux-sgx.git. Any contribution should be done there. Future versions of the sgx driver code will be imported later on. The motivation behind this decision is to maintain a single source code of the sgx linux driver. An additional directory inker2ext/ has been created, it contains a script and a patch file that can be used in order to separately generate the code base of the sgx external module; it can be used in case someone wants the newest sgx driver as an external module and does not want to wait for next update. +The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch is maintained in inker2ext/sgx2.patch in the 2.0 branch and will be periodically updated to the linux-sgx-driver:master branch. Contributions for this patch should be managed directly through the linux-sgx-driver project on Github. sgx2 will have the same behavior as linux-sgx-driver on hardware platforms that do not support SGX 2.0. Documentation ------------- @@ -31,7 +32,7 @@ Build and Install the Intel(R) SGX Driver ### Prerequisites - Ensure that you have the following required operating systems: * Ubuntu* Desktop-16.04-LTS 64bits - * Red Hat Enterprise Linux Server release 7.2 64bits + * Red Hat Enterprise Linux Server release 7.3 64bits * CentOS 7.3.1611 64bits - Ensure that you have the following required hardware: * 6th Generation Intel(R) Core(TM) Processor (code named Skylake) diff --git a/sgx.h b/sgx.h index 01dcfb3..0dae86c 100644 --- a/sgx.h +++ b/sgx.h @@ -69,11 +69,13 @@ #include #include #include +#include #include "sgx_arch.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 @@ -99,9 +101,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 { @@ -147,6 +161,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 { @@ -210,11 +225,22 @@ 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); void sgx_encl_release(struct kref *ref); void sgx_tgid_ctx_release(struct kref *ref); +void sgx_ipi_cb(void *info); +bool sgx_etrack(struct sgx_encl *encl, unsigned int epoch); +struct sgx_encl_page *sgx_augment_encl(struct vm_area_struct *vma, + unsigned long addr, + bool write); +int sgx_eldu(struct sgx_encl *encl, + struct sgx_encl_page *encl_page, + struct sgx_epc_page *epc_page, + bool is_secs); + extern struct mutex sgx_tgid_ctx_mutex; extern struct list_head sgx_tgid_ctx_list; extern struct task_struct *ksgxswapd_tsk; diff --git a/sgx_arch.h b/sgx_arch.h index 233d3a6..6d2fea9 100644 --- a/sgx_arch.h +++ b/sgx_arch.h @@ -81,6 +81,7 @@ enum sgx_secinfo_flags { SGX_SECINFO_SECS = 0x000ULL, SGX_SECINFO_TCS = 0x100ULL, SGX_SECINFO_REG = 0x200ULL, + SGX_SECINFO_TRIM = 0x400ULL, }; struct sgx_secinfo { @@ -105,7 +106,7 @@ enum isgx_secs_attributes { GENMASK_ULL(63, 6)), }; -#define SGX_SECS_RESERVED1_SIZE 28 +#define SGX_SECS_RESERVED1_SIZE 24 #define SGX_SECS_RESERVED2_SIZE 32 #define SGX_SECS_RESERVED3_SIZE 96 #define SGX_SECS_RESERVED4_SIZE 3836 @@ -114,6 +115,7 @@ struct sgx_secs { u64 size; u64 base; u32 ssaframesize; + u32 misc_select; uint8_t reserved1[SGX_SECS_RESERVED1_SIZE]; u64 flags; u64 xfrm; @@ -339,6 +341,7 @@ static inline int __emodt(struct sgx_secinfo *secinfo, void *epc) return __encls_ret(EMODT, secinfo, epc, rdx); } + struct sgx_encl; struct sgx_epc_page { diff --git a/sgx_ioctl.c b/sgx_ioctl.c index f2519a5..9cedfd3 100644 --- a/sgx_ioctl.c +++ b/sgx_ioctl.c @@ -73,6 +73,8 @@ #include #include +#define SGX_NR_MOD_CHUNK_PAGES 16 + struct sgx_add_page_req { struct sgx_encl *encl; struct sgx_encl_page *encl_page; @@ -274,6 +276,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(&encl_page->load_list, &encl->load_list); + encl_page->flags |= SGX_ENCL_PAGE_ADDED; mutex_unlock(&encl->lock); up_read(&encl->mm->mmap_sem); @@ -390,7 +393,9 @@ static int sgx_validate_secs(const struct sgx_secs *secs) static int sgx_init_page(struct sgx_encl *encl, struct sgx_encl_page *entry, - unsigned long addr) + unsigned long addr, + struct sgx_epc_page **va_src, + bool already_locked) { struct sgx_va_page *va_page; struct sgx_epc_page *epc_page = NULL; @@ -409,10 +414,15 @@ static int sgx_init_page(struct sgx_encl *encl, if (!va_page) return -ENOMEM; - epc_page = sgx_alloc_page(0); - 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(0); + if (IS_ERR(epc_page)) { + kfree(va_page); + return PTR_ERR(epc_page); + } } vaddr = sgx_get_page(epc_page); @@ -437,9 +447,11 @@ static int sgx_init_page(struct sgx_encl *encl, 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; @@ -556,7 +568,7 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, goto out; ret = sgx_init_page(encl, &encl->secs_page, - encl->base + encl->size); + encl->base + encl->size, NULL, false); if (ret) goto out; @@ -592,17 +604,17 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, goto out; } - down_read(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); vma = find_vma(current->mm, secs->base); if (!vma || vma->vm_ops != &sgx_vm_ops || vma->vm_start != secs->base || vma->vm_end != (secs->base + secs->size)) { ret = -EINVAL; - up_read(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); goto out; } vma->vm_private_data = encl; - up_read(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); mutex_lock(&sgx_tgid_ctx_mutex); list_add_tail(&encl->encl_list, &encl->tgid_ctx->encl_list); @@ -697,7 +709,7 @@ static int __encl_add_page(struct sgx_encl *encl, } } - ret = sgx_init_page(encl, encl_page, addp->addr); + ret = sgx_init_page(encl, encl_page, addp->addr, NULL, false); if (ret) { __free_page(tmp_page); return -EINVAL; @@ -930,6 +942,500 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, return ret; } +/** + * sgx_augment_encl() - 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_augment_encl(struct vm_area_struct *vma, + unsigned long addr, + bool write) +{ + struct sgx_page_info 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_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, &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_page, secs_epc_page, true); + if (ret) + goto out; + + encl->secs_page.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_page.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; + } + + 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->load_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; + + address = rg->start_addr; + end = address + rg->nr_pages * PAGE_SIZE; + + vma = sgx_find_vma(encl, address); + if (!vma) + 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->load_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, *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(encl_page, tmp, &list, load_list) { + 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(encl_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; +} + +static 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_find_and_get_encl(rg->start_addr, &encl); + if (ret) { + pr_debug("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; +} + +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 need to be invoked after that. + * @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); +} + +static 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; + + vma = sgx_find_vma(encl, address); + if (!vma) + 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->load_list); + 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; +} + +/** + * 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_find_and_get_encl(address, &encl); + if (ret) { + pr_debug("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_find_and_get_encl(address, &encl)) { + pr_debug("sgx: No enclave found at start address 0x%lx\n", + address); + return -EINVAL; + } + + ret = remove_page(encl, address, false); + if (ret) { + pr_debug("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); @@ -949,6 +1455,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 91fee13..7e22bcc 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -70,7 +70,7 @@ #include #define DRV_DESCRIPTION "Intel SGX Driver" -#define DRV_VERSION "0.10" +#define DRV_VERSION "0.11" #define ENCL_SIZE_MAX_64 (64ULL * 1024ULL * 1024ULL * 1024ULL) #define ENCL_SIZE_MAX_32 (2ULL * 1024ULL * 1024ULL * 1024ULL) diff --git a/sgx_page_cache.c b/sgx_page_cache.c index 0cb9b4e..728ad90 100644 --- a/sgx_page_cache.c +++ b/sgx_page_cache.c @@ -242,19 +242,32 @@ static void sgx_eblock(struct sgx_encl *encl, } -static void sgx_etrack(struct sgx_encl *encl) +bool sgx_etrack(struct sgx_encl *encl, unsigned int epoch) { void *epc; int ret; + bool ipi = false; + + /* If someone already called etrack in the meantime */ + if (epoch < encl->shadow_epoch) + return false; epc = sgx_get_page(encl->secs_page.epc_page); ret = __etrack(epc); sgx_put_page(epc); - - if (ret) { + encl->shadow_epoch++; + + 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)); + ipi = true; + } else if (ret) { sgx_crit(encl, "ETRACK returned %d\n", ret); sgx_invalidate(encl, true); } + + return ipi; } static int __sgx_ewb(struct sgx_encl *encl, @@ -362,7 +375,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 503f6be..d268b45 100644 --- a/sgx_user.h +++ b/sgx_user.h @@ -71,6 +71,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 @@ -92,6 +102,7 @@ #define SGX_INVALID_LICENSE 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 @@ -142,4 +153,22 @@ struct sgx_enclave_destroy { __u64 addr; } __packed; + +/* + * SGX2.0 definitions + */ + +#define SGX_GROW_UP_FLAG 1 +#define SGX_GROW_DOWN_FLAG 2 + +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 614a635..16276f9 100644 --- a/sgx_util.c +++ b/sgx_util.c @@ -145,7 +145,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) { } @@ -186,10 +186,10 @@ int sgx_find_encl(struct mm_struct *mm, unsigned long addr, return 0; } -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; @@ -253,7 +253,8 @@ static int sgx_eldu(struct sgx_encl *encl, } static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, - unsigned long addr, unsigned int flags) + unsigned long addr, unsigned int flags, + struct vm_fault *vmf) { struct sgx_encl *encl = vma->vm_private_data; struct sgx_encl_page *entry; @@ -261,6 +262,8 @@ 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. @@ -271,6 +274,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_augment_encl(vma, addr, write); + goto out; + } + + /* No entry found can not happen in 'reloading an evicted page' + * flow. + */ if (!entry) { rc = -EFAULT; goto out; @@ -371,12 +382,13 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, 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); diff --git a/sgx_vma.c b/sgx_vma.c index 4dbe26c..d76b948 100644 --- a/sgx_vma.c +++ b/sgx_vma.c @@ -75,6 +75,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. */ @@ -89,7 +95,6 @@ static void sgx_vma_close(struct vm_area_struct *vma) mutex_lock(&encl->lock); 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); } @@ -111,7 +116,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; @@ -210,7 +215,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; From 45a66bd625a3856623a9390d66cad6b85f3711b3 Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Mon, 30 Oct 2017 16:55:32 -0400 Subject: [PATCH 03/50] Add sgx2.patch to the repository. Signed-off-by: Angie Chinchilla --- inker2ext/sgx2.patch | 1031 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1031 insertions(+) create mode 100644 inker2ext/sgx2.patch diff --git a/inker2ext/sgx2.patch b/inker2ext/sgx2.patch new file mode 100644 index 0000000..767d101 --- /dev/null +++ b/inker2ext/sgx2.patch @@ -0,0 +1,1031 @@ +From 24bd0ac2c443438695de82e446833e9b0a060b6f Mon Sep 17 00:00:00 2001 +From: Angie Chinchilla +Date: Mon, 5 Jun 2017 11:08:18 -0400 +Subject: [PATCH] SGX 2.0 Implementation + +Authors: +Serge Ayoun +Angie Chinchilla +Shay Katz-zamir +Cedric Xing + +Signed-off-by: Angie Chinchilla +--- + Makefile | 2 +- + README.md | 3 +- + sgx.h | 28 ++- + sgx_arch.h | 5 +- + sgx_ioctl.c | 545 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- + sgx_main.c | 2 +- + sgx_page_cache.c | 21 ++- + sgx_user.h | 29 +++ + sgx_util.c | 28 ++- + sgx_vma.c | 11 +- + 10 files changed, 642 insertions(+), 32 deletions(-) + +diff --git a/Makefile b/Makefile +index 896d397..11f2927 100644 +--- a/Makefile ++++ b/Makefile +@@ -20,4 +20,4 @@ install: default + endif + + clean: +- rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd ++ rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd .*.o.d +diff --git a/README.md b/README.md +index a8b2b04..61946c4 100644 +--- a/README.md ++++ b/README.md +@@ -19,6 +19,7 @@ Contributing + ------- + Starting from 05/2017, we are importing the sgx driver code from the in-kernel sgx repository located at git-hub: https://github.com/jsakkine-intel/linux-sgx.git. Any contribution should be done there. Future versions of the sgx driver code will be imported later on. The motivation behind this decision is to maintain a single source code of the sgx linux driver. + An additional directory inker2ext/ has been created, it contains a script and a patch file that can be used in order to separately generate the code base of the sgx external module; it can be used in case someone wants the newest sgx driver as an external module and does not want to wait for next update. ++The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch is maintained in inker2ext/sgx2.patch in the 2.0 branch and will be periodically updated to the linux-sgx-driver:master branch. Contributions for this patch should be managed directly through the linux-sgx-driver project on Github. sgx2 will have the same behavior as linux-sgx-driver on hardware platforms that do not support SGX 2.0. + + Documentation + ------------- +@@ -31,7 +32,7 @@ Build and Install the Intel(R) SGX Driver + ### Prerequisites + - Ensure that you have the following required operating systems: + * Ubuntu* Desktop-16.04-LTS 64bits +- * Red Hat Enterprise Linux Server release 7.2 64bits ++ * Red Hat Enterprise Linux Server release 7.3 64bits + * CentOS 7.3.1611 64bits + - Ensure that you have the following required hardware: + * 6th Generation Intel(R) Core(TM) Processor (code named Skylake) +diff --git a/sgx.h b/sgx.h +index 01dcfb3..0dae86c 100644 +--- a/sgx.h ++++ b/sgx.h +@@ -69,11 +69,13 @@ + #include + #include + #include ++#include + #include "sgx_arch.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 + +@@ -99,9 +101,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 { +@@ -147,6 +161,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 { +@@ -210,11 +225,22 @@ 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); + + void sgx_encl_release(struct kref *ref); + void sgx_tgid_ctx_release(struct kref *ref); + ++void sgx_ipi_cb(void *info); ++bool sgx_etrack(struct sgx_encl *encl, unsigned int epoch); ++struct sgx_encl_page *sgx_augment_encl(struct vm_area_struct *vma, ++ unsigned long addr, ++ bool write); ++int sgx_eldu(struct sgx_encl *encl, ++ struct sgx_encl_page *encl_page, ++ struct sgx_epc_page *epc_page, ++ bool is_secs); ++ + extern struct mutex sgx_tgid_ctx_mutex; + extern struct list_head sgx_tgid_ctx_list; + extern struct task_struct *ksgxswapd_tsk; +diff --git a/sgx_arch.h b/sgx_arch.h +index 233d3a6..6d2fea9 100644 +--- a/sgx_arch.h ++++ b/sgx_arch.h +@@ -81,6 +81,7 @@ enum sgx_secinfo_flags { + SGX_SECINFO_SECS = 0x000ULL, + SGX_SECINFO_TCS = 0x100ULL, + SGX_SECINFO_REG = 0x200ULL, ++ SGX_SECINFO_TRIM = 0x400ULL, + }; + + struct sgx_secinfo { +@@ -105,7 +106,7 @@ enum isgx_secs_attributes { + GENMASK_ULL(63, 6)), + }; + +-#define SGX_SECS_RESERVED1_SIZE 28 ++#define SGX_SECS_RESERVED1_SIZE 24 + #define SGX_SECS_RESERVED2_SIZE 32 + #define SGX_SECS_RESERVED3_SIZE 96 + #define SGX_SECS_RESERVED4_SIZE 3836 +@@ -114,6 +115,7 @@ struct sgx_secs { + u64 size; + u64 base; + u32 ssaframesize; ++ u32 misc_select; + uint8_t reserved1[SGX_SECS_RESERVED1_SIZE]; + u64 flags; + u64 xfrm; +@@ -339,6 +341,7 @@ static inline int __emodt(struct sgx_secinfo *secinfo, void *epc) + return __encls_ret(EMODT, secinfo, epc, rdx); + } + ++ + struct sgx_encl; + + struct sgx_epc_page { +diff --git a/sgx_ioctl.c b/sgx_ioctl.c +index f2519a5..9cedfd3 100644 +--- a/sgx_ioctl.c ++++ b/sgx_ioctl.c +@@ -73,6 +73,8 @@ + #include + #include + ++#define SGX_NR_MOD_CHUNK_PAGES 16 ++ + struct sgx_add_page_req { + struct sgx_encl *encl; + struct sgx_encl_page *encl_page; +@@ -274,6 +276,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(&encl_page->load_list, &encl->load_list); ++ encl_page->flags |= SGX_ENCL_PAGE_ADDED; + + mutex_unlock(&encl->lock); + up_read(&encl->mm->mmap_sem); +@@ -390,7 +393,9 @@ static int sgx_validate_secs(const struct sgx_secs *secs) + + static int sgx_init_page(struct sgx_encl *encl, + struct sgx_encl_page *entry, +- unsigned long addr) ++ unsigned long addr, ++ struct sgx_epc_page **va_src, ++ bool already_locked) + { + struct sgx_va_page *va_page; + struct sgx_epc_page *epc_page = NULL; +@@ -409,10 +414,15 @@ static int sgx_init_page(struct sgx_encl *encl, + if (!va_page) + return -ENOMEM; + +- epc_page = sgx_alloc_page(0); +- 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(0); ++ if (IS_ERR(epc_page)) { ++ kfree(va_page); ++ return PTR_ERR(epc_page); ++ } + } + + vaddr = sgx_get_page(epc_page); +@@ -437,9 +447,11 @@ static int sgx_init_page(struct sgx_encl *encl, + 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; +@@ -556,7 +568,7 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, + goto out; + + ret = sgx_init_page(encl, &encl->secs_page, +- encl->base + encl->size); ++ encl->base + encl->size, NULL, false); + if (ret) + goto out; + +@@ -592,17 +604,17 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, + goto out; + } + +- down_read(¤t->mm->mmap_sem); ++ down_write(¤t->mm->mmap_sem); + vma = find_vma(current->mm, secs->base); + if (!vma || vma->vm_ops != &sgx_vm_ops || + vma->vm_start != secs->base || + vma->vm_end != (secs->base + secs->size)) { + ret = -EINVAL; +- up_read(¤t->mm->mmap_sem); ++ up_write(¤t->mm->mmap_sem); + goto out; + } + vma->vm_private_data = encl; +- up_read(¤t->mm->mmap_sem); ++ up_write(¤t->mm->mmap_sem); + + mutex_lock(&sgx_tgid_ctx_mutex); + list_add_tail(&encl->encl_list, &encl->tgid_ctx->encl_list); +@@ -697,7 +709,7 @@ static int __encl_add_page(struct sgx_encl *encl, + } + } + +- ret = sgx_init_page(encl, encl_page, addp->addr); ++ ret = sgx_init_page(encl, encl_page, addp->addr, NULL, false); + if (ret) { + __free_page(tmp_page); + return -EINVAL; +@@ -930,6 +942,500 @@ out_free_page: + return ret; + } + ++/** ++ * sgx_augment_encl() - 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_augment_encl(struct vm_area_struct *vma, ++ unsigned long addr, ++ bool write) ++{ ++ struct sgx_page_info 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_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, &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_page, secs_epc_page, true); ++ if (ret) ++ goto out; ++ ++ encl->secs_page.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_page.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; ++ } ++ ++ 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->load_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; ++ ++ address = rg->start_addr; ++ end = address + rg->nr_pages * PAGE_SIZE; ++ ++ vma = sgx_find_vma(encl, address); ++ if (!vma) ++ 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->load_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, *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(encl_page, tmp, &list, load_list) { ++ 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(encl_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; ++} ++ ++static 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_find_and_get_encl(rg->start_addr, &encl); ++ if (ret) { ++ pr_debug("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; ++} ++ ++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 need to be invoked after that. ++ * @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); ++} ++ ++static 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; ++ ++ vma = sgx_find_vma(encl, address); ++ if (!vma) ++ 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->load_list); ++ 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; ++} ++ ++/** ++ * 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_find_and_get_encl(address, &encl); ++ if (ret) { ++ pr_debug("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_find_and_get_encl(address, &encl)) { ++ pr_debug("sgx: No enclave found at start address 0x%lx\n", ++ address); ++ return -EINVAL; ++ } ++ ++ ret = remove_page(encl, address, false); ++ if (ret) { ++ pr_debug("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); + +@@ -949,6 +1455,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 91fee13..7e22bcc 100644 +--- a/sgx_main.c ++++ b/sgx_main.c +@@ -70,7 +70,7 @@ + #include + + #define DRV_DESCRIPTION "Intel SGX Driver" +-#define DRV_VERSION "0.10" ++#define DRV_VERSION "0.11" + + #define ENCL_SIZE_MAX_64 (64ULL * 1024ULL * 1024ULL * 1024ULL) + #define ENCL_SIZE_MAX_32 (2ULL * 1024ULL * 1024ULL * 1024ULL) +diff --git a/sgx_page_cache.c b/sgx_page_cache.c +index 0cb9b4e..728ad90 100644 +--- a/sgx_page_cache.c ++++ b/sgx_page_cache.c +@@ -242,19 +242,32 @@ static void sgx_eblock(struct sgx_encl *encl, + + } + +-static void sgx_etrack(struct sgx_encl *encl) ++bool sgx_etrack(struct sgx_encl *encl, unsigned int epoch) + { + void *epc; + int ret; ++ bool ipi = false; ++ ++ /* If someone already called etrack in the meantime */ ++ if (epoch < encl->shadow_epoch) ++ return false; + + epc = sgx_get_page(encl->secs_page.epc_page); + ret = __etrack(epc); + sgx_put_page(epc); +- +- if (ret) { ++ encl->shadow_epoch++; ++ ++ 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)); ++ ipi = true; ++ } else if (ret) { + sgx_crit(encl, "ETRACK returned %d\n", ret); + sgx_invalidate(encl, true); + } ++ ++ return ipi; + } + + static int __sgx_ewb(struct sgx_encl *encl, +@@ -362,7 +375,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 503f6be..d268b45 100644 +--- a/sgx_user.h ++++ b/sgx_user.h +@@ -71,6 +71,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 +@@ -92,6 +102,7 @@ + #define SGX_INVALID_LICENSE 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 +@@ -142,4 +153,22 @@ struct sgx_enclave_destroy { + __u64 addr; + } __packed; + ++ ++/* ++ * SGX2.0 definitions ++ */ ++ ++#define SGX_GROW_UP_FLAG 1 ++#define SGX_GROW_DOWN_FLAG 2 ++ ++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 614a635..16276f9 100644 +--- a/sgx_util.c ++++ b/sgx_util.c +@@ -145,7 +145,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) + { + } + +@@ -186,10 +186,10 @@ int sgx_find_encl(struct mm_struct *mm, unsigned long addr, + return 0; + } + +-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; +@@ -253,7 +253,8 @@ out: + } + + static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, +- unsigned long addr, unsigned int flags) ++ unsigned long addr, unsigned int flags, ++ struct vm_fault *vmf) + { + struct sgx_encl *encl = vma->vm_private_data; + struct sgx_encl_page *entry; +@@ -261,6 +262,8 @@ 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. +@@ -271,6 +274,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_augment_encl(vma, addr, write); ++ goto out; ++ } ++ ++ /* No entry found can not happen in 'reloading an evicted page' ++ * flow. ++ */ + if (!entry) { + rc = -EFAULT; + goto out; +@@ -371,12 +382,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); +diff --git a/sgx_vma.c b/sgx_vma.c +index 4dbe26c..d76b948 100644 +--- a/sgx_vma.c ++++ b/sgx_vma.c +@@ -75,6 +75,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. + */ +@@ -89,7 +95,6 @@ static void sgx_vma_close(struct vm_area_struct *vma) + + mutex_lock(&encl->lock); + 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); + } +@@ -111,7 +116,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; +@@ -210,7 +215,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 + From eb61a952df31e3eb5526418611ebd3fd8b1ede11 Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Mon, 30 Oct 2017 22:25:17 -0400 Subject: [PATCH 04/50] Update README Signed-off-by: Angie Chinchilla --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 61946c4..05ccbc3 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Contributing ------- Starting from 05/2017, we are importing the sgx driver code from the in-kernel sgx repository located at git-hub: https://github.com/jsakkine-intel/linux-sgx.git. Any contribution should be done there. Future versions of the sgx driver code will be imported later on. The motivation behind this decision is to maintain a single source code of the sgx linux driver. An additional directory inker2ext/ has been created, it contains a script and a patch file that can be used in order to separately generate the code base of the sgx external module; it can be used in case someone wants the newest sgx driver as an external module and does not want to wait for next update. -The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch is maintained in inker2ext/sgx2.patch in the 2.0 branch and will be periodically updated to the linux-sgx-driver:master branch. Contributions for this patch should be managed directly through the linux-sgx-driver project on Github. sgx2 will have the same behavior as linux-sgx-driver on hardware platforms that do not support SGX 2.0. +The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch is maintained in inker2ext/sgx2.patch in the 2.0 branch and will be periodically rebased to take updates from the linux-sgx-driver:master branch. Contributions for this patch should be managed directly through the linux-sgx-driver project on Github. sgx2 will have the same behavior as linux-sgx-driver on hardware platforms that do not support SGX 2.0. Documentation ------------- @@ -32,7 +32,7 @@ Build and Install the Intel(R) SGX Driver ### Prerequisites - Ensure that you have the following required operating systems: * Ubuntu* Desktop-16.04-LTS 64bits - * Red Hat Enterprise Linux Server release 7.3 64bits + * Red Hat Enterprise Linux Server release 7.4 64bits * CentOS 7.3.1611 64bits - Ensure that you have the following required hardware: * 6th Generation Intel(R) Core(TM) Processor (code named Skylake) From a7997dafe184d7d527683d8d46c4066db205758d Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Wed, 22 Nov 2017 13:53:46 -0500 Subject: [PATCH 05/50] Set sgx2 to master to rebase Set sgx2 to master:<03435d33de0bcca6c5777f23ac161249b9158f1e> for rebasing but keep the previous commit history/label. --- Makefile | 7 +- README.md | 14 +- .../internal-to-external-tree-changes.patch | 1031 ++++++++++++- inker2ext/kernel_2_extern.sh | 31 +- inker2ext/sgx2.patch | 1031 ------------- sgx.h | 106 +- sgx_arch.h | 434 +++--- sgx_asm.h | 233 +++ sgx_encl.c | 993 ++++++++++++ sgx_ioctl.c | 1336 +---------------- sgx_main.c | 243 ++- sgx_page_cache.c | 214 ++- sgx_user.h | 45 +- sgx_util.c | 169 +-- sgx_vma.c | 13 +- 15 files changed, 2780 insertions(+), 3120 deletions(-) delete mode 100644 inker2ext/sgx2.patch create mode 100644 sgx_asm.h create mode 100644 sgx_encl.c diff --git a/Makefile b/Makefile index 11f2927..4b5edaf 100644 --- a/Makefile +++ b/Makefile @@ -4,14 +4,15 @@ ifneq ($(KERNELRELEASE),) sgx_page_cache.o \ sgx_ioctl.o \ sgx_vma.o \ - sgx_util.o + sgx_util.o\ + sgx_encl.o obj-m += isgx.o else KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: - $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) CFLAGS_MODULE="-DDEBUG -g -O0" modules install: default $(MAKE) INSTALL_MOD_DIR=kernel/drivers/intel/sgx -C $(KDIR) M=$(PWD) modules_install @@ -20,4 +21,4 @@ install: default endif clean: - rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd .*.o.d + rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd diff --git a/README.md b/README.md index 05ccbc3..faa7cb6 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,13 @@ The Linux SGX software stack is comprised of the Intel(R) SGX driver, the Intel( The [linux-sgx-driver](https://github.com/01org/linux-sgx-driver) project hosts the out-of-tree driver for the Linux Intel(R) SGX software stack, which will be used until the driver upstreaming process is complete. +Within the linux-sgx-driver project, two versions of the out-of-tree driver are provided. Both versions are compatible with the linux-sgx PSW and SDK: +- SGX 2.0 Linux Driver (sgx2) + * The sgx2 branch of the linux-sgx-driver project contains the SGX 2.0 Linux Driver. This driver has additional support for SGX 2.0-based features available in upcoming CPUs. This driver has the same behavior as the SGX Linux Driver (master) on CPUs without SGX 2.0 support. +- SGX Linux Driver (master) + * The master branch of the linux-sgx-driver project tracks the proposed upstream version of the SGX driver and does not yet support SGX 2.0-based features. + + License ------- See License.txt for details. @@ -19,7 +26,8 @@ Contributing ------- Starting from 05/2017, we are importing the sgx driver code from the in-kernel sgx repository located at git-hub: https://github.com/jsakkine-intel/linux-sgx.git. Any contribution should be done there. Future versions of the sgx driver code will be imported later on. The motivation behind this decision is to maintain a single source code of the sgx linux driver. An additional directory inker2ext/ has been created, it contains a script and a patch file that can be used in order to separately generate the code base of the sgx external module; it can be used in case someone wants the newest sgx driver as an external module and does not want to wait for next update. -The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch is maintained in inker2ext/sgx2.patch in the 2.0 branch and will be periodically rebased to take updates from the linux-sgx-driver:master branch. Contributions for this patch should be managed directly through the linux-sgx-driver project on Github. sgx2 will have the same behavior as linux-sgx-driver on hardware platforms that do not support SGX 2.0. + +The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch is maintained in inker2ext/sgx2.patch in the 2.0 branch and will be periodically rebased to take updates from the linux-sgx-driver:master branch. Contributions for this patch should be managed directly through the linux-sgx-driver project on Github. Documentation ------------- @@ -32,7 +40,7 @@ Build and Install the Intel(R) SGX Driver ### Prerequisites - Ensure that you have the following required operating systems: * Ubuntu* Desktop-16.04-LTS 64bits - * Red Hat Enterprise Linux Server release 7.4 64bits + * Red Hat Enterprise Linux Server release 7.2 64bits * CentOS 7.3.1611 64bits - Ensure that you have the following required hardware: * 6th Generation Intel(R) Core(TM) Processor (code named Skylake) @@ -40,6 +48,8 @@ Build and Install the Intel(R) SGX Driver - Configure the system with the **SGX hardware enabled** option. ### Build the Intel(R) SGX Driver +**Note:** To use the SGX 2.0 driver, checkout or download the sgx2 branch and then follow the build instructions. + To build Intel(R) SGX driver, change the directory to the driver path and enter the following command: ``` $ make diff --git a/inker2ext/internal-to-external-tree-changes.patch b/inker2ext/internal-to-external-tree-changes.patch index 2ca3c12..9479548 100644 --- a/inker2ext/internal-to-external-tree-changes.patch +++ b/inker2ext/internal-to-external-tree-changes.patch @@ -1,28 +1,77 @@ -From 06bc2c551c06d45e2fe06dd54e7ebace7cbc674b Mon Sep 17 00:00:00 2001 +From 2ff2ed01f25da0e87eb7891594f32469eae1b0bc Mon Sep 17 00:00:00 2001 From: Serge Ayoun -Date: Wed, 3 May 2017 15:55:19 +0300 -Subject: [PATCH] isgx: internal to external tree changes +Date: Mon, 23 Oct 2017 17:30:10 +0300 +Subject: [PATCH] in kernel code to out of tree driver patch. -Signed-off-by: Serge Ayoun --- - drivers/platform/x86/intel_sgx/sgx.h | 5 +++-- - drivers/platform/x86/intel_sgx/sgx_ioctl.c | 6 +++++- - drivers/platform/x86/intel_sgx/sgx_main.c | 5 ++++- - drivers/platform/x86/intel_sgx/sgx_page_cache.c | 6 +++++- - drivers/platform/x86/intel_sgx/sgx_util.c | 6 +++++- - drivers/platform/x86/intel_sgx/sgx_vma.c | 11 +++++++++++ - 6 files changed, 33 insertions(+), 6 deletions(-) + drivers/platform/x86/intel_sgx/Makefile | 37 ++-- + drivers/platform/x86/intel_sgx/sgx.h | 6 +- + drivers/platform/x86/intel_sgx/sgx_arch.h | 269 ++++++++++++++++++++++++ + drivers/platform/x86/intel_sgx/sgx_asm.h | 233 ++++++++++++++++++++ + drivers/platform/x86/intel_sgx/sgx_encl.c | 13 +- + drivers/platform/x86/intel_sgx/sgx_ioctl.c | 6 +- + drivers/platform/x86/intel_sgx/sgx_main.c | 151 ++++--------- + drivers/platform/x86/intel_sgx/sgx_page_cache.c | 6 +- + drivers/platform/x86/intel_sgx/sgx_user.h | 139 ++++++++++++ + drivers/platform/x86/intel_sgx/sgx_util.c | 6 +- + drivers/platform/x86/intel_sgx/sgx_vma.c | 11 + + 11 files changed, 749 insertions(+), 128 deletions(-) + create mode 100644 drivers/platform/x86/intel_sgx/sgx_arch.h + create mode 100644 drivers/platform/x86/intel_sgx/sgx_asm.h + create mode 100644 drivers/platform/x86/intel_sgx/sgx_user.h +diff --git a/drivers/platform/x86/intel_sgx/Makefile b/drivers/platform/x86/intel_sgx/Makefile +index 92af946..4b5edaf 100644 +--- a/drivers/platform/x86/intel_sgx/Makefile ++++ b/drivers/platform/x86/intel_sgx/Makefile +@@ -1,13 +1,24 @@ +-# +-# Intel SGX +-# +- +-obj-$(CONFIG_INTEL_SGX) += intel_sgx.o +- +-intel_sgx-$(CONFIG_INTEL_SGX) += \ +- sgx_ioctl.o \ +- sgx_encl.o \ +- sgx_main.o \ +- sgx_page_cache.o \ +- sgx_util.o \ +- sgx_vma.o \ ++ifneq ($(KERNELRELEASE),) ++ isgx-y := \ ++ sgx_main.o \ ++ sgx_page_cache.o \ ++ sgx_ioctl.o \ ++ sgx_vma.o \ ++ sgx_util.o\ ++ sgx_encl.o ++ obj-m += isgx.o ++else ++KDIR := /lib/modules/$(shell uname -r)/build ++PWD := $(shell pwd) ++ ++default: ++ $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) CFLAGS_MODULE="-DDEBUG -g -O0" modules ++ ++install: default ++ $(MAKE) INSTALL_MOD_DIR=kernel/drivers/intel/sgx -C $(KDIR) M=$(PWD) modules_install ++ sh -c "cat /etc/modules | grep -Fxq isgx || echo isgx >> /etc/modules" ++ ++endif ++ ++clean: ++ rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd diff --git a/drivers/platform/x86/intel_sgx/sgx.h b/drivers/platform/x86/intel_sgx/sgx.h -index e59ff01..01dcfb3 100644 +index 24140a3..bfc24c0 100644 --- a/drivers/platform/x86/intel_sgx/sgx.h +++ b/drivers/platform/x86/intel_sgx/sgx.h -@@ -60,15 +60,16 @@ +@@ -60,15 +60,17 @@ #ifndef __ARCH_INTEL_SGX_H__ #define __ARCH_INTEL_SGX_H__ -#include -+#include "sgx_user.h" ++#include "sgx_asm.h" #include +#include #include @@ -33,11 +82,564 @@ index e59ff01..01dcfb3 100644 #include -#include +#include "sgx_arch.h" ++#include "sgx_user.h" #define SGX_EINIT_SPIN_COUNT 20 #define SGX_EINIT_SLEEP_COUNT 50 +diff --git a/drivers/platform/x86/intel_sgx/sgx_arch.h b/drivers/platform/x86/intel_sgx/sgx_arch.h +new file mode 100644 +index 0000000..dcb620e +--- /dev/null ++++ b/drivers/platform/x86/intel_sgx/sgx_arch.h +@@ -0,0 +1,269 @@ ++/* ++ * 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 ++ * 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: ++ * ++ * Jarkko Sakkinen ++ */ ++ ++#include ++#ifndef _ASM_X86_SGX_ARCH_H ++#define _ASM_X86_SGX_ARCH_H ++ ++#define SGX_SSA_GPRS_SIZE 182 ++#define SGX_SSA_MISC_EXINFO_SIZE 16 ++ ++enum sgx_misc { ++ SGX_MISC_EXINFO = 0x01, ++}; ++ ++#define SGX_MISC_RESERVED_MASK 0xFFFFFFFFFFFFFFFEL ++ ++enum sgx_attribute { ++ SGX_ATTR_DEBUG = 0x02, ++ SGX_ATTR_MODE64BIT = 0x04, ++ SGX_ATTR_PROVISIONKEY = 0x10, ++ SGX_ATTR_EINITTOKENKEY = 0x20, ++}; ++ ++#define SGX_ATTR_RESERVED_MASK 0xFFFFFFFFFFFFFFC9L ++ ++#define SGX_SECS_RESERVED1_SIZE 24 ++#define SGX_SECS_RESERVED2_SIZE 32 ++#define SGX_SECS_RESERVED3_SIZE 96 ++#define SGX_SECS_RESERVED4_SIZE 3836 ++ ++struct sgx_secs { ++ uint64_t size; ++ uint64_t base; ++ uint32_t ssaframesize; ++ uint32_t miscselect; ++ uint8_t reserved1[SGX_SECS_RESERVED1_SIZE]; ++ uint64_t attributes; ++ uint64_t xfrm; ++ uint32_t mrenclave[8]; ++ uint8_t reserved2[SGX_SECS_RESERVED2_SIZE]; ++ uint32_t mrsigner[8]; ++ uint8_t reserved3[SGX_SECS_RESERVED3_SIZE]; ++ uint16_t isvvprodid; ++ uint16_t isvsvn; ++ uint8_t reserved4[SGX_SECS_RESERVED4_SIZE]; ++}; ++ ++enum sgx_tcs_flags { ++ SGX_TCS_DBGOPTIN = 0x01, /* cleared on EADD */ ++}; ++ ++#define SGX_TCS_RESERVED_MASK 0xFFFFFFFFFFFFFFFEL ++ ++struct sgx_tcs { ++ uint64_t state; ++ uint64_t flags; ++ uint64_t ossa; ++ uint32_t cssa; ++ uint32_t nssa; ++ uint64_t oentry; ++ uint64_t aep; ++ uint64_t ofsbase; ++ uint64_t ogsbase; ++ uint32_t fslimit; ++ uint32_t gslimit; ++ uint64_t reserved[503]; ++}; ++ ++struct sgx_pageinfo { ++ uint64_t linaddr; ++ uint64_t srcpge; ++ union { ++ uint64_t secinfo; ++ uint64_t pcmd; ++ }; ++ uint64_t secs; ++} __attribute__((aligned(32))); ++ ++ ++#define SGX_SECINFO_PERMISSION_MASK 0x0000000000000007L ++#define SGX_SECINFO_PAGE_TYPE_MASK 0x000000000000FF00L ++#define SGX_SECINFO_RESERVED_MASK 0xFFFFFFFFFFFF00F8L ++ ++enum sgx_page_type { ++ SGX_PAGE_TYPE_SECS = 0x00, ++ SGX_PAGE_TYPE_TCS = 0x01, ++ SGX_PAGE_TYPE_REG = 0x02, ++ SGX_PAGE_TYPE_VA = 0x03, ++}; ++ ++enum sgx_secinfo_flags { ++ SGX_SECINFO_R = 0x01, ++ SGX_SECINFO_W = 0x02, ++ SGX_SECINFO_X = 0x04, ++ SGX_SECINFO_SECS = (SGX_PAGE_TYPE_SECS << 8), ++ SGX_SECINFO_TCS = (SGX_PAGE_TYPE_TCS << 8), ++ SGX_SECINFO_REG = (SGX_PAGE_TYPE_REG << 8), ++}; ++ ++struct sgx_secinfo { ++ uint64_t flags; ++ uint64_t reserved[7]; ++} __attribute__((aligned(64))); ++ ++struct sgx_pcmd { ++ struct sgx_secinfo secinfo; ++ uint64_t enclave_id; ++ uint8_t reserved[40]; ++ uint8_t mac[16]; ++}; ++ ++#define SGX_MODULUS_SIZE 384 ++ ++struct sgx_sigstruct_header { ++ uint64_t header1[2]; ++ uint32_t vendor; ++ uint32_t date; ++ uint64_t header2[2]; ++ uint32_t swdefined; ++ uint8_t reserved1[84]; ++}; ++ ++struct sgx_sigstruct_body { ++ uint32_t miscselect; ++ uint32_t miscmask; ++ uint8_t reserved2[20]; ++ uint64_t attributes; ++ uint64_t xfrm; ++ uint8_t attributemask[16]; ++ uint8_t mrenclave[32]; ++ uint8_t reserved3[32]; ++ uint16_t isvprodid; ++ uint16_t isvsvn; ++} __attribute__((__packed__)); ++ ++struct sgx_sigstruct { ++ struct sgx_sigstruct_header header; ++ uint8_t modulus[SGX_MODULUS_SIZE]; ++ uint32_t exponent; ++ uint8_t signature[SGX_MODULUS_SIZE]; ++ struct sgx_sigstruct_body body; ++ uint8_t reserved4[12]; ++ uint8_t q1[SGX_MODULUS_SIZE]; ++ uint8_t q2[SGX_MODULUS_SIZE]; ++}; ++ ++struct sgx_sigstruct_payload { ++ struct sgx_sigstruct_header header; ++ struct sgx_sigstruct_body body; ++}; ++ ++struct sgx_einittoken_payload { ++ uint32_t valid; ++ uint32_t reserved1[11]; ++ uint64_t attributes; ++ uint64_t xfrm; ++ uint8_t mrenclave[32]; ++ uint8_t reserved2[32]; ++ uint8_t mrsigner[32]; ++ uint8_t reserved3[32]; ++}; ++ ++struct sgx_einittoken { ++ struct sgx_einittoken_payload payload; ++ uint8_t cpusvnle[16]; ++ uint16_t isvprodidle; ++ uint16_t isvsvnle; ++ uint8_t reserved2[24]; ++ uint32_t maskedmiscselectle; ++ uint64_t maskedattributesle; ++ uint64_t maskedxfrmle; ++ uint8_t keyid[32]; ++ uint8_t mac[16]; ++}; ++ ++struct sgx_report { ++ uint8_t cpusvn[16]; ++ uint32_t miscselect; ++ uint8_t reserved1[28]; ++ uint64_t attributes; ++ uint64_t xfrm; ++ uint8_t mrenclave[32]; ++ uint8_t reserved2[32]; ++ uint8_t mrsigner[32]; ++ uint8_t reserved3[96]; ++ uint16_t isvprodid; ++ uint16_t isvsvn; ++ uint8_t reserved4[60]; ++ uint8_t reportdata[64]; ++ uint8_t keyid[32]; ++ uint8_t mac[16]; ++}; ++ ++struct sgx_targetinfo { ++ uint8_t mrenclave[32]; ++ uint64_t attributes; ++ uint64_t xfrm; ++ uint8_t reserved1[4]; ++ uint32_t miscselect; ++ uint8_t reserved2[456]; ++}; ++ ++struct sgx_keyrequest { ++ uint16_t keyname; ++ uint16_t keypolicy; ++ uint16_t isvsvn; ++ uint16_t reserved1; ++ uint8_t cpusvn[16]; ++ uint64_t attributemask; ++ uint64_t xfrmmask; ++ uint8_t keyid[32]; ++ uint32_t miscmask; ++ uint8_t reserved2[436]; ++}; ++ ++#endif /* _ASM_X86_SGX_ARCH_H */ +diff --git a/drivers/platform/x86/intel_sgx/sgx_asm.h b/drivers/platform/x86/intel_sgx/sgx_asm.h +new file mode 100644 +index 0000000..b786f34 +--- /dev/null ++++ b/drivers/platform/x86/intel_sgx/sgx_asm.h +@@ -0,0 +1,233 @@ ++/* ++ * 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 ++ * 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: ++ * ++ * Jarkko Sakkinen ++ * Suresh Siddha ++ */ ++ ++#ifndef _ASM_X86_SGX_H ++#define _ASM_X86_SGX_H ++ ++#include "sgx_arch.h" ++#include ++#include ++#include ++#include ++ ++#define SGX_CPUID 0x12 ++ ++enum sgx_cpuid { ++ SGX_CPUID_CAPABILITIES = 0, ++ SGX_CPUID_ATTRIBUTES = 1, ++ SGX_CPUID_EPC_BANKS = 2, ++}; ++ ++enum sgx_commands { ++ ECREATE = 0x0, ++ EADD = 0x1, ++ EINIT = 0x2, ++ EREMOVE = 0x3, ++ EDGBRD = 0x4, ++ EDGBWR = 0x5, ++ EEXTEND = 0x6, ++ ELDU = 0x8, ++ EBLOCK = 0x9, ++ EPA = 0xA, ++ EWB = 0xB, ++ ETRACK = 0xC, ++ EAUG = 0xD, ++ EMODPR = 0xE, ++ EMODT = 0xF, ++}; ++ ++#ifdef CONFIG_X86_64 ++#define XAX "%%rax" ++#else ++#define XAX "%%eax" ++#endif ++ ++#define __encls_ret(rax, rbx, rcx, rdx) \ ++ ({ \ ++ int ret; \ ++ asm volatile( \ ++ "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ ++ "2:\n" \ ++ ".section .fixup,\"ax\"\n" \ ++ "3: mov $-14,"XAX"\n" \ ++ " jmp 2b\n" \ ++ ".previous\n" \ ++ _ASM_EXTABLE(1b, 3b) \ ++ : "=a"(ret) \ ++ : "a"(rax), "b"(rbx), "c"(rcx), "d"(rdx) \ ++ : "memory"); \ ++ ret; \ ++ }) ++ ++#define __encls(rax, rbx, rcx, rdx...) \ ++ ({ \ ++ int ret; \ ++ asm volatile( \ ++ "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ ++ " xor "XAX","XAX"\n" \ ++ "2:\n" \ ++ ".section .fixup,\"ax\"\n" \ ++ "3: mov $-14,"XAX"\n" \ ++ " jmp 2b\n" \ ++ ".previous\n" \ ++ _ASM_EXTABLE(1b, 3b) \ ++ : "=a"(ret), "=b"(rbx), "=c"(rcx) \ ++ : "a"(rax), "b"(rbx), "c"(rcx), rdx \ ++ : "memory"); \ ++ ret; \ ++ }) ++ ++static inline unsigned long __ecreate(struct sgx_pageinfo *pginfo, void *secs) ++{ ++ return __encls(ECREATE, pginfo, secs, "d"(0)); ++} ++ ++static inline int __eextend(void *secs, void *epc) ++{ ++ return __encls(EEXTEND, secs, epc, "d"(0)); ++} ++ ++static inline int __eadd(struct sgx_pageinfo *pginfo, void *epc) ++{ ++ return __encls(EADD, pginfo, epc, "d"(0)); ++} ++ ++static inline int __einit(void *sigstruct, struct sgx_einittoken *einittoken, ++ void *secs) ++{ ++ return __encls_ret(EINIT, sigstruct, secs, einittoken); ++} ++ ++static inline int __eremove(void *epc) ++{ ++ unsigned long rbx = 0; ++ unsigned long rdx = 0; ++ ++ return __encls_ret(EREMOVE, rbx, epc, rdx); ++} ++ ++static inline int __edbgwr(void *epc, unsigned long *data) ++{ ++ return __encls(EDGBWR, *data, epc, "d"(0)); ++} ++ ++static inline int __edbgrd(void *epc, unsigned long *data) ++{ ++ unsigned long rbx = 0; ++ int ret; ++ ++ ret = __encls(EDGBRD, rbx, epc, "d"(0)); ++ if (!ret) ++ *(unsigned long *) data = rbx; ++ ++ return ret; ++} ++ ++static inline int __etrack(void *epc) ++{ ++ unsigned long rbx = 0; ++ unsigned long rdx = 0; ++ ++ return __encls_ret(ETRACK, rbx, epc, rdx); ++} ++ ++static inline int __eldu(unsigned long rbx, unsigned long rcx, ++ unsigned long rdx) ++{ ++ return __encls_ret(ELDU, rbx, rcx, rdx); ++} ++ ++static inline int __eblock(unsigned long rcx) ++{ ++ unsigned long rbx = 0; ++ unsigned long rdx = 0; ++ ++ return __encls_ret(EBLOCK, rbx, rcx, rdx); ++} ++ ++static inline int __epa(void *epc) ++{ ++ unsigned long rbx = SGX_PAGE_TYPE_VA; ++ ++ return __encls(EPA, rbx, epc, "d"(0)); ++} ++ ++static inline int __ewb(struct sgx_pageinfo *pginfo, void *epc, void *va) ++{ ++ return __encls_ret(EWB, pginfo, epc, va); ++} ++ ++static inline int __eaug(struct sgx_pageinfo *pginfo, void *epc) ++{ ++ return __encls(EAUG, pginfo, epc, "d"(0)); ++} ++ ++static inline int __emodpr(struct sgx_secinfo *secinfo, void *epc) ++{ ++ unsigned long rdx = 0; ++ ++ return __encls_ret(EMODPR, secinfo, epc, rdx); ++} ++ ++static inline int __emodt(struct sgx_secinfo *secinfo, void *epc) ++{ ++ unsigned long rdx = 0; ++ ++ return __encls_ret(EMODT, secinfo, epc, rdx); ++} ++ ++#endif /* _ASM_X86_SGX_H */ +diff --git a/drivers/platform/x86/intel_sgx/sgx_encl.c b/drivers/platform/x86/intel_sgx/sgx_encl.c +index 6f69126..2669509 100644 +--- a/drivers/platform/x86/intel_sgx/sgx_encl.c ++++ b/drivers/platform/x86/intel_sgx/sgx_encl.c +@@ -64,7 +64,12 @@ + #include + #include + #include +-#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) ++ #include ++#else ++ #include ++#endif ++#include "linux/file.h" + #include + #include + #include +@@ -576,7 +581,7 @@ int sgx_encl_create(struct sgx_secs *secs) + long ret; + + encl = sgx_encl_alloc(secs); +- if (IS_ERR(secs)) ++ if (IS_ERR(encl)) + return PTR_ERR(encl); + + secs_epc = sgx_alloc_page(0); +@@ -634,8 +639,8 @@ int sgx_encl_create(struct sgx_secs *secs) + } + + if (vma->vm_start != secs->base || +- vma->vm_end != (secs->base + secs->size) || +- vma->vm_pgoff != 0) { ++ vma->vm_end != (secs->base + secs->size) ++ /* vma->vm_pgoff != 0 */) { + ret = -EINVAL; + up_read(¤t->mm->mmap_sem); + goto out; diff --git a/drivers/platform/x86/intel_sgx/sgx_ioctl.c b/drivers/platform/x86/intel_sgx/sgx_ioctl.c -index ba7c0d2..e1db58c 100644 +index af8b6b6..f7540fc 100644 --- a/drivers/platform/x86/intel_sgx/sgx_ioctl.c +++ b/drivers/platform/x86/intel_sgx/sgx_ioctl.c @@ -64,7 +64,11 @@ @@ -45,7 +647,7 @@ index ba7c0d2..e1db58c 100644 #include #include -#include -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) + #include +#else + #include @@ -54,30 +656,248 @@ index ba7c0d2..e1db58c 100644 #include #include diff --git a/drivers/platform/x86/intel_sgx/sgx_main.c b/drivers/platform/x86/intel_sgx/sgx_main.c -index 5890643..70b95c1 100644 +index dc50410..7ff3864 100644 --- a/drivers/platform/x86/intel_sgx/sgx_main.c +++ b/drivers/platform/x86/intel_sgx/sgx_main.c -@@ -78,6 +78,9 @@ +@@ -58,16 +58,17 @@ + * Sean Christopherson + */ + ++#include "asm/msr-index.h" + #include "sgx.h" + #include + #include + #include ++#include + #include + #include + #include + #include + #include +-#include + + #define DRV_DESCRIPTION "Intel SGX Driver" + #define DRV_VERSION "0.10" +@@ -75,6 +76,11 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR("Jarkko Sakkinen "); MODULE_VERSION(DRV_VERSION); +#ifndef X86_FEATURE_SGX -+#define X86_FEATURE_SGX (9 * 32 + 2) ++ #define X86_FEATURE_SGX (9 * 32 + 2) +#endif ++ ++#define FEATURE_CONTROL_SGX_ENABLE (1<<18) /* * Global data. -@@ -156,7 +159,7 @@ static unsigned long sgx_get_unmapped_area(struct file *file, +@@ -152,6 +158,13 @@ static const struct file_operations sgx_fops = { + .get_unmapped_area = sgx_get_unmapped_area, }; - static struct miscdevice sgx_dev = { -- .name = "sgx", ++static struct miscdevice sgx_dev = { ++ .minor = MISC_DYNAMIC_MINOR, + .name = "isgx", - .fops = &sgx_fops, - .mode = 0666, ++ .fops = &sgx_fops, ++ .mode = 0666, ++}; ++ + static int sgx_pm_suspend(struct device *dev) + { + struct sgx_tgid_ctx *ctx; +@@ -170,71 +183,8 @@ static int sgx_pm_suspend(struct device *dev) + + static SIMPLE_DEV_PM_OPS(sgx_drv_pm, sgx_pm_suspend, NULL); + +-static struct bus_type sgx_bus_type = { +- .name = "sgx", +-}; +- +-struct sgx_context { +- struct device dev; +- struct cdev cdev; +-}; +- +-static dev_t sgx_devt; +- +-static void sgx_dev_release(struct device *dev) +-{ +- struct sgx_context *ctx = container_of(dev, struct sgx_context, dev); +- +- kfree(ctx); +-} +- +-static struct sgx_context *sgx_ctx_alloc(struct device *parent) +-{ +- struct sgx_context *ctx; +- +- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); +- if (!ctx) +- return ERR_PTR(-ENOMEM); +- +- device_initialize(&ctx->dev); +- +- ctx->dev.bus = &sgx_bus_type; +- ctx->dev.parent = parent; +- ctx->dev.devt = MKDEV(MAJOR(sgx_devt), 0); +- ctx->dev.release = sgx_dev_release; +- +- dev_set_name(&ctx->dev, "sgx"); +- +- cdev_init(&ctx->cdev, &sgx_fops); +- ctx->cdev.owner = THIS_MODULE; +- +- dev_set_drvdata(parent, ctx); +- +- return ctx; +-} +- +-static struct sgx_context *sgxm_ctx_alloc(struct device *parent) +-{ +- struct sgx_context *ctx; +- int rc; +- +- ctx = sgx_ctx_alloc(parent); +- if (IS_ERR(ctx)) +- return ctx; +- +- rc = devm_add_action_or_reset(parent, (void (*)(void *))put_device, +- &ctx->dev); +- if (rc) { +- kfree(ctx); +- return ERR_PTR(rc); +- } +- +- return ctx; +-} +- + static int sgx_dev_init(struct device *parent) + { +- struct sgx_context *sgx_dev; + unsigned int eax, ebx, ecx, edx; + unsigned long pa; + unsigned long size; +@@ -243,8 +193,6 @@ static int sgx_dev_init(struct device *parent) + + pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n"); + +- sgx_dev = sgxm_ctx_alloc(parent); +- + cpuid_count(SGX_CPUID, SGX_CPUID_CAPABILITIES, &eax, &ebx, &ecx, &edx); + /* Only allow misc bits supported by the driver. */ + sgx_misc_reserved = ~ebx | SGX_MISC_RESERVED_MASK; +@@ -313,7 +261,13 @@ static int sgx_dev_init(struct device *parent) + goto out_iounmap; + } + +- ret = cdev_device_add(&sgx_dev->cdev, &sgx_dev->dev); ++ sgx_dev.parent = parent; ++ ret = misc_register(&sgx_dev); ++ if (ret) { ++ pr_err("intel_sgx: misc_register() failed\n"); ++ goto out_workqueue; ++ } ++ + if (ret) + goto out_workqueue; + +@@ -328,10 +282,16 @@ static int sgx_dev_init(struct device *parent) + return ret; + } + ++static atomic_t sgx_init_flag = ATOMIC_INIT(0); + static int sgx_drv_probe(struct platform_device *pdev) + { + unsigned int eax, ebx, ecx, edx; + unsigned long fc; ++ if (atomic_cmpxchg(&sgx_init_flag, 0, 1)) { ++ pr_warn("intel_sgx: second initialization call skipped\n"); ++ return 0; ++ } ++ + + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return -ENODEV; +@@ -370,11 +330,14 @@ static int sgx_drv_probe(struct platform_device *pdev) + + static int sgx_drv_remove(struct platform_device *pdev) + { +- struct device *parent = &pdev->dev; +- struct sgx_context *ctx = dev_get_drvdata(parent); + int i; + +- cdev_device_del(&ctx->cdev, &ctx->dev); ++ if (!atomic_cmpxchg(&sgx_init_flag, 1, 0)) { ++ pr_warn("intel_sgx: second release call skipped\n"); ++ return 0; ++ } ++ ++ misc_deregister(&sgx_dev); + + destroy_workqueue(sgx_add_page_wq); + #ifdef CONFIG_X86_64 +@@ -404,48 +367,24 @@ static struct platform_driver sgx_drv = { + }, }; + +-static int __init sgx_drv_subsys_init(void) ++static struct platform_device *pdev; ++int init_sgx_module(void) + { +- int ret; +- +- ret = bus_register(&sgx_bus_type); +- if (ret) +- return ret; +- +- ret = alloc_chrdev_region(&sgx_devt, 0, 1, "sgx"); +- if (ret < 0) { +- bus_unregister(&sgx_bus_type); +- return ret; +- } +- ++ platform_driver_register(&sgx_drv); ++ pdev = platform_device_register_simple("intel_sgx", 0, NULL, 0); ++ if (IS_ERR(pdev)) ++ pr_err("platform_device_register_simple failed\n"); + return 0; + } + +-static void sgx_drv_subsys_exit(void) +-{ +- bus_unregister(&sgx_bus_type); +- unregister_chrdev_region(sgx_devt, 1); +-} +- +-static int __init sgx_drv_init(void) +-{ +- int ret; +- +- ret = sgx_drv_subsys_init(); +- +- ret = platform_driver_register(&sgx_drv); +- if (ret) +- sgx_drv_subsys_exit(); +- +- return ret; +-} +-module_init(sgx_drv_init); +- +-static void __exit sgx_drv_exit(void) ++void cleanup_sgx_module(void) + { ++ dev_set_uevent_suppress(&pdev->dev, true); ++ platform_device_unregister(pdev); + platform_driver_unregister(&sgx_drv); +- sgx_drv_subsys_exit(); + } +-module_exit(sgx_drv_exit); ++ ++module_init(init_sgx_module); ++module_exit(cleanup_sgx_module); + + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/platform/x86/intel_sgx/sgx_page_cache.c b/drivers/platform/x86/intel_sgx/sgx_page_cache.c -index 59a67cb..0cb9b4e 100644 +index f8883d2..8472037 100644 --- a/drivers/platform/x86/intel_sgx/sgx_page_cache.c +++ b/drivers/platform/x86/intel_sgx/sgx_page_cache.c @@ -63,7 +63,11 @@ @@ -85,7 +905,7 @@ index 59a67cb..0cb9b4e 100644 #include #include -#include -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) + #include +#else + #include @@ -93,8 +913,153 @@ index 59a67cb..0cb9b4e 100644 #include #define SGX_NR_LOW_EPC_PAGES_DEFAULT 32 +diff --git a/drivers/platform/x86/intel_sgx/sgx_user.h b/drivers/platform/x86/intel_sgx/sgx_user.h +new file mode 100644 +index 0000000..a15f87b +--- /dev/null ++++ b/drivers/platform/x86/intel_sgx/sgx_user.h +@@ -0,0 +1,139 @@ ++/* ++ * 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 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 ++ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2016 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: ++ * ++ * Jarkko Sakkinen ++ * Suresh Siddha ++ */ ++ ++#ifndef _UAPI_ASM_X86_SGX_H ++#define _UAPI_ASM_X86_SGX_H ++ ++#include ++#include ++ ++#define SGX_MAGIC 0xA4 ++ ++#define SGX_IOC_ENCLAVE_CREATE \ ++ _IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create) ++#define SGX_IOC_ENCLAVE_ADD_PAGE \ ++ _IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page) ++#define SGX_IOC_ENCLAVE_INIT \ ++ _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) ++ ++/* SGX leaf instruction return values */ ++#define SGX_SUCCESS 0 ++#define SGX_INVALID_SIG_STRUCT 1 ++#define SGX_INVALID_ATTRIBUTE 2 ++#define SGX_BLKSTATE 3 ++#define SGX_INVALID_MEASUREMENT 4 ++#define SGX_NOTBLOCKABLE 5 ++#define SGX_PG_INVLD 6 ++#define SGX_LOCKFAIL 7 ++#define SGX_INVALID_SIGNATURE 8 ++#define SGX_MAC_COMPARE_FAIL 9 ++#define SGX_PAGE_NOT_BLOCKED 10 ++#define SGX_NOT_TRACKED 11 ++#define SGX_VA_SLOT_OCCUPIED 12 ++#define SGX_CHILD_PRESENT 13 ++#define SGX_ENCLAVE_ACT 14 ++#define SGX_ENTRYEPOCH_LOCKED 15 ++#define SGX_INVALID_EINITTOKEN 16 ++#define SGX_PREV_TRK_INCMPL 17 ++#define SGX_PG_IS_SECS 18 ++#define SGX_INVALID_CPUSVN 32 ++#define SGX_INVALID_ISVSVN 64 ++#define SGX_UNMASKED_EVENT 128 ++#define SGX_INVALID_KEYNAME 256 ++ ++/* IOCTL return values */ ++#define SGX_POWER_LOST_ENCLAVE 0x40000000 ++#define SGX_LE_ROLLBACK 0x40000001 ++ ++/** ++ * struct sgx_enclave_create - parameter structure for the ++ * %SGX_IOC_ENCLAVE_CREATE ioctl ++ * @src: address for the SECS page data ++ */ ++struct sgx_enclave_create { ++ __u64 src; ++} __attribute__((__packed__)); ++ ++/** ++ * struct sgx_enclave_add_page - parameter structure for the ++ * %SGX_IOC_ENCLAVE_ADD_PAGE ioctl ++ * @addr: address in the ELRANGE ++ * @src: address for the page data ++ * @secinfo: address for the SECINFO data ++ * @mrmask: bitmask for the 256 byte chunks that are to be measured ++ */ ++struct sgx_enclave_add_page { ++ __u64 addr; ++ __u64 src; ++ __u64 secinfo; ++ __u16 mrmask; ++} __attribute__((__packed__)); ++ ++/** ++ * struct sgx_enclave_init - parameter structure for the ++ * %SGX_IOC_ENCLAVE_INIT ioctl ++ * @addr: address in the ELRANGE ++ * @sigstruct: address for the page data ++ * @einittoken: EINITTOKEN ++ */ ++struct sgx_enclave_init { ++ __u64 addr; ++ __u64 sigstruct; ++ __u64 einittoken; ++} __attribute__((__packed__)); ++ ++#endif /* _UAPI_ASM_X86_SGX_H */ diff --git a/drivers/platform/x86/intel_sgx/sgx_util.c b/drivers/platform/x86/intel_sgx/sgx_util.c -index 1e9fa18..4226f2a 100644 +index 6ef7949..ff0e40a 100644 --- a/drivers/platform/x86/intel_sgx/sgx_util.c +++ b/drivers/platform/x86/intel_sgx/sgx_util.c @@ -61,7 +61,11 @@ @@ -102,19 +1067,19 @@ index 1e9fa18..4226f2a 100644 #include #include -#include -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) -+ #include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) ++ #include +#else -+ #include ++ #include +#endif struct page *sgx_get_backing(struct sgx_encl *encl, struct sgx_encl_page *entry, diff --git a/drivers/platform/x86/intel_sgx/sgx_vma.c b/drivers/platform/x86/intel_sgx/sgx_vma.c -index f83c0b8..4dbe26c 100644 +index 54b588f..dae9eb9 100644 --- a/drivers/platform/x86/intel_sgx/sgx_vma.c +++ b/drivers/platform/x86/intel_sgx/sgx_vma.c -@@ -94,10 +94,21 @@ static void sgx_vma_close(struct vm_area_struct *vma) +@@ -96,10 +96,21 @@ static void sgx_vma_close(struct vm_area_struct *vma) kref_put(&encl->refcount, sgx_encl_release); } @@ -137,5 +1102,5 @@ index f83c0b8..4dbe26c 100644 entry = sgx_fault_page(vma, addr, 0); -- -1.9.1 +2.7.4 diff --git a/inker2ext/kernel_2_extern.sh b/inker2ext/kernel_2_extern.sh index 4a47332..869c813 100755 --- a/inker2ext/kernel_2_extern.sh +++ b/inker2ext/kernel_2_extern.sh @@ -1,27 +1,26 @@ #! /bin/bash -# Should run within git-hub sgx driver directory: +# Should be run from git-hub sgx driver root directory. +# Assumes in kernel sgx master branch code repo has been cloned +# # Usage: -# kernel_2_extern +# kernel_2_extern pa=`pwd` -file="$1/arch/x86/include/asm/sgx.h" -if [ ! -f $file ]; then - echo "Missing file $file" - exit -fi -cp $file sgx_arch.h +patchfile="$pa/inker2ext/internal-to-external-tree-changes.patch" -file="$1/arch/x86/include/uapi/asm/sgx.h" -if [ ! -f $file ]; then - echo "Missing file $file" - exit -fi -cp $file sgx_user.h +if [ ! -f $file ]; then + echo "Missing patch file: $file" + echo "You should run the script from the out of tree driver repository root directory" + exit +fi cd $1 -git apply $pa/$2 +git apply $patchfile + +cp *.c $pa +cp *.h $pa +cp Makefile $pa cd $pa -cp $1/drivers/platform/x86/intel_sgx/sgx* . diff --git a/inker2ext/sgx2.patch b/inker2ext/sgx2.patch deleted file mode 100644 index 767d101..0000000 --- a/inker2ext/sgx2.patch +++ /dev/null @@ -1,1031 +0,0 @@ -From 24bd0ac2c443438695de82e446833e9b0a060b6f Mon Sep 17 00:00:00 2001 -From: Angie Chinchilla -Date: Mon, 5 Jun 2017 11:08:18 -0400 -Subject: [PATCH] SGX 2.0 Implementation - -Authors: -Serge Ayoun -Angie Chinchilla -Shay Katz-zamir -Cedric Xing - -Signed-off-by: Angie Chinchilla ---- - Makefile | 2 +- - README.md | 3 +- - sgx.h | 28 ++- - sgx_arch.h | 5 +- - sgx_ioctl.c | 545 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- - sgx_main.c | 2 +- - sgx_page_cache.c | 21 ++- - sgx_user.h | 29 +++ - sgx_util.c | 28 ++- - sgx_vma.c | 11 +- - 10 files changed, 642 insertions(+), 32 deletions(-) - -diff --git a/Makefile b/Makefile -index 896d397..11f2927 100644 ---- a/Makefile -+++ b/Makefile -@@ -20,4 +20,4 @@ install: default - endif - - clean: -- rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd -+ rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd .*.o.d -diff --git a/README.md b/README.md -index a8b2b04..61946c4 100644 ---- a/README.md -+++ b/README.md -@@ -19,6 +19,7 @@ Contributing - ------- - Starting from 05/2017, we are importing the sgx driver code from the in-kernel sgx repository located at git-hub: https://github.com/jsakkine-intel/linux-sgx.git. Any contribution should be done there. Future versions of the sgx driver code will be imported later on. The motivation behind this decision is to maintain a single source code of the sgx linux driver. - An additional directory inker2ext/ has been created, it contains a script and a patch file that can be used in order to separately generate the code base of the sgx external module; it can be used in case someone wants the newest sgx driver as an external module and does not want to wait for next update. -+The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch is maintained in inker2ext/sgx2.patch in the 2.0 branch and will be periodically updated to the linux-sgx-driver:master branch. Contributions for this patch should be managed directly through the linux-sgx-driver project on Github. sgx2 will have the same behavior as linux-sgx-driver on hardware platforms that do not support SGX 2.0. - - Documentation - ------------- -@@ -31,7 +32,7 @@ Build and Install the Intel(R) SGX Driver - ### Prerequisites - - Ensure that you have the following required operating systems: - * Ubuntu* Desktop-16.04-LTS 64bits -- * Red Hat Enterprise Linux Server release 7.2 64bits -+ * Red Hat Enterprise Linux Server release 7.3 64bits - * CentOS 7.3.1611 64bits - - Ensure that you have the following required hardware: - * 6th Generation Intel(R) Core(TM) Processor (code named Skylake) -diff --git a/sgx.h b/sgx.h -index 01dcfb3..0dae86c 100644 ---- a/sgx.h -+++ b/sgx.h -@@ -69,11 +69,13 @@ - #include - #include - #include -+#include - #include "sgx_arch.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 - -@@ -99,9 +101,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 { -@@ -147,6 +161,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 { -@@ -210,11 +225,22 @@ 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); - - void sgx_encl_release(struct kref *ref); - void sgx_tgid_ctx_release(struct kref *ref); - -+void sgx_ipi_cb(void *info); -+bool sgx_etrack(struct sgx_encl *encl, unsigned int epoch); -+struct sgx_encl_page *sgx_augment_encl(struct vm_area_struct *vma, -+ unsigned long addr, -+ bool write); -+int sgx_eldu(struct sgx_encl *encl, -+ struct sgx_encl_page *encl_page, -+ struct sgx_epc_page *epc_page, -+ bool is_secs); -+ - extern struct mutex sgx_tgid_ctx_mutex; - extern struct list_head sgx_tgid_ctx_list; - extern struct task_struct *ksgxswapd_tsk; -diff --git a/sgx_arch.h b/sgx_arch.h -index 233d3a6..6d2fea9 100644 ---- a/sgx_arch.h -+++ b/sgx_arch.h -@@ -81,6 +81,7 @@ enum sgx_secinfo_flags { - SGX_SECINFO_SECS = 0x000ULL, - SGX_SECINFO_TCS = 0x100ULL, - SGX_SECINFO_REG = 0x200ULL, -+ SGX_SECINFO_TRIM = 0x400ULL, - }; - - struct sgx_secinfo { -@@ -105,7 +106,7 @@ enum isgx_secs_attributes { - GENMASK_ULL(63, 6)), - }; - --#define SGX_SECS_RESERVED1_SIZE 28 -+#define SGX_SECS_RESERVED1_SIZE 24 - #define SGX_SECS_RESERVED2_SIZE 32 - #define SGX_SECS_RESERVED3_SIZE 96 - #define SGX_SECS_RESERVED4_SIZE 3836 -@@ -114,6 +115,7 @@ struct sgx_secs { - u64 size; - u64 base; - u32 ssaframesize; -+ u32 misc_select; - uint8_t reserved1[SGX_SECS_RESERVED1_SIZE]; - u64 flags; - u64 xfrm; -@@ -339,6 +341,7 @@ static inline int __emodt(struct sgx_secinfo *secinfo, void *epc) - return __encls_ret(EMODT, secinfo, epc, rdx); - } - -+ - struct sgx_encl; - - struct sgx_epc_page { -diff --git a/sgx_ioctl.c b/sgx_ioctl.c -index f2519a5..9cedfd3 100644 ---- a/sgx_ioctl.c -+++ b/sgx_ioctl.c -@@ -73,6 +73,8 @@ - #include - #include - -+#define SGX_NR_MOD_CHUNK_PAGES 16 -+ - struct sgx_add_page_req { - struct sgx_encl *encl; - struct sgx_encl_page *encl_page; -@@ -274,6 +276,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(&encl_page->load_list, &encl->load_list); -+ encl_page->flags |= SGX_ENCL_PAGE_ADDED; - - mutex_unlock(&encl->lock); - up_read(&encl->mm->mmap_sem); -@@ -390,7 +393,9 @@ static int sgx_validate_secs(const struct sgx_secs *secs) - - static int sgx_init_page(struct sgx_encl *encl, - struct sgx_encl_page *entry, -- unsigned long addr) -+ unsigned long addr, -+ struct sgx_epc_page **va_src, -+ bool already_locked) - { - struct sgx_va_page *va_page; - struct sgx_epc_page *epc_page = NULL; -@@ -409,10 +414,15 @@ static int sgx_init_page(struct sgx_encl *encl, - if (!va_page) - return -ENOMEM; - -- epc_page = sgx_alloc_page(0); -- 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(0); -+ if (IS_ERR(epc_page)) { -+ kfree(va_page); -+ return PTR_ERR(epc_page); -+ } - } - - vaddr = sgx_get_page(epc_page); -@@ -437,9 +447,11 @@ static int sgx_init_page(struct sgx_encl *encl, - 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; -@@ -556,7 +568,7 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, - goto out; - - ret = sgx_init_page(encl, &encl->secs_page, -- encl->base + encl->size); -+ encl->base + encl->size, NULL, false); - if (ret) - goto out; - -@@ -592,17 +604,17 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, - goto out; - } - -- down_read(¤t->mm->mmap_sem); -+ down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, secs->base); - if (!vma || vma->vm_ops != &sgx_vm_ops || - vma->vm_start != secs->base || - vma->vm_end != (secs->base + secs->size)) { - ret = -EINVAL; -- up_read(¤t->mm->mmap_sem); -+ up_write(¤t->mm->mmap_sem); - goto out; - } - vma->vm_private_data = encl; -- up_read(¤t->mm->mmap_sem); -+ up_write(¤t->mm->mmap_sem); - - mutex_lock(&sgx_tgid_ctx_mutex); - list_add_tail(&encl->encl_list, &encl->tgid_ctx->encl_list); -@@ -697,7 +709,7 @@ static int __encl_add_page(struct sgx_encl *encl, - } - } - -- ret = sgx_init_page(encl, encl_page, addp->addr); -+ ret = sgx_init_page(encl, encl_page, addp->addr, NULL, false); - if (ret) { - __free_page(tmp_page); - return -EINVAL; -@@ -930,6 +942,500 @@ out_free_page: - return ret; - } - -+/** -+ * sgx_augment_encl() - 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_augment_encl(struct vm_area_struct *vma, -+ unsigned long addr, -+ bool write) -+{ -+ struct sgx_page_info 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_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, &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_page, secs_epc_page, true); -+ if (ret) -+ goto out; -+ -+ encl->secs_page.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_page.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; -+ } -+ -+ 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->load_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; -+ -+ address = rg->start_addr; -+ end = address + rg->nr_pages * PAGE_SIZE; -+ -+ vma = sgx_find_vma(encl, address); -+ if (!vma) -+ 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->load_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, *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(encl_page, tmp, &list, load_list) { -+ 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(encl_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; -+} -+ -+static 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_find_and_get_encl(rg->start_addr, &encl); -+ if (ret) { -+ pr_debug("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; -+} -+ -+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 need to be invoked after that. -+ * @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); -+} -+ -+static 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; -+ -+ vma = sgx_find_vma(encl, address); -+ if (!vma) -+ 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->load_list); -+ 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; -+} -+ -+/** -+ * 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_find_and_get_encl(address, &encl); -+ if (ret) { -+ pr_debug("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_find_and_get_encl(address, &encl)) { -+ pr_debug("sgx: No enclave found at start address 0x%lx\n", -+ address); -+ return -EINVAL; -+ } -+ -+ ret = remove_page(encl, address, false); -+ if (ret) { -+ pr_debug("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); - -@@ -949,6 +1455,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 91fee13..7e22bcc 100644 ---- a/sgx_main.c -+++ b/sgx_main.c -@@ -70,7 +70,7 @@ - #include - - #define DRV_DESCRIPTION "Intel SGX Driver" --#define DRV_VERSION "0.10" -+#define DRV_VERSION "0.11" - - #define ENCL_SIZE_MAX_64 (64ULL * 1024ULL * 1024ULL * 1024ULL) - #define ENCL_SIZE_MAX_32 (2ULL * 1024ULL * 1024ULL * 1024ULL) -diff --git a/sgx_page_cache.c b/sgx_page_cache.c -index 0cb9b4e..728ad90 100644 ---- a/sgx_page_cache.c -+++ b/sgx_page_cache.c -@@ -242,19 +242,32 @@ static void sgx_eblock(struct sgx_encl *encl, - - } - --static void sgx_etrack(struct sgx_encl *encl) -+bool sgx_etrack(struct sgx_encl *encl, unsigned int epoch) - { - void *epc; - int ret; -+ bool ipi = false; -+ -+ /* If someone already called etrack in the meantime */ -+ if (epoch < encl->shadow_epoch) -+ return false; - - epc = sgx_get_page(encl->secs_page.epc_page); - ret = __etrack(epc); - sgx_put_page(epc); -- -- if (ret) { -+ encl->shadow_epoch++; -+ -+ 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)); -+ ipi = true; -+ } else if (ret) { - sgx_crit(encl, "ETRACK returned %d\n", ret); - sgx_invalidate(encl, true); - } -+ -+ return ipi; - } - - static int __sgx_ewb(struct sgx_encl *encl, -@@ -362,7 +375,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 503f6be..d268b45 100644 ---- a/sgx_user.h -+++ b/sgx_user.h -@@ -71,6 +71,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 -@@ -92,6 +102,7 @@ - #define SGX_INVALID_LICENSE 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 -@@ -142,4 +153,22 @@ struct sgx_enclave_destroy { - __u64 addr; - } __packed; - -+ -+/* -+ * SGX2.0 definitions -+ */ -+ -+#define SGX_GROW_UP_FLAG 1 -+#define SGX_GROW_DOWN_FLAG 2 -+ -+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 614a635..16276f9 100644 ---- a/sgx_util.c -+++ b/sgx_util.c -@@ -145,7 +145,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) - { - } - -@@ -186,10 +186,10 @@ int sgx_find_encl(struct mm_struct *mm, unsigned long addr, - return 0; - } - --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; -@@ -253,7 +253,8 @@ out: - } - - static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, -- unsigned long addr, unsigned int flags) -+ unsigned long addr, unsigned int flags, -+ struct vm_fault *vmf) - { - struct sgx_encl *encl = vma->vm_private_data; - struct sgx_encl_page *entry; -@@ -261,6 +262,8 @@ 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. -@@ -271,6 +274,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_augment_encl(vma, addr, write); -+ goto out; -+ } -+ -+ /* No entry found can not happen in 'reloading an evicted page' -+ * flow. -+ */ - if (!entry) { - rc = -EFAULT; - goto out; -@@ -371,12 +382,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); -diff --git a/sgx_vma.c b/sgx_vma.c -index 4dbe26c..d76b948 100644 ---- a/sgx_vma.c -+++ b/sgx_vma.c -@@ -75,6 +75,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. - */ -@@ -89,7 +95,6 @@ static void sgx_vma_close(struct vm_area_struct *vma) - - mutex_lock(&encl->lock); - 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); - } -@@ -111,7 +116,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; -@@ -210,7 +215,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 - diff --git a/sgx.h b/sgx.h index 0dae86c..bfc24c0 100644 --- a/sgx.h +++ b/sgx.h @@ -4,7 +4,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -21,7 +21,7 @@ * * BSD LICENSE * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -60,7 +60,7 @@ #ifndef __ARCH_INTEL_SGX_H__ #define __ARCH_INTEL_SGX_H__ -#include "sgx_user.h" +#include "sgx_asm.h" #include #include #include @@ -69,16 +69,25 @@ #include #include #include -#include #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 +struct sgx_epc_page { + resource_size_t pa; + struct list_head list; + struct sgx_encl_page *encl_page; +}; + +enum sgx_alloc_flags { + SGX_ALLOC_ATOMIC = BIT(0), +}; + struct sgx_va_page { struct sgx_epc_page *epc_page; DECLARE_BITMAP(slots, SGX_VA_SLOT_COUNT); @@ -101,28 +110,15 @@ 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 { unsigned long addr; unsigned int flags; struct sgx_epc_page *epc_page; - struct list_head load_list; struct sgx_va_page *va_page; unsigned int va_offset; }; @@ -144,6 +140,8 @@ enum sgx_encl_flags { struct sgx_encl { unsigned int flags; + uint64_t attributes; + uint64_t xfrm; unsigned int secs_child_cnt; struct mutex lock; struct mm_struct *mm; @@ -153,23 +151,23 @@ struct sgx_encl { struct kref refcount; unsigned long base; unsigned long size; + unsigned long ssaframesize; struct list_head va_pages; struct radix_tree_root page_tree; struct list_head add_page_reqs; struct work_struct add_page_work; - struct sgx_encl_page secs_page; + struct sgx_encl_page secs; struct sgx_tgid_ctx *tgid_ctx; struct list_head encl_list; struct mmu_notifier mmu_notifier; - unsigned int shadow_epoch; }; struct sgx_epc_bank { + unsigned long pa; #ifdef CONFIG_X86_64 - void *mem; + unsigned long va; #endif - unsigned long start; - unsigned long end; + unsigned long size; }; extern struct workqueue_struct *sgx_add_page_wq; @@ -178,22 +176,36 @@ extern int sgx_nr_epc_banks; extern u64 sgx_encl_size_max_32; extern u64 sgx_encl_size_max_64; extern u64 sgx_xfrm_mask; -extern u32 sgx_ssaframesize_tbl[64]; -extern bool sgx_has_sgx2; +extern u32 sgx_misc_reserved; +extern u32 sgx_xsave_size_tbl[64]; extern const struct vm_operations_struct sgx_vm_ops; -extern atomic_t sgx_nr_pids; #define sgx_pr_ratelimited(level, encl, fmt, ...) \ pr_ ## level ## _ratelimited("intel_sgx: [%d:0x%p] " fmt, \ pid_nr((encl)->tgid_ctx->tgid), \ (void *)(encl)->base, ##__VA_ARGS__) -#define sgx_dbg(encl, fmt, ...) sgx_pr_ratelimited(debug, encl, fmt, ##__VA_ARGS__) -#define sgx_info(encl, fmt, ...) sgx_pr_ratelimited(info, encl, fmt, ##__VA_ARGS__) -#define sgx_warn(encl, fmt, ...) sgx_pr_ratelimited(warn, encl, fmt, ##__VA_ARGS__) -#define sgx_err(encl, fmt, ...) sgx_pr_ratelimited(err, encl, fmt, ##__VA_ARGS__) -#define sgx_crit(encl, fmt, ...) sgx_pr_ratelimited(crit, encl, fmt, ##__VA_ARGS__) +#define sgx_dbg(encl, fmt, ...) \ + sgx_pr_ratelimited(debug, encl, fmt, ##__VA_ARGS__) +#define sgx_info(encl, fmt, ...) \ + sgx_pr_ratelimited(info, encl, fmt, ##__VA_ARGS__) +#define sgx_warn(encl, fmt, ...) \ + sgx_pr_ratelimited(warn, encl, fmt, ##__VA_ARGS__) +#define sgx_err(encl, fmt, ...) \ + sgx_pr_ratelimited(err, encl, fmt, ##__VA_ARGS__) +#define sgx_crit(encl, fmt, ...) \ + sgx_pr_ratelimited(crit, encl, fmt, ##__VA_ARGS__) + +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, + struct vm_area_struct **vma); +void sgx_tgid_ctx_release(struct kref *ref); +int sgx_encl_create(struct sgx_secs *secs); +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); +void sgx_encl_release(struct kref *ref); long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); #ifdef CONFIG_COMPAT @@ -211,13 +223,10 @@ void sgx_insert_pte(struct sgx_encl *encl, struct sgx_epc_page *epc_page, struct vm_area_struct *vma); int sgx_eremove(struct sgx_epc_page *epc_page); -struct vm_area_struct *sgx_find_vma(struct sgx_encl *encl, unsigned long addr); void sgx_zap_tcs_ptes(struct sgx_encl *encl, struct vm_area_struct *vma); void sgx_invalidate(struct sgx_encl *encl, bool flush_cpus); void sgx_flush_cpus(struct sgx_encl *encl); -int sgx_find_encl(struct mm_struct *mm, unsigned long addr, - struct vm_area_struct **vma); enum sgx_fault_flags { SGX_FAULT_RESERVE = BIT(0), @@ -225,36 +234,21 @@ enum sgx_fault_flags { struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma, unsigned long addr, - unsigned int flags, - struct vm_fault *vmf); + unsigned int flags); -void sgx_encl_release(struct kref *ref); -void sgx_tgid_ctx_release(struct kref *ref); - -void sgx_ipi_cb(void *info); -bool sgx_etrack(struct sgx_encl *encl, unsigned int epoch); -struct sgx_encl_page *sgx_augment_encl(struct vm_area_struct *vma, - unsigned long addr, - bool write); -int sgx_eldu(struct sgx_encl *encl, - struct sgx_encl_page *encl_page, - struct sgx_epc_page *epc_page, - bool is_secs); extern struct mutex sgx_tgid_ctx_mutex; extern struct list_head sgx_tgid_ctx_list; -extern struct task_struct *ksgxswapd_tsk; - -enum sgx_alloc_flags { - SGX_ALLOC_ATOMIC = BIT(0), -}; +extern atomic_t sgx_va_pages_cnt; -int ksgxswapd(void *p); -int sgx_page_cache_init(resource_size_t start, unsigned long size); +int sgx_add_epc_bank(resource_size_t start, unsigned long size, int bank); +int sgx_page_cache_init(void); void sgx_page_cache_teardown(void); struct sgx_epc_page *sgx_alloc_page(unsigned int flags); -int sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl); +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); #endif /* __ARCH_X86_INTEL_SGX_H__ */ diff --git a/sgx_arch.h b/sgx_arch.h index 6d2fea9..dcb620e 100644 --- a/sgx_arch.h +++ b/sgx_arch.h @@ -4,7 +4,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -21,7 +21,7 @@ * * BSD LICENSE * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -52,306 +52,218 @@ * Authors: * * Jarkko Sakkinen - * Suresh Siddha - * Serge Ayoun - * Shay Katz-zamir */ -#ifndef _ASM_X86_SGX_H -#define _ASM_X86_SGX_H - -#include -#include -#include #include +#ifndef _ASM_X86_SGX_ARCH_H +#define _ASM_X86_SGX_ARCH_H -#define SGX_CPUID 0x12 - -enum sgx_page_type { - SGX_PAGE_TYPE_SECS = 0x00, - SGX_PAGE_TYPE_TCS = 0x01, - SGX_PAGE_TYPE_REG = 0x02, - SGX_PAGE_TYPE_VA = 0x03, -}; +#define SGX_SSA_GPRS_SIZE 182 +#define SGX_SSA_MISC_EXINFO_SIZE 16 -enum sgx_secinfo_flags { - SGX_SECINFO_R = 0x01, - SGX_SECINFO_W = 0x02, - SGX_SECINFO_X = 0x04, - SGX_SECINFO_SECS = 0x000ULL, - SGX_SECINFO_TCS = 0x100ULL, - SGX_SECINFO_REG = 0x200ULL, - SGX_SECINFO_TRIM = 0x400ULL, +enum sgx_misc { + SGX_MISC_EXINFO = 0x01, }; -struct sgx_secinfo { - u64 flags; - u64 reserved[7]; -} __aligned(128); - -struct sgx_einittoken { - u32 valid; - u8 reserved1[206]; - u16 isvsvnle; - u8 reserved2[92]; -} __aligned(512); +#define SGX_MISC_RESERVED_MASK 0xFFFFFFFFFFFFFFFEL -enum isgx_secs_attributes { - SGX_SECS_A_DEBUG = BIT_ULL(1), - SGX_SECS_A_MODE64BIT = BIT_ULL(2), - SGX_SECS_A_PROVISION_KEY = BIT_ULL(4), - SGX_SECS_A_LICENSE_KEY = BIT_ULL(5), - SGX_SECS_A_RESERVED_MASK = (BIT_ULL(0) | - BIT_ULL(3) | - GENMASK_ULL(63, 6)), +enum sgx_attribute { + SGX_ATTR_DEBUG = 0x02, + SGX_ATTR_MODE64BIT = 0x04, + SGX_ATTR_PROVISIONKEY = 0x10, + SGX_ATTR_EINITTOKENKEY = 0x20, }; +#define SGX_ATTR_RESERVED_MASK 0xFFFFFFFFFFFFFFC9L + #define SGX_SECS_RESERVED1_SIZE 24 #define SGX_SECS_RESERVED2_SIZE 32 #define SGX_SECS_RESERVED3_SIZE 96 #define SGX_SECS_RESERVED4_SIZE 3836 struct sgx_secs { - u64 size; - u64 base; - u32 ssaframesize; - u32 misc_select; + uint64_t size; + uint64_t base; + uint32_t ssaframesize; + uint32_t miscselect; uint8_t reserved1[SGX_SECS_RESERVED1_SIZE]; - u64 flags; - u64 xfrm; - u32 mrenclave[8]; - uint8_t reserved2[SGX_SECS_RESERVED2_SIZE]; - u32 mrsigner[8]; + uint64_t attributes; + uint64_t xfrm; + uint32_t mrenclave[8]; + uint8_t reserved2[SGX_SECS_RESERVED2_SIZE]; + uint32_t mrsigner[8]; uint8_t reserved3[SGX_SECS_RESERVED3_SIZE]; - u16 isvvprodid; - u16 isvsvn; - uint8_t reserved[SGX_SECS_RESERVED4_SIZE]; + uint16_t isvvprodid; + uint16_t isvsvn; + uint8_t reserved4[SGX_SECS_RESERVED4_SIZE]; }; -struct sgx_tcs { - u64 state; - u64 flags; - u64 ossa; - u32 cssa; - u32 nssa; - u64 oentry; - u64 aep; - u64 ofsbase; - u64 ogsbase; - u32 fslimit; - u32 gslimit; - u64 reserved[503]; +enum sgx_tcs_flags { + SGX_TCS_DBGOPTIN = 0x01, /* cleared on EADD */ }; -enum sgx_secinfo_masks { - SGX_SECINFO_PERMISSION_MASK = GENMASK_ULL(2, 0), - SGX_SECINFO_PAGE_TYPE_MASK = GENMASK_ULL(15, 8), - SGX_SECINFO_RESERVED_MASK = (GENMASK_ULL(7, 3) | - GENMASK_ULL(63, 16)), -}; +#define SGX_TCS_RESERVED_MASK 0xFFFFFFFFFFFFFFFEL -struct sgx_pcmd { - struct sgx_secinfo secinfo; - u64 enclave_id; - u8 reserved[40]; - u8 mac[16]; +struct sgx_tcs { + uint64_t state; + uint64_t flags; + uint64_t ossa; + uint32_t cssa; + uint32_t nssa; + uint64_t oentry; + uint64_t aep; + uint64_t ofsbase; + uint64_t ogsbase; + uint32_t fslimit; + uint32_t gslimit; + uint64_t reserved[503]; }; -struct sgx_page_info { - u64 linaddr; - u64 srcpge; +struct sgx_pageinfo { + uint64_t linaddr; + uint64_t srcpge; union { - u64 secinfo; - u64 pcmd; + uint64_t secinfo; + uint64_t pcmd; }; - u64 secs; -} __aligned(32); - -#define SIGSTRUCT_SIZE 1808 -#define EINITTOKEN_SIZE 304 - -enum { - ECREATE = 0x0, - EADD = 0x1, - EINIT = 0x2, - EREMOVE = 0x3, - EDGBRD = 0x4, - EDGBWR = 0x5, - EEXTEND = 0x6, - ELDU = 0x8, - EBLOCK = 0x9, - EPA = 0xA, - EWB = 0xB, - ETRACK = 0xC, - EAUG = 0xD, - EMODPR = 0xE, - EMODT = 0xF, -}; - -#define __encls_ret(rax, rbx, rcx, rdx) \ - ({ \ - int ret; \ - asm volatile( \ - "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : "=a"(ret) \ - : "a"(rax), "b"(rbx), "c"(rcx), "d"(rdx) \ - : "memory"); \ - ret; \ - }) - -#ifdef CONFIG_X86_64 -#define __encls(rax, rbx, rcx, rdx...) \ - ({ \ - int ret; \ - asm volatile( \ - "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ - " xor %%eax,%%eax;\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movq $-1,%%rax\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : "=a"(ret), "=b"(rbx), "=c"(rcx) \ - : "a"(rax), "b"(rbx), "c"(rcx), rdx \ - : "memory"); \ - ret; \ - }) -#else -#define __encls(rax, rbx, rcx, rdx...) \ - ({ \ - int ret; \ - asm volatile( \ - "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ - " xor %%eax,%%eax;\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: mov $-1,%%eax\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : "=a"(ret), "=b"(rbx), "=c"(rcx) \ - : "a"(rax), "b"(rbx), "c"(rcx), rdx \ - : "memory"); \ - ret; \ - }) -#endif - -static inline unsigned long __ecreate(struct sgx_page_info *pginfo, void *secs) -{ - return __encls(ECREATE, pginfo, secs, "d"(0)); -} - -static inline int __eextend(void *secs, void *epc) -{ - return __encls(EEXTEND, secs, epc, "d"(0)); -} - -static inline int __eadd(struct sgx_page_info *pginfo, void *epc) -{ - return __encls(EADD, pginfo, epc, "d"(0)); -} - -static inline int __einit(void *sigstruct, struct sgx_einittoken *einittoken, - void *secs) -{ - return __encls_ret(EINIT, sigstruct, secs, einittoken); -} - -static inline int __eremove(void *epc) -{ - unsigned long rbx = 0; - unsigned long rdx = 0; + uint64_t secs; +} __attribute__((aligned(32))); - return __encls_ret(EREMOVE, rbx, epc, rdx); -} -static inline int __edbgwr(void *epc, unsigned long *data) -{ - return __encls(EDGBWR, *data, epc, "d"(0)); -} +#define SGX_SECINFO_PERMISSION_MASK 0x0000000000000007L +#define SGX_SECINFO_PAGE_TYPE_MASK 0x000000000000FF00L +#define SGX_SECINFO_RESERVED_MASK 0xFFFFFFFFFFFF00F8L -static inline int __edbgrd(void *epc, unsigned long *data) -{ - unsigned long rbx = 0; - int ret; - - ret = __encls(EDGBRD, rbx, epc, "d"(0)); - if (!ret) - *(unsigned long *) data = rbx; - - return ret; -} - -static inline int __etrack(void *epc) -{ - unsigned long rbx = 0; - unsigned long rdx = 0; - - return __encls_ret(ETRACK, rbx, epc, rdx); -} - -static inline int __eldu(unsigned long rbx, unsigned long rcx, - unsigned long rdx) -{ - return __encls_ret(ELDU, rbx, rcx, rdx); -} - -static inline int __eblock(unsigned long rcx) -{ - unsigned long rbx = 0; - unsigned long rdx = 0; - - return __encls_ret(EBLOCK, rbx, rcx, rdx); -} +enum sgx_page_type { + SGX_PAGE_TYPE_SECS = 0x00, + SGX_PAGE_TYPE_TCS = 0x01, + SGX_PAGE_TYPE_REG = 0x02, + SGX_PAGE_TYPE_VA = 0x03, +}; -static inline int __epa(void *epc) -{ - unsigned long rbx = SGX_PAGE_TYPE_VA; +enum sgx_secinfo_flags { + SGX_SECINFO_R = 0x01, + SGX_SECINFO_W = 0x02, + SGX_SECINFO_X = 0x04, + SGX_SECINFO_SECS = (SGX_PAGE_TYPE_SECS << 8), + SGX_SECINFO_TCS = (SGX_PAGE_TYPE_TCS << 8), + SGX_SECINFO_REG = (SGX_PAGE_TYPE_REG << 8), +}; - return __encls(EPA, rbx, epc, "d"(0)); -} +struct sgx_secinfo { + uint64_t flags; + uint64_t reserved[7]; +} __attribute__((aligned(64))); -static inline int __ewb(struct sgx_page_info *pginfo, void *epc, void *va) -{ - return __encls_ret(EWB, pginfo, epc, va); -} +struct sgx_pcmd { + struct sgx_secinfo secinfo; + uint64_t enclave_id; + uint8_t reserved[40]; + uint8_t mac[16]; +}; -static inline int __eaug(struct sgx_page_info *pginfo, void *epc) -{ - return __encls(EAUG, pginfo, epc, "d"(0)); -} +#define SGX_MODULUS_SIZE 384 -static inline int __emodpr(struct sgx_secinfo *secinfo, void *epc) -{ - unsigned long rdx = 0; +struct sgx_sigstruct_header { + uint64_t header1[2]; + uint32_t vendor; + uint32_t date; + uint64_t header2[2]; + uint32_t swdefined; + uint8_t reserved1[84]; +}; - return __encls_ret(EMODPR, secinfo, epc, rdx); -} +struct sgx_sigstruct_body { + uint32_t miscselect; + uint32_t miscmask; + uint8_t reserved2[20]; + uint64_t attributes; + uint64_t xfrm; + uint8_t attributemask[16]; + uint8_t mrenclave[32]; + uint8_t reserved3[32]; + uint16_t isvprodid; + uint16_t isvsvn; +} __attribute__((__packed__)); + +struct sgx_sigstruct { + struct sgx_sigstruct_header header; + uint8_t modulus[SGX_MODULUS_SIZE]; + uint32_t exponent; + uint8_t signature[SGX_MODULUS_SIZE]; + struct sgx_sigstruct_body body; + uint8_t reserved4[12]; + uint8_t q1[SGX_MODULUS_SIZE]; + uint8_t q2[SGX_MODULUS_SIZE]; +}; -static inline int __emodt(struct sgx_secinfo *secinfo, void *epc) -{ - unsigned long rdx = 0; +struct sgx_sigstruct_payload { + struct sgx_sigstruct_header header; + struct sgx_sigstruct_body body; +}; - return __encls_ret(EMODT, secinfo, epc, rdx); -} +struct sgx_einittoken_payload { + uint32_t valid; + uint32_t reserved1[11]; + uint64_t attributes; + uint64_t xfrm; + uint8_t mrenclave[32]; + uint8_t reserved2[32]; + uint8_t mrsigner[32]; + uint8_t reserved3[32]; +}; +struct sgx_einittoken { + struct sgx_einittoken_payload payload; + uint8_t cpusvnle[16]; + uint16_t isvprodidle; + uint16_t isvsvnle; + uint8_t reserved2[24]; + uint32_t maskedmiscselectle; + uint64_t maskedattributesle; + uint64_t maskedxfrmle; + uint8_t keyid[32]; + uint8_t mac[16]; +}; -struct sgx_encl; +struct sgx_report { + uint8_t cpusvn[16]; + uint32_t miscselect; + uint8_t reserved1[28]; + uint64_t attributes; + uint64_t xfrm; + uint8_t mrenclave[32]; + uint8_t reserved2[32]; + uint8_t mrsigner[32]; + uint8_t reserved3[96]; + uint16_t isvprodid; + uint16_t isvsvn; + uint8_t reserved4[60]; + uint8_t reportdata[64]; + uint8_t keyid[32]; + uint8_t mac[16]; +}; -struct sgx_epc_page { - resource_size_t pa; - struct list_head free_list; +struct sgx_targetinfo { + uint8_t mrenclave[32]; + uint64_t attributes; + uint64_t xfrm; + uint8_t reserved1[4]; + uint32_t miscselect; + uint8_t reserved2[456]; }; -extern struct sgx_epc_page *sgx_alloc_page(unsigned int flags); -extern int sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl); -extern void *sgx_get_page(struct sgx_epc_page *entry); -extern void sgx_put_page(void *epc_page_vaddr); +struct sgx_keyrequest { + uint16_t keyname; + uint16_t keypolicy; + uint16_t isvsvn; + uint16_t reserved1; + uint8_t cpusvn[16]; + uint64_t attributemask; + uint64_t xfrmmask; + uint8_t keyid[32]; + uint32_t miscmask; + uint8_t reserved2[436]; +}; -#endif /* _ASM_X86_SGX_H */ +#endif /* _ASM_X86_SGX_ARCH_H */ diff --git a/sgx_asm.h b/sgx_asm.h new file mode 100644 index 0000000..b786f34 --- /dev/null +++ b/sgx_asm.h @@ -0,0 +1,233 @@ +/* + * 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 + * 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: + * + * Jarkko Sakkinen + * Suresh Siddha + */ + +#ifndef _ASM_X86_SGX_H +#define _ASM_X86_SGX_H + +#include "sgx_arch.h" +#include +#include +#include +#include + +#define SGX_CPUID 0x12 + +enum sgx_cpuid { + SGX_CPUID_CAPABILITIES = 0, + SGX_CPUID_ATTRIBUTES = 1, + SGX_CPUID_EPC_BANKS = 2, +}; + +enum sgx_commands { + ECREATE = 0x0, + EADD = 0x1, + EINIT = 0x2, + EREMOVE = 0x3, + EDGBRD = 0x4, + EDGBWR = 0x5, + EEXTEND = 0x6, + ELDU = 0x8, + EBLOCK = 0x9, + EPA = 0xA, + EWB = 0xB, + ETRACK = 0xC, + EAUG = 0xD, + EMODPR = 0xE, + EMODT = 0xF, +}; + +#ifdef CONFIG_X86_64 +#define XAX "%%rax" +#else +#define XAX "%%eax" +#endif + +#define __encls_ret(rax, rbx, rcx, rdx) \ + ({ \ + int ret; \ + asm volatile( \ + "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: mov $-14,"XAX"\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=a"(ret) \ + : "a"(rax), "b"(rbx), "c"(rcx), "d"(rdx) \ + : "memory"); \ + ret; \ + }) + +#define __encls(rax, rbx, rcx, rdx...) \ + ({ \ + int ret; \ + asm volatile( \ + "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ + " xor "XAX","XAX"\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: mov $-14,"XAX"\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=a"(ret), "=b"(rbx), "=c"(rcx) \ + : "a"(rax), "b"(rbx), "c"(rcx), rdx \ + : "memory"); \ + ret; \ + }) + +static inline unsigned long __ecreate(struct sgx_pageinfo *pginfo, void *secs) +{ + return __encls(ECREATE, pginfo, secs, "d"(0)); +} + +static inline int __eextend(void *secs, void *epc) +{ + return __encls(EEXTEND, secs, epc, "d"(0)); +} + +static inline int __eadd(struct sgx_pageinfo *pginfo, void *epc) +{ + return __encls(EADD, pginfo, epc, "d"(0)); +} + +static inline int __einit(void *sigstruct, struct sgx_einittoken *einittoken, + void *secs) +{ + return __encls_ret(EINIT, sigstruct, secs, einittoken); +} + +static inline int __eremove(void *epc) +{ + unsigned long rbx = 0; + unsigned long rdx = 0; + + return __encls_ret(EREMOVE, rbx, epc, rdx); +} + +static inline int __edbgwr(void *epc, unsigned long *data) +{ + return __encls(EDGBWR, *data, epc, "d"(0)); +} + +static inline int __edbgrd(void *epc, unsigned long *data) +{ + unsigned long rbx = 0; + int ret; + + ret = __encls(EDGBRD, rbx, epc, "d"(0)); + if (!ret) + *(unsigned long *) data = rbx; + + return ret; +} + +static inline int __etrack(void *epc) +{ + unsigned long rbx = 0; + unsigned long rdx = 0; + + return __encls_ret(ETRACK, rbx, epc, rdx); +} + +static inline int __eldu(unsigned long rbx, unsigned long rcx, + unsigned long rdx) +{ + return __encls_ret(ELDU, rbx, rcx, rdx); +} + +static inline int __eblock(unsigned long rcx) +{ + unsigned long rbx = 0; + unsigned long rdx = 0; + + return __encls_ret(EBLOCK, rbx, rcx, rdx); +} + +static inline int __epa(void *epc) +{ + unsigned long rbx = SGX_PAGE_TYPE_VA; + + return __encls(EPA, rbx, epc, "d"(0)); +} + +static inline int __ewb(struct sgx_pageinfo *pginfo, void *epc, void *va) +{ + return __encls_ret(EWB, pginfo, epc, va); +} + +static inline int __eaug(struct sgx_pageinfo *pginfo, void *epc) +{ + return __encls(EAUG, pginfo, epc, "d"(0)); +} + +static inline int __emodpr(struct sgx_secinfo *secinfo, void *epc) +{ + unsigned long rdx = 0; + + return __encls_ret(EMODPR, secinfo, epc, rdx); +} + +static inline int __emodt(struct sgx_secinfo *secinfo, void *epc) +{ + unsigned long rdx = 0; + + return __encls_ret(EMODT, secinfo, epc, rdx); +} + +#endif /* _ASM_X86_SGX_H */ diff --git a/sgx_encl.c b/sgx_encl.c new file mode 100644 index 0000000..2669509 --- /dev/null +++ b/sgx_encl.c @@ -0,0 +1,993 @@ +/* + * 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 + * 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: + * + * Jarkko Sakkinen + * Suresh Siddha + * Serge Ayoun + * Shay Katz-zamir + * Sean Christopherson + */ + +#include "sgx.h" +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) + #include +#else + #include +#endif +#include "linux/file.h" +#include +#include +#include + +struct sgx_add_page_req { + struct sgx_encl *encl; + struct sgx_encl_page *encl_page; + struct sgx_secinfo secinfo; + u16 mrmask; + struct list_head list; +}; + +/** + * sgx_encl_find - find an enclave + * @mm: mm struct of the current process + * @addr: address in the ELRANGE + * @vma: the resulting VMA + * + * Finds an enclave identified by the given address. Gives back the VMA, that + * is part of the enclave, located in that address. The VMA is given back if it + * is a proper enclave VMA even if a &struct sgx_encl instance does not exist + * yet (enclave creation has not been performed). + * + * Return: + * 0 on success, + * -EINVAL if an enclave was not found, + * -ENOENT if the enclave has not been created yet + */ +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, + struct vm_area_struct **vma) +{ + struct vm_area_struct *result; + struct sgx_encl *encl; + + result = find_vma(mm, addr); + if (!result || result->vm_ops != &sgx_vm_ops || addr < result->vm_start) + return -EINVAL; + + encl = result->vm_private_data; + *vma = result; + + return encl ? 0 : -ENOENT; +} + +static struct sgx_tgid_ctx *sgx_find_tgid_ctx(struct pid *tgid) +{ + struct sgx_tgid_ctx *ctx; + + list_for_each_entry(ctx, &sgx_tgid_ctx_list, list) + if (pid_nr(ctx->tgid) == pid_nr(tgid)) + return ctx; + + return NULL; +} + +static int sgx_add_to_tgid_ctx(struct sgx_encl *encl) +{ + struct sgx_tgid_ctx *ctx; + struct pid *tgid = get_pid(task_tgid(current)); + + mutex_lock(&sgx_tgid_ctx_mutex); + + ctx = sgx_find_tgid_ctx(tgid); + if (ctx) { + if (kref_get_unless_zero(&ctx->refcount)) { + encl->tgid_ctx = ctx; + mutex_unlock(&sgx_tgid_ctx_mutex); + put_pid(tgid); + return 0; + } else { + list_del_init(&ctx->list); + } + } + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + mutex_unlock(&sgx_tgid_ctx_mutex); + put_pid(tgid); + return -ENOMEM; + } + + ctx->tgid = tgid; + kref_init(&ctx->refcount); + INIT_LIST_HEAD(&ctx->encl_list); + + list_add(&ctx->list, &sgx_tgid_ctx_list); + + encl->tgid_ctx = ctx; + + mutex_unlock(&sgx_tgid_ctx_mutex); + return 0; +} + +void sgx_tgid_ctx_release(struct kref *ref) +{ + struct sgx_tgid_ctx *pe = + container_of(ref, struct sgx_tgid_ctx, refcount); + mutex_lock(&sgx_tgid_ctx_mutex); + list_del(&pe->list); + mutex_unlock(&sgx_tgid_ctx_mutex); + put_pid(pe->tgid); + kfree(pe); +} + +static int sgx_measure(struct sgx_epc_page *secs_page, + struct sgx_epc_page *epc_page, + u16 mrmask) +{ + void *secs; + void *epc; + int ret = 0; + int i, j; + + for (i = 0, j = 1; i < 0x1000 && !ret; i += 0x100, j <<= 1) { + if (!(j & mrmask)) + continue; + + secs = sgx_get_page(secs_page); + epc = sgx_get_page(epc_page); + + ret = __eextend(secs, (void *)((unsigned long)epc + i)); + + sgx_put_page(epc); + sgx_put_page(secs); + } + + return ret; +} + +static int sgx_eadd(struct sgx_epc_page *secs_page, + struct sgx_epc_page *epc_page, + unsigned long linaddr, + struct sgx_secinfo *secinfo, + struct page *backing) +{ + struct sgx_pageinfo pginfo; + void *epc_page_vaddr; + int ret; + + pginfo.srcpge = (unsigned long)kmap_atomic(backing); + pginfo.secs = (unsigned long)sgx_get_page(secs_page); + epc_page_vaddr = sgx_get_page(epc_page); + + pginfo.linaddr = linaddr; + pginfo.secinfo = (unsigned long)secinfo; + ret = __eadd(&pginfo, epc_page_vaddr); + + sgx_put_page(epc_page_vaddr); + sgx_put_page((void *)(unsigned long)pginfo.secs); + kunmap_atomic((void *)(unsigned long)pginfo.srcpge); + + return ret; +} + +static bool sgx_process_add_page_req(struct sgx_add_page_req *req, + struct sgx_epc_page *epc_page) +{ + struct page *backing; + struct sgx_encl_page *encl_page = req->encl_page; + struct sgx_encl *encl = req->encl; + struct vm_area_struct *vma; + int ret; + + if (encl->flags & (SGX_ENCL_SUSPEND | SGX_ENCL_DEAD)) + return false; + + ret = sgx_encl_find(encl->mm, encl_page->addr, &vma); + if (ret) + return false; + + backing = sgx_get_backing(encl, encl_page, false); + if (IS_ERR(backing)) + return false; + + /* Do not race with do_exit() */ + if (!atomic_read(&encl->mm->mm_users)) { + sgx_put_backing(backing, 0); + return false; + } + + ret = vm_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); + if (ret) { + sgx_put_backing(backing, 0); + return false; + } + + ret = sgx_eadd(encl->secs.epc_page, epc_page, encl_page->addr, + &req->secinfo, backing); + + sgx_put_backing(backing, 0); + if (ret) { + sgx_warn(encl, "EADD returned %d\n", ret); + zap_vma_ptes(vma, encl_page->addr, PAGE_SIZE); + return false; + } + + encl->secs_child_cnt++; + + ret = sgx_measure(encl->secs.epc_page, epc_page, req->mrmask); + if (ret) { + sgx_warn(encl, "EEXTEND returned %d\n", ret); + zap_vma_ptes(vma, encl_page->addr, PAGE_SIZE); + return false; + } + + epc_page->encl_page = encl_page; + encl_page->epc_page = epc_page; + sgx_test_and_clear_young(encl_page, encl); + list_add_tail(&epc_page->list, &encl->load_list); + + return true; +} + +static void sgx_add_page_worker(struct work_struct *work) +{ + struct sgx_encl *encl; + struct sgx_add_page_req *req; + struct sgx_epc_page *epc_page; + bool skip_rest = false; + bool is_empty = false; + + encl = container_of(work, struct sgx_encl, add_page_work); + + do { + schedule(); + + if (encl->flags & SGX_ENCL_DEAD) + skip_rest = true; + + mutex_lock(&encl->lock); + req = list_first_entry(&encl->add_page_reqs, + struct sgx_add_page_req, list); + list_del(&req->list); + is_empty = list_empty(&encl->add_page_reqs); + mutex_unlock(&encl->lock); + + if (skip_rest) + goto next; + + epc_page = sgx_alloc_page(0); + if (IS_ERR(epc_page)) { + skip_rest = true; + goto next; + } + + down_read(&encl->mm->mmap_sem); + mutex_lock(&encl->lock); + + if (!sgx_process_add_page_req(req, epc_page)) { + sgx_free_page(epc_page, encl); + skip_rest = true; + } + + mutex_unlock(&encl->lock); + up_read(&encl->mm->mmap_sem); + +next: + kfree(req); + } while (!kref_put(&encl->refcount, sgx_encl_release) && !is_empty); +} + +static u32 sgx_calc_ssaframesize(u32 miscselect, u64 xfrm) +{ + u32 size_max = PAGE_SIZE; + u32 size; + int i; + + for (i = 2; i < 64; i++) { + if (!((1 << i) & xfrm)) + continue; + + size = SGX_SSA_GPRS_SIZE + sgx_xsave_size_tbl[i]; + if (miscselect & SGX_MISC_EXINFO) + size += SGX_SSA_MISC_EXINFO_SIZE; + + if (size > size_max) + size_max = size; + } + + return (size_max + PAGE_SIZE - 1) >> PAGE_SHIFT; +} + +static int sgx_validate_secs(const struct sgx_secs *secs, + unsigned long ssaframesize) +{ + int i; + + if (secs->size < (2 * PAGE_SIZE) || + (secs->size & (secs->size - 1)) != 0) + return -EINVAL; + + if (secs->base & (secs->size - 1)) + return -EINVAL; + + if (secs->attributes & SGX_ATTR_RESERVED_MASK || + secs->miscselect & sgx_misc_reserved) + return -EINVAL; + + if (secs->attributes & SGX_ATTR_MODE64BIT) { +#ifdef CONFIG_X86_64 + if (secs->size > sgx_encl_size_max_64) + return -EINVAL; +#else + return -EINVAL; +#endif + } else { + /* On 64-bit architecture allow 32-bit encls only in + * the compatibility mode. + */ +#ifdef CONFIG_X86_64 + if (!test_thread_flag(TIF_ADDR32)) + return -EINVAL; +#endif + if (secs->size > sgx_encl_size_max_32) + return -EINVAL; + } + + if ((secs->xfrm & 0x3) != 0x3 || (secs->xfrm & ~sgx_xfrm_mask)) + return -EINVAL; + + /* Check that BNDREGS and BNDCSR are equal. */ + if (((secs->xfrm >> 3) & 1) != ((secs->xfrm >> 4) & 1)) + return -EINVAL; + + if (!secs->ssaframesize || ssaframesize > secs->ssaframesize) + return -EINVAL; + + for (i = 0; i < SGX_SECS_RESERVED1_SIZE; i++) + if (secs->reserved1[i]) + return -EINVAL; + + for (i = 0; i < SGX_SECS_RESERVED2_SIZE; i++) + if (secs->reserved2[i]) + return -EINVAL; + + for (i = 0; i < SGX_SECS_RESERVED3_SIZE; i++) + if (secs->reserved3[i]) + return -EINVAL; + + for (i = 0; i < SGX_SECS_RESERVED4_SIZE; i++) + if (secs->reserved4[i]) + return -EINVAL; + + 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_DEAD; + mutex_unlock(&encl->lock); +} + +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) +{ + struct sgx_va_page *va_page; + struct sgx_epc_page *epc_page = NULL; + unsigned int va_offset = PAGE_SIZE; + void *vaddr; + int ret = 0; + + list_for_each_entry(va_page, &encl->va_pages, list) { + va_offset = sgx_alloc_va_slot(va_page); + if (va_offset < PAGE_SIZE) + break; + } + + if (va_offset == PAGE_SIZE) { + va_page = kzalloc(sizeof(*va_page), GFP_KERNEL); + 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); + } + + vaddr = sgx_get_page(epc_page); + if (!vaddr) { + sgx_warn(encl, "kmap of a new VA page failed %d\n", + ret); + sgx_free_page(epc_page, encl); + kfree(va_page); + return -EFAULT; + } + + ret = __epa(vaddr); + sgx_put_page(vaddr); + + if (ret) { + sgx_warn(encl, "EPA returned %d\n", ret); + sgx_free_page(epc_page, encl); + kfree(va_page); + return -EFAULT; + } + + atomic_inc(&sgx_va_pages_cnt); + + va_page->epc_page = epc_page; + va_offset = sgx_alloc_va_slot(va_page); + + mutex_lock(&encl->lock); + list_add(&va_page->list, &encl->va_pages); + mutex_unlock(&encl->lock); + } + + entry->va_page = va_page; + entry->va_offset = va_offset; + entry->addr = addr; + + return 0; +} + +/** + * sgx_encl_alloc - allocate memory for an enclave and set attributes + * + * @secs: SECS data (must be page aligned) + * + * Allocates a new &struct sgx_encl instance. Validates SECS attributes, creates + * backing storage for the enclave and sets enclave attributes to sane initial + * values. + * + * Return: + * &struct sgx_encl instance on success, + * system error on failure + */ +static struct sgx_encl *sgx_encl_alloc(struct sgx_secs *secs) +{ + unsigned long ssaframesize; + struct sgx_encl *encl; + struct file *backing; + struct file *pcmd; + + ssaframesize = sgx_calc_ssaframesize(secs->miscselect, secs->xfrm); + if (sgx_validate_secs(secs, ssaframesize)) + return ERR_PTR(-EINVAL); + + backing = shmem_file_setup("[dev/sgx]", secs->size + PAGE_SIZE, + VM_NORESERVE); + if (IS_ERR(backing)) + return (void *)backing; + + pcmd = shmem_file_setup("[dev/sgx]", (secs->size + PAGE_SIZE) >> 5, + VM_NORESERVE); + if (IS_ERR(pcmd)) { + fput(backing); + return (void *)pcmd; + } + + encl = kzalloc(sizeof(*encl), GFP_KERNEL); + if (!encl) { + fput(backing); + fput(pcmd); + return ERR_PTR(-ENOMEM); + } + + encl->attributes = secs->attributes; + encl->xfrm = secs->xfrm; + + kref_init(&encl->refcount); + INIT_LIST_HEAD(&encl->add_page_reqs); + INIT_LIST_HEAD(&encl->va_pages); + INIT_RADIX_TREE(&encl->page_tree, GFP_KERNEL); + INIT_LIST_HEAD(&encl->load_list); + INIT_LIST_HEAD(&encl->encl_list); + mutex_init(&encl->lock); + INIT_WORK(&encl->add_page_work, sgx_add_page_worker); + + encl->mm = current->mm; + encl->base = secs->base; + encl->size = secs->size; + encl->ssaframesize = secs->ssaframesize; + encl->backing = backing; + encl->pcmd = pcmd; + + return encl; +} + +/** + * sgx_encl_create - create an enclave + * + * @secs: page aligned SECS data + * + * Validates SECS attributes, allocates an EPC page for the SECS and creates + * the enclave by performing ECREATE. + * + * Return: + * 0 on success, + * system error on failure + */ +int sgx_encl_create(struct sgx_secs *secs) +{ + struct sgx_pageinfo pginfo; + struct sgx_secinfo secinfo; + struct sgx_encl *encl; + struct sgx_epc_page *secs_epc; + struct vm_area_struct *vma; + void *secs_vaddr; + long ret; + + encl = sgx_encl_alloc(secs); + if (IS_ERR(encl)) + return PTR_ERR(encl); + + secs_epc = sgx_alloc_page(0); + if (IS_ERR(secs_epc)) { + ret = PTR_ERR(secs_epc); + goto out; + } + + encl->secs.epc_page = secs_epc; + + ret = sgx_add_to_tgid_ctx(encl); + if (ret) + goto out; + + ret = sgx_init_page(encl, &encl->secs, encl->base + encl->size, 0); + if (ret) + goto out; + + secs_vaddr = sgx_get_page(secs_epc); + + pginfo.srcpge = (unsigned long)secs; + pginfo.linaddr = 0; + pginfo.secinfo = (unsigned long)&secinfo; + pginfo.secs = 0; + memset(&secinfo, 0, sizeof(secinfo)); + ret = __ecreate((void *)&pginfo, secs_vaddr); + + sgx_put_page(secs_vaddr); + + if (ret) { + sgx_dbg(encl, "ECREATE returned %ld\n", ret); + ret = -EFAULT; + goto out; + } + + if (secs->attributes & SGX_ATTR_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) { + if (ret == -EINTR) + ret = -ERESTARTSYS; + encl->mmu_notifier.ops = NULL; + goto out; + } + + down_read(¤t->mm->mmap_sem); + ret = sgx_encl_find(current->mm, secs->base, &vma); + if (ret != -ENOENT) { + if (!ret) + ret = -EINVAL; + up_read(¤t->mm->mmap_sem); + goto out; + } + + if (vma->vm_start != secs->base || + vma->vm_end != (secs->base + secs->size) + /* vma->vm_pgoff != 0 */) { + ret = -EINVAL; + up_read(¤t->mm->mmap_sem); + goto out; + } + + vma->vm_private_data = encl; + up_read(¤t->mm->mmap_sem); + + mutex_lock(&sgx_tgid_ctx_mutex); + list_add_tail(&encl->encl_list, &encl->tgid_ctx->encl_list); + mutex_unlock(&sgx_tgid_ctx_mutex); + + return 0; +out: + if (encl) + kref_put(&encl->refcount, sgx_encl_release); + return ret; +} + +static int sgx_validate_secinfo(struct sgx_secinfo *secinfo) +{ + u64 perm = secinfo->flags & SGX_SECINFO_PERMISSION_MASK; + u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK; + int i; + + if ((secinfo->flags & SGX_SECINFO_RESERVED_MASK) || + ((perm & SGX_SECINFO_W) && !(perm & SGX_SECINFO_R)) || + (page_type != SGX_SECINFO_TCS && + page_type != SGX_SECINFO_REG)) + return -EINVAL; + + for (i = 0; i < sizeof(secinfo->reserved) / sizeof(u64); i++) + if (secinfo->reserved[i]) + return -EINVAL; + + return 0; +} + +static bool sgx_validate_offset(struct sgx_encl *encl, unsigned long offset) +{ + if (offset & (PAGE_SIZE - 1)) + return false; + + if (offset >= encl->size) + return false; + + return true; +} + +static int sgx_validate_tcs(struct sgx_encl *encl, struct sgx_tcs *tcs) +{ + int i; + + if (tcs->flags & SGX_TCS_RESERVED_MASK) { + sgx_dbg(encl, "%s: invalid TCS flags = 0x%lx\n", + __func__, (unsigned long)tcs->flags); + return -EINVAL; + } + + if (tcs->flags & SGX_TCS_DBGOPTIN) { + sgx_dbg(encl, "%s: DBGOPTIN TCS flag is set, EADD will clear it\n", + __func__); + return -EINVAL; + } + + if (!sgx_validate_offset(encl, tcs->ossa)) { + sgx_dbg(encl, "%s: invalid OSSA: 0x%lx\n", __func__, + (unsigned long)tcs->ossa); + return -EINVAL; + } + + if (!sgx_validate_offset(encl, tcs->ofsbase)) { + sgx_dbg(encl, "%s: invalid OFSBASE: 0x%lx\n", __func__, + (unsigned long)tcs->ofsbase); + return -EINVAL; + } + + if (!sgx_validate_offset(encl, tcs->ogsbase)) { + sgx_dbg(encl, "%s: invalid OGSBASE: 0x%lx\n", __func__, + (unsigned long)tcs->ogsbase); + return -EINVAL; + } + + if ((tcs->fslimit & 0xFFF) != 0xFFF) { + sgx_dbg(encl, "%s: invalid FSLIMIT: 0x%x\n", __func__, + tcs->fslimit); + return -EINVAL; + } + + if ((tcs->gslimit & 0xFFF) != 0xFFF) { + sgx_dbg(encl, "%s: invalid GSLIMIT: 0x%x\n", __func__, + tcs->gslimit); + return -EINVAL; + } + + for (i = 0; i < sizeof(tcs->reserved) / sizeof(u64); i++) + if (tcs->reserved[i]) + return -EINVAL; + + return 0; +} + +static int __sgx_encl_add_page(struct sgx_encl *encl, + struct sgx_encl_page *encl_page, + unsigned long addr, + void *data, + struct sgx_secinfo *secinfo, + unsigned int mrmask) +{ + u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK; + struct page *backing; + struct sgx_add_page_req *req = NULL; + int ret; + int empty; + void *backing_ptr; + + if (sgx_validate_secinfo(secinfo)) + return -EINVAL; + + if (page_type == SGX_SECINFO_TCS) { + ret = sgx_validate_tcs(encl, data); + if (ret) + return ret; + } + + ret = sgx_init_page(encl, encl_page, addr, 0); + if (ret) + return ret; + + mutex_lock(&encl->lock); + + if (encl->flags & (SGX_ENCL_INITIALIZED | SGX_ENCL_DEAD)) { + ret = -EINVAL; + goto out; + } + + if (radix_tree_lookup(&encl->page_tree, addr >> PAGE_SHIFT)) { + ret = -EEXIST; + goto out; + } + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) { + ret = -ENOMEM; + goto out; + } + + backing = sgx_get_backing(encl, encl_page, false); + if (IS_ERR((void *)backing)) { + ret = PTR_ERR((void *)backing); + goto out; + } + + ret = radix_tree_insert(&encl->page_tree, encl_page->addr >> PAGE_SHIFT, + encl_page); + if (ret) { + sgx_put_backing(backing, false /* write */); + goto out; + } + + backing_ptr = kmap(backing); + memcpy(backing_ptr, data, PAGE_SIZE); + kunmap(backing); + + if (page_type == SGX_SECINFO_TCS) + encl_page->flags |= SGX_ENCL_PAGE_TCS; + + memcpy(&req->secinfo, secinfo, sizeof(*secinfo)); + + req->encl = encl; + req->encl_page = encl_page; + req->mrmask = mrmask; + empty = list_empty(&encl->add_page_reqs); + kref_get(&encl->refcount); + list_add_tail(&req->list, &encl->add_page_reqs); + if (empty) + queue_work(sgx_add_page_wq, &encl->add_page_work); + + sgx_put_backing(backing, true /* write */); + + mutex_unlock(&encl->lock); + return 0; +out: + kfree(req); + sgx_free_va_slot(encl_page->va_page, encl_page->va_offset); + mutex_unlock(&encl->lock); + return ret; +} + +/** + * sgx_encl_add_page - add a page to the enclave + * + * @encl: an enclave + * @addr: page address in the ELRANGE + * @data: page data + * @secinfo: page permissions + * @mrmask: bitmask to select the 256 byte chunks to be measured + * + * Creates a new enclave page and enqueues an EADD operation that will be + * processed by a worker thread later on. + * + * Return: + * 0 on success, + * system error on failure + */ +int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr, void *data, + struct sgx_secinfo *secinfo, unsigned int mrmask) +{ + struct sgx_encl_page *page; + int ret; + + page = kzalloc(sizeof(*page), GFP_KERNEL); + if (!page) + return -ENOMEM; + + ret = __sgx_encl_add_page(encl, page, addr, data, secinfo, mrmask); + + if (ret) + kfree(page); + + return ret; +} + +static int sgx_einit(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, + struct sgx_einittoken *token) +{ + struct sgx_epc_page *secs_epc = encl->secs.epc_page; + void *secs_va; + int ret; + + secs_va = sgx_get_page(secs_epc); + ret = __einit(sigstruct, token, secs_va); + sgx_put_page(secs_va); + + return ret; +} + +/** + * sgx_encl_init - perform EINIT for the given enclave + * + * @encl: an enclave + * @sigstruct: SIGSTRUCT for the enclave + * @token: EINITTOKEN for the enclave + * + * Retries a few times in order to perform EINIT operation on an enclave + * because there could be potentially an interrupt storm. + * + * Return: + * 0 on success, + * -FAULT on a CPU exception during EINIT, + * SGX error code + */ +int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, + struct sgx_einittoken *token) +{ + int ret; + int i; + int j; + + flush_work(&encl->add_page_work); + + mutex_lock(&encl->lock); + + if (encl->flags & SGX_ENCL_INITIALIZED) { + mutex_unlock(&encl->lock); + return 0; + } + + for (i = 0; i < SGX_EINIT_SLEEP_COUNT; i++) { + for (j = 0; j < SGX_EINIT_SPIN_COUNT; j++) { + ret = sgx_einit(encl, sigstruct, token); + + if (ret == SGX_UNMASKED_EVENT) + continue; + else + break; + } + + if (ret != SGX_UNMASKED_EVENT) + break; + + msleep_interruptible(SGX_EINIT_SLEEP_TIME); + if (signal_pending(current)) { + mutex_unlock(&encl->lock); + return -ERESTARTSYS; + } + } + + mutex_unlock(&encl->lock); + + if (ret) { + if (ret > 0) + sgx_dbg(encl, "EINIT returned %d\n", ret); + return ret; + } + + encl->flags |= SGX_ENCL_INITIALIZED; + return 0; +} + +void sgx_encl_release(struct kref *ref) +{ + struct sgx_encl_page *entry; + struct sgx_va_page *va_page; + struct sgx_encl *encl = container_of(ref, struct sgx_encl, refcount); + struct radix_tree_iter iter; + void **slot; + + mutex_lock(&sgx_tgid_ctx_mutex); + if (!list_empty(&encl->encl_list)) + list_del(&encl->encl_list); + mutex_unlock(&sgx_tgid_ctx_mutex); + + if (encl->mmu_notifier.ops) + mmu_notifier_unregister_no_release(&encl->mmu_notifier, + encl->mm); + + radix_tree_for_each_slot(slot, &encl->page_tree, &iter, 0) { + entry = *slot; + if (entry->epc_page) { + list_del(&entry->epc_page->list); + sgx_free_page(entry->epc_page, encl); + } + radix_tree_delete(&encl->page_tree, entry->addr >> PAGE_SHIFT); + kfree(entry); + } + + while (!list_empty(&encl->va_pages)) { + va_page = list_first_entry(&encl->va_pages, + struct sgx_va_page, list); + list_del(&va_page->list); + sgx_free_page(va_page->epc_page, encl); + kfree(va_page); + atomic_dec(&sgx_va_pages_cnt); + } + + if (encl->secs.epc_page) + sgx_free_page(encl->secs.epc_page, encl); + + if (encl->tgid_ctx) + kref_put(&encl->tgid_ctx->refcount, sgx_tgid_ctx_release); + + if (encl->backing) + fput(encl->backing); + + if (encl->pcmd) + fput(encl->pcmd); + + kfree(encl); +} diff --git a/sgx_ioctl.c b/sgx_ioctl.c index 9cedfd3..f7540fc 100644 --- a/sgx_ioctl.c +++ b/sgx_ioctl.c @@ -4,7 +4,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -21,7 +21,7 @@ * * BSD LICENSE * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -64,7 +64,7 @@ #include #include #include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) #include #else #include @@ -73,820 +73,138 @@ #include #include -#define SGX_NR_MOD_CHUNK_PAGES 16 - -struct sgx_add_page_req { - struct sgx_encl *encl; - struct sgx_encl_page *encl_page; - struct sgx_secinfo secinfo; - u16 mrmask; - struct list_head list; -}; - -static u16 sgx_isvsvnle_min; -atomic_t sgx_nr_pids = ATOMIC_INIT(0); - -static struct sgx_tgid_ctx *sgx_find_tgid_ctx(struct pid *tgid) -{ - struct sgx_tgid_ctx *ctx; - - list_for_each_entry(ctx, &sgx_tgid_ctx_list, list) - if (pid_nr(ctx->tgid) == pid_nr(tgid)) - return ctx; - - return NULL; -} - -static int sgx_add_to_tgid_ctx(struct sgx_encl *encl) -{ - struct sgx_tgid_ctx *ctx; - struct pid *tgid = get_pid(task_tgid(current)); - - mutex_lock(&sgx_tgid_ctx_mutex); - - ctx = sgx_find_tgid_ctx(tgid); - if (ctx) { - if (kref_get_unless_zero(&ctx->refcount)) { - encl->tgid_ctx = ctx; - mutex_unlock(&sgx_tgid_ctx_mutex); - put_pid(tgid); - return 0; - } - else - list_del_init(&ctx->list); - } - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - mutex_unlock(&sgx_tgid_ctx_mutex); - put_pid(tgid); - return -ENOMEM; - } - - ctx->tgid = tgid; - kref_init(&ctx->refcount); - INIT_LIST_HEAD(&ctx->encl_list); - - list_add(&ctx->list, &sgx_tgid_ctx_list); - atomic_inc(&sgx_nr_pids); - - encl->tgid_ctx = ctx; - - mutex_unlock(&sgx_tgid_ctx_mutex); - return 0; -} - -void sgx_tgid_ctx_release(struct kref *ref) -{ - struct sgx_tgid_ctx *pe = - container_of(ref, struct sgx_tgid_ctx, refcount); - mutex_lock(&sgx_tgid_ctx_mutex); - list_del(&pe->list); - atomic_dec(&sgx_nr_pids); - mutex_unlock(&sgx_tgid_ctx_mutex); - put_pid(pe->tgid); - kfree(pe); -} - -static int sgx_find_and_get_encl(unsigned long addr, struct sgx_encl **encl) +static int sgx_get_encl(unsigned long addr, struct sgx_encl **encl) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; int ret; + if (addr & (PAGE_SIZE - 1)) + return -EINVAL; + down_read(&mm->mmap_sem); - ret = sgx_find_encl(mm, addr, &vma); + ret = sgx_encl_find(mm, addr, &vma); if (!ret) { *encl = vma->vm_private_data; - kref_get(&(*encl)->refcount); - } - up_read(&mm->mmap_sem); - - return ret; -} - -static int sgx_measure(struct sgx_epc_page *secs_page, - struct sgx_epc_page *epc_page, - u16 mrmask) -{ - void *secs; - void *epc; - int ret = 0; - int i, j; - - for (i = 0, j = 1; i < 0x1000 && !ret; i += 0x100, j <<= 1) { - if (!(j & mrmask)) - continue; - - secs = sgx_get_page(secs_page); - epc = sgx_get_page(epc_page); - - ret = __eextend(secs, (void *)((unsigned long)epc + i)); - - sgx_put_page(epc); - sgx_put_page(secs); + if ((*encl)->flags & SGX_ENCL_SUSPEND) + ret = SGX_POWER_LOST_ENCLAVE; + else + kref_get(&(*encl)->refcount); } + up_read(&mm->mmap_sem); return ret; } -static int sgx_add_page(struct sgx_epc_page *secs_page, - struct sgx_epc_page *epc_page, - unsigned long linaddr, - struct sgx_secinfo *secinfo, - struct page *backing) -{ - struct sgx_page_info pginfo; - void *epc_page_vaddr; - int ret; - - pginfo.srcpge = (unsigned long)kmap_atomic(backing); - pginfo.secs = (unsigned long)sgx_get_page(secs_page); - epc_page_vaddr = sgx_get_page(epc_page); - - pginfo.linaddr = linaddr; - pginfo.secinfo = (unsigned long)secinfo; - ret = __eadd(&pginfo, epc_page_vaddr); - - sgx_put_page(epc_page_vaddr); - sgx_put_page((void *)(unsigned long)pginfo.secs); - kunmap_atomic((void *)(unsigned long)pginfo.srcpge); - - return ret; -} - -static bool sgx_process_add_page_req(struct sgx_add_page_req *req) -{ - struct page *backing; - struct sgx_epc_page *epc_page; - struct sgx_encl_page *encl_page = req->encl_page; - struct sgx_encl *encl = req->encl; - struct vm_area_struct *vma; - int ret; - - epc_page = sgx_alloc_page(0); - if (IS_ERR(epc_page)) - return false; - - down_read(&encl->mm->mmap_sem); - - mutex_lock(&encl->lock); - - 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, false); - if (IS_ERR(backing)) - goto out; - - /* Do not race with do_exit() */ - if (!atomic_read(&encl->mm->mm_users)) { - sgx_put_backing(backing, 0); - goto out; - } - - ret = vm_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); - if (ret) - goto out; - - ret = sgx_add_page(encl->secs_page.epc_page, epc_page, - encl_page->addr, &req->secinfo, backing); - - sgx_put_backing(backing, 0); - if (ret) { - sgx_warn(encl, "EADD returned %d\n", ret); - zap_vma_ptes(vma, encl_page->addr, PAGE_SIZE); - goto out; - } - - encl->secs_child_cnt++; - - ret = sgx_measure(encl->secs_page.epc_page, epc_page, req->mrmask); - if (ret) { - sgx_warn(encl, "EEXTEND returned %d\n", ret); - zap_vma_ptes(vma, encl_page->addr, PAGE_SIZE); - goto out; - } - - encl_page->epc_page = epc_page; - sgx_test_and_clear_young(encl_page, encl); - list_add_tail(&encl_page->load_list, &encl->load_list); - encl_page->flags |= SGX_ENCL_PAGE_ADDED; - - mutex_unlock(&encl->lock); - up_read(&encl->mm->mmap_sem); - return true; -out: - sgx_free_page(epc_page, encl); - mutex_unlock(&encl->lock); - up_read(&encl->mm->mmap_sem); - return false; -} - -static void sgx_add_page_worker(struct work_struct *work) -{ - struct sgx_encl *encl; - struct sgx_add_page_req *req; - bool skip_rest = false; - bool is_empty = false; - - encl = container_of(work, struct sgx_encl, add_page_work); - - do { - schedule(); - - if (encl->flags & SGX_ENCL_DEAD) - skip_rest = true; - - mutex_lock(&encl->lock); - req = list_first_entry(&encl->add_page_reqs, - struct sgx_add_page_req, list); - list_del(&req->list); - is_empty = list_empty(&encl->add_page_reqs); - mutex_unlock(&encl->lock); - - if (!skip_rest) { - if (!sgx_process_add_page_req(req)) { - skip_rest = true; - sgx_dbg(encl, "EADD failed 0x%p\n", - (void *)req->encl_page->addr); - } - } - - kfree(req); - } while (!kref_put(&encl->refcount, sgx_encl_release) && - !is_empty); -} - -static int sgx_validate_secs(const struct sgx_secs *secs) -{ - u32 needed_ssaframesize = 1; - u32 tmp; - int i; - - if (secs->flags & SGX_SECS_A_RESERVED_MASK) - return -EINVAL; - - if (secs->flags & SGX_SECS_A_MODE64BIT) { -#ifdef CONFIG_X86_64 - if (secs->size > sgx_encl_size_max_64) - return -EINVAL; -#else - return -EINVAL; -#endif - } else { - /* On 64-bit architecture allow 32-bit encls only in - * the compatibility mode. - */ -#ifdef CONFIG_X86_64 - if (!test_thread_flag(TIF_ADDR32)) - return -EINVAL; -#endif - if (secs->size > sgx_encl_size_max_32) - return -EINVAL; - } - - if ((secs->xfrm & 0x3) != 0x3 || (secs->xfrm & ~sgx_xfrm_mask)) - return -EINVAL; - - /* Check that BNDREGS and BNDCSR are equal. */ - if (((secs->xfrm >> 3) & 1) != ((secs->xfrm >> 4) & 1)) - return -EINVAL; - - for (i = 2; i < 64; i++) { - tmp = sgx_ssaframesize_tbl[i]; - if (((1 << i) & secs->xfrm) && (tmp > needed_ssaframesize)) - needed_ssaframesize = tmp; - } - - if (!secs->ssaframesize || !needed_ssaframesize || - needed_ssaframesize > secs->ssaframesize) - return -EINVAL; - - /* Must be power of two */ - if (secs->size == 0 || (secs->size & (secs->size - 1)) != 0) - return -EINVAL; - - for (i = 0; i < SGX_SECS_RESERVED1_SIZE; i++) - if (secs->reserved1[i]) - return -EINVAL; - - for (i = 0; i < SGX_SECS_RESERVED2_SIZE; i++) - if (secs->reserved2[i]) - return -EINVAL; - - for (i = 0; i < SGX_SECS_RESERVED3_SIZE; i++) - if (secs->reserved3[i]) - return -EINVAL; - - for (i = 0; i < SGX_SECS_RESERVED4_SIZE; i++) - if (secs->reserved[i]) - return -EINVAL; - - return 0; -} - -static int sgx_init_page(struct sgx_encl *encl, - struct sgx_encl_page *entry, - unsigned long addr, - struct sgx_epc_page **va_src, - bool already_locked) -{ - struct sgx_va_page *va_page; - struct sgx_epc_page *epc_page = NULL; - unsigned int va_offset = PAGE_SIZE; - void *vaddr; - int ret = 0; - - list_for_each_entry(va_page, &encl->va_pages, list) { - va_offset = sgx_alloc_va_slot(va_page); - if (va_offset < PAGE_SIZE) - break; - } - - if (va_offset == PAGE_SIZE) { - va_page = kzalloc(sizeof(*va_page), GFP_KERNEL); - if (!va_page) - return -ENOMEM; - - if (va_src) { - epc_page = *va_src; - *va_src = NULL; - } else { - epc_page = sgx_alloc_page(0); - if (IS_ERR(epc_page)) { - kfree(va_page); - return PTR_ERR(epc_page); - } - } - - vaddr = sgx_get_page(epc_page); - if (!vaddr) { - sgx_warn(encl, "kmap of a new VA page failed %d\n", - ret); - sgx_free_page(epc_page, encl); - kfree(va_page); - return -EFAULT; - } - - ret = __epa(vaddr); - sgx_put_page(vaddr); - - if (ret) { - sgx_warn(encl, "EPA returned %d\n", ret); - sgx_free_page(epc_page, encl); - kfree(va_page); - return -EFAULT; - } - - va_page->epc_page = epc_page; - va_offset = sgx_alloc_va_slot(va_page); - - if (!already_locked) - mutex_lock(&encl->lock); - list_add(&va_page->list, &encl->va_pages); - if (!already_locked) - mutex_unlock(&encl->lock); - } - - entry->va_page = va_page; - entry->va_offset = va_offset; - entry->addr = addr; - - 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_DEAD; - 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 + * sgx_ioc_enclave_create - handler for %SGX_IOC_ENCLAVE_CREATE * @filep: open file to /dev/sgx * @cmd: the command value - * @arg: pointer to the struct sgx_enclave_create + * @arg: pointer to the &struct sgx_enclave_create + * + * Validates SECS attributes, allocates an EPC page for the SECS and performs + * ECREATE. * - * Creates meta-data for an enclave and executes ENCLS(ECREATE) + * Return: + * 0 on success, + * system error on failure */ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, unsigned long arg) { struct sgx_enclave_create *createp = (struct sgx_enclave_create *)arg; - unsigned long src = (unsigned long)createp->src; - struct sgx_page_info pginfo; - struct sgx_secinfo secinfo; - struct sgx_encl *encl = NULL; - struct sgx_secs *secs = NULL; - struct sgx_epc_page *secs_epc; - struct vm_area_struct *vma; - void *secs_vaddr = NULL; - struct file *backing; - struct file *pcmd; - long ret; + void __user *src = (void __user *)createp->src; + struct sgx_secs *secs; + int ret; secs = kzalloc(sizeof(*secs), GFP_KERNEL); if (!secs) return -ENOMEM; - ret = copy_from_user(secs, (void __user *)src, sizeof(*secs)); + ret = copy_from_user(secs, src, sizeof(*secs)); if (ret) { kfree(secs); return ret; } - if (sgx_validate_secs(secs)) { - kfree(secs); - return -EINVAL; - } - - backing = shmem_file_setup("dev/sgx", secs->size + PAGE_SIZE, - VM_NORESERVE); - if (IS_ERR(backing)) { - ret = PTR_ERR(backing); - goto out; - } - - pcmd = shmem_file_setup("dev/sgx", - (secs->size + PAGE_SIZE) >> 5, - VM_NORESERVE); - if (IS_ERR(pcmd)) { - fput(backing); - ret = PTR_ERR(pcmd); - goto out; - } - - encl = kzalloc(sizeof(*encl), GFP_KERNEL); - if (!encl) { - fput(backing); - fput(pcmd); - ret = -ENOMEM; - goto out; - } - - kref_init(&encl->refcount); - INIT_LIST_HEAD(&encl->add_page_reqs); - INIT_LIST_HEAD(&encl->va_pages); - INIT_RADIX_TREE(&encl->page_tree, GFP_KERNEL); - INIT_LIST_HEAD(&encl->load_list); - INIT_LIST_HEAD(&encl->encl_list); - mutex_init(&encl->lock); - INIT_WORK(&encl->add_page_work, sgx_add_page_worker); - - encl->mm = current->mm; - encl->base = secs->base; - encl->size = secs->size; - encl->backing = backing; - encl->pcmd = pcmd; - - secs_epc = sgx_alloc_page(0); - if (IS_ERR(secs_epc)) { - ret = PTR_ERR(secs_epc); - secs_epc = NULL; - goto out; - } - - encl->secs_page.epc_page = secs_epc; - - ret = sgx_add_to_tgid_ctx(encl); - if (ret) - goto out; - - ret = sgx_init_page(encl, &encl->secs_page, - encl->base + encl->size, NULL, false); - if (ret) - goto out; - - secs_vaddr = sgx_get_page(secs_epc); - - pginfo.srcpge = (unsigned long)secs; - pginfo.linaddr = 0; - pginfo.secinfo = (unsigned long)&secinfo; - pginfo.secs = 0; - memset(&secinfo, 0, sizeof(secinfo)); - ret = __ecreate((void *)&pginfo, secs_vaddr); - - sgx_put_page(secs_vaddr); - - if (ret) { - sgx_dbg(encl, "ECREATE returned %ld\n", ret); - ret = -EFAULT; - goto out; - } - - createp->src = (unsigned long)encl->base; - - if (secs->flags & SGX_SECS_A_DEBUG) - encl->flags |= SGX_ENCL_DEBUG; + ret = sgx_encl_create(secs); - - encl->mmu_notifier.ops = &sgx_mmu_notifier_ops; - ret = mmu_notifier_register(&encl->mmu_notifier, encl->mm); - if (ret) { - if (ret == -EINTR) - ret = -ERESTARTSYS; - encl->mmu_notifier.ops = NULL; - goto out; - } - - down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, secs->base); - if (!vma || vma->vm_ops != &sgx_vm_ops || - vma->vm_start != secs->base || - vma->vm_end != (secs->base + secs->size)) { - ret = -EINVAL; - up_write(¤t->mm->mmap_sem); - goto out; - } - vma->vm_private_data = encl; - up_write(¤t->mm->mmap_sem); - - mutex_lock(&sgx_tgid_ctx_mutex); - list_add_tail(&encl->encl_list, &encl->tgid_ctx->encl_list); - mutex_unlock(&sgx_tgid_ctx_mutex); - -out: - if (ret && encl) - kref_put(&encl->refcount, sgx_encl_release); kfree(secs); return ret; } -static int sgx_validate_secinfo(struct sgx_secinfo *secinfo) -{ - u64 perm = secinfo->flags & SGX_SECINFO_PERMISSION_MASK; - u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK; - int i; - - if ((secinfo->flags & SGX_SECINFO_RESERVED_MASK) || - ((perm & SGX_SECINFO_W) && !(perm & SGX_SECINFO_R)) || - (page_type != SGX_SECINFO_TCS && - page_type != SGX_SECINFO_REG)) - return -EINVAL; - - for (i = 0; i < sizeof(secinfo->reserved) / sizeof(u64); i++) - if (secinfo->reserved[i]) - return -EINVAL; - - return 0; -} - -static int sgx_validate_tcs(struct sgx_tcs *tcs) -{ - int i; - - /* If FLAGS is not zero, ECALL will fail. */ - if ((tcs->flags != 0) || - (tcs->ossa & (PAGE_SIZE - 1)) || - (tcs->ofsbase & (PAGE_SIZE - 1)) || - (tcs->ogsbase & (PAGE_SIZE - 1)) || - ((tcs->fslimit & 0xFFF) != 0xFFF) || - ((tcs->gslimit & 0xFFF) != 0xFFF)) - return -EINVAL; - - for (i = 0; i < sizeof(tcs->reserved) / sizeof(u64); i++) - if (tcs->reserved[i]) - return -EINVAL; - - return 0; -} - -static int __encl_add_page(struct sgx_encl *encl, - struct sgx_encl_page *encl_page, - struct sgx_enclave_add_page *addp, - struct sgx_secinfo *secinfo) -{ - u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK; - unsigned long src = (unsigned long)addp->src; - struct sgx_tcs *tcs; - struct page *backing; - struct sgx_add_page_req *req = NULL; - int ret; - int empty; - void *user_vaddr; - void *tmp_vaddr; - struct page *tmp_page; - - tmp_page = alloc_page(GFP_HIGHUSER); - if (!tmp_page) - return -ENOMEM; - - tmp_vaddr = kmap(tmp_page); - ret = copy_from_user((void *)tmp_vaddr, (void __user *)src, PAGE_SIZE); - kunmap(tmp_page); - if (ret) { - __free_page(tmp_page); - return -EFAULT; - } - - if (sgx_validate_secinfo(secinfo)) { - __free_page(tmp_page); - return -EINVAL; - } - - if (page_type == SGX_SECINFO_TCS) { - tcs = (struct sgx_tcs *)kmap(tmp_page); - ret = sgx_validate_tcs(tcs); - kunmap(tmp_page); - if (ret) { - __free_page(tmp_page); - return ret; - } - } - - ret = sgx_init_page(encl, encl_page, addp->addr, NULL, false); - if (ret) { - __free_page(tmp_page); - return -EINVAL; - } - - mutex_lock(&encl->lock); - - if (encl->flags & (SGX_ENCL_INITIALIZED | SGX_ENCL_DEAD)) { - ret = -EINVAL; - goto out; - } - - if (radix_tree_lookup(&encl->page_tree, addp->addr >> PAGE_SHIFT)) { - ret = -EEXIST; - goto out; - } - - req = kzalloc(sizeof(*req), GFP_KERNEL); - if (!req) { - ret = -ENOMEM; - goto out; - } - - backing = sgx_get_backing(encl, encl_page, false); - if (IS_ERR((void *)backing)) { - ret = PTR_ERR((void *)backing); - goto out; - } - - ret = radix_tree_insert(&encl->page_tree, encl_page->addr >> PAGE_SHIFT, - encl_page); - if (ret) { - sgx_put_backing(backing, false /* write */); - goto out; - } - - user_vaddr = kmap(backing); - tmp_vaddr = kmap(tmp_page); - memcpy(user_vaddr, tmp_vaddr, PAGE_SIZE); - kunmap(backing); - kunmap(tmp_page); - - if (page_type == SGX_SECINFO_TCS) - encl_page->flags |= SGX_ENCL_PAGE_TCS; - - memcpy(&req->secinfo, secinfo, sizeof(*secinfo)); - - req->encl = encl; - req->encl_page = encl_page; - req->mrmask = addp->mrmask; - empty = list_empty(&encl->add_page_reqs); - kref_get(&encl->refcount); - list_add_tail(&req->list, &encl->add_page_reqs); - if (empty) - queue_work(sgx_add_page_wq, &encl->add_page_work); - - sgx_put_backing(backing, true /* write */); -out: - - if (ret) { - kfree(req); - sgx_free_va_slot(encl_page->va_page, - encl_page->va_offset); - } - - mutex_unlock(&encl->lock); - __free_page(tmp_page); - return ret; -} - /** - * sgx_ioc_enclave_add_page - handler for SGX_IOC_ENCLAVE_ADD_PAGE + * sgx_ioc_enclave_add_page - handler for %SGX_IOC_ENCLAVE_ADD_PAGE * * @filep: open file to /dev/sgx * @cmd: the command value - * @arg: pointer to the struct sgx_enclave_add_page + * @arg: pointer to the &struct sgx_enclave_add_page + * + * Creates a new enclave page and enqueues an EADD operation that will be + * processed by a worker thread later on. * - * Creates meta-data for an enclave page and enqueues ENCLS(EADD) that will - * be processed by a worker thread later on. + * Return: + * 0 on success, + * system error on failure */ static long sgx_ioc_enclave_add_page(struct file *filep, unsigned int cmd, unsigned long arg) { struct sgx_enclave_add_page *addp = (void *)arg; unsigned long secinfop = (unsigned long)addp->secinfo; - struct sgx_encl *encl; - struct sgx_encl_page *page; struct sgx_secinfo secinfo; + struct sgx_encl *encl; + struct page *data_page; + void *data; int ret; - if (addp->addr & (PAGE_SIZE - 1)) - return -EINVAL; - - if (copy_from_user(&secinfo, (void __user *)secinfop, sizeof(secinfo))) - return -EFAULT; - - ret = sgx_find_and_get_encl(addp->addr, &encl); + ret = sgx_get_encl(addp->addr, &encl); if (ret) return ret; - if (addp->addr < encl->base || - addp->addr > (encl->base + encl->size - PAGE_SIZE)) { + if (copy_from_user(&secinfo, (void __user *)secinfop, + sizeof(secinfo))) { kref_put(&encl->refcount, sgx_encl_release); - return -EINVAL; + return -EFAULT; } - page = kzalloc(sizeof(*page), GFP_KERNEL); - if (!page) { + data_page = alloc_page(GFP_HIGHUSER); + if (!data_page) { kref_put(&encl->refcount, sgx_encl_release); return -ENOMEM; } - ret = __encl_add_page(encl, page, addp, &secinfo); - kref_put(&encl->refcount, sgx_encl_release); + data = kmap(data_page); + ret = copy_from_user((void *)data, (void __user *)addp->src, PAGE_SIZE); if (ret) - kfree(page); - - return ret; -} - -static int __sgx_encl_init(struct sgx_encl *encl, char *sigstruct, - struct sgx_einittoken *einittoken) -{ - int ret = SGX_UNMASKED_EVENT; - struct sgx_epc_page *secs_epc = encl->secs_page.epc_page; - void *secs_va = NULL; - int i; - int j; - - if (einittoken->valid && einittoken->isvsvnle < sgx_isvsvnle_min) - return SGX_LE_ROLLBACK; - - for (i = 0; i < SGX_EINIT_SLEEP_COUNT; i++) { - for (j = 0; j < SGX_EINIT_SPIN_COUNT; j++) { - mutex_lock(&encl->lock); - secs_va = sgx_get_page(secs_epc); - ret = __einit(sigstruct, einittoken, secs_va); - sgx_put_page(secs_va); - mutex_unlock(&encl->lock); - if (ret == SGX_UNMASKED_EVENT) - continue; - else - break; - } - - if (ret != SGX_UNMASKED_EVENT) - goto out; + goto out; - msleep_interruptible(SGX_EINIT_SLEEP_TIME); - if (signal_pending(current)) - return -ERESTARTSYS; - } + ret = sgx_encl_add_page(encl, addp->addr, data, &secinfo, addp->mrmask); + if (ret) + goto out; out: - if (ret) { - sgx_dbg(encl, "EINIT returned %d\n", ret); - } else { - encl->flags |= SGX_ENCL_INITIALIZED; - - if (einittoken->isvsvnle > sgx_isvsvnle_min) - sgx_isvsvnle_min = einittoken->isvsvnle; - } - + kref_put(&encl->refcount, sgx_encl_release); + kunmap(data_page); + __free_page(data_page); return ret; } /** - * sgx_ioc_enclave_init - handler for SGX_IOC_ENCLAVE_INIT + * sgx_ioc_enclave_init - handler for %SGX_IOC_ENCLAVE_INIT * * @filep: open file to /dev/sgx * @cmd: the command value - * @arg: pointer to the struct sgx_enclave_init + * @arg: pointer to the &struct sgx_enclave_init * - * Flushes the remaining enqueued ENCLS(EADD) operations and executes - * ENCLS(EINIT). Does a number of retries because EINIT might fail because of an - * interrupt storm. + * Flushes the remaining enqueued EADD operations and performs EINIT. + * + * Return: + * 0 on success, + * system error on failure */ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, unsigned long arg) @@ -895,7 +213,7 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, unsigned long sigstructp = (unsigned long)initp->sigstruct; unsigned long einittokenp = (unsigned long)initp->einittoken; unsigned long encl_id = initp->addr; - char *sigstruct; + struct sgx_sigstruct *sigstruct; struct sgx_einittoken *einittoken; struct sgx_encl *encl; struct page *initp_page; @@ -910,529 +228,26 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, ((unsigned long)sigstruct + PAGE_SIZE / 2); ret = copy_from_user(sigstruct, (void __user *)sigstructp, - SIGSTRUCT_SIZE); + sizeof(*sigstruct)); if (ret) - goto out_free_page; + goto out; ret = copy_from_user(einittoken, (void __user *)einittokenp, - EINITTOKEN_SIZE); + sizeof(*einittoken)); if (ret) - goto out_free_page; - - ret = sgx_find_and_get_encl(encl_id, &encl); - if (ret) - goto out_free_page; - - mutex_lock(&encl->lock); - if (encl->flags & SGX_ENCL_INITIALIZED) { - ret = -EINVAL; - mutex_unlock(&encl->lock); - goto out; - } - mutex_unlock(&encl->lock); - - flush_work(&encl->add_page_work); - - ret = __sgx_encl_init(encl, sigstruct, einittoken); -out: - kref_put(&encl->refcount, sgx_encl_release); -out_free_page: - kunmap(initp_page); - __free_page(initp_page); - return ret; -} - -/** - * sgx_augment_encl() - 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_augment_encl(struct vm_area_struct *vma, - unsigned long addr, - bool write) -{ - struct sgx_page_info 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_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, &va_page, true); + ret = sgx_get_encl(encl_id, &encl); 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_page, secs_epc_page, true); - if (ret) - goto out; - - encl->secs_page.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_page.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; - } - - 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->load_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; - - address = rg->start_addr; - end = address + rg->nr_pages * PAGE_SIZE; - - vma = sgx_find_vma(encl, address); - if (!vma) - 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); + ret = sgx_encl_init(encl, sigstruct, einittoken); - 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->load_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, *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(encl_page, tmp, &list, load_list) { - 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(encl_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; -} - -static 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_find_and_get_encl(rg->start_addr, &encl); - if (ret) { - pr_debug("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; -} - -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 need to be invoked after that. - * @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); -} -static 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; - - vma = sgx_find_vma(encl, address); - if (!vma) - 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->load_list); - 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; -} - -/** - * 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_find_and_get_encl(address, &encl); - if (ret) { - pr_debug("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_find_and_get_encl(address, &encl)) { - pr_debug("sgx: No enclave found at start address 0x%lx\n", - address); - return -EINVAL; - } - - ret = remove_page(encl, address, false); - if (ret) { - pr_debug("sgx: Failed to remove page, address=0x%lx ret=%d\n", - address, ret); - } - - kref_put(&encl->refcount, sgx_encl_release); +out: + kunmap(initp_page); + __free_page(initp_page); return ret; } @@ -1455,21 +270,6 @@ 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 7e22bcc..7ff3864 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -4,7 +4,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -21,7 +21,7 @@ * * BSD LICENSE * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -58,6 +58,7 @@ * Sean Christopherson */ +#include "asm/msr-index.h" #include "sgx.h" #include #include @@ -70,18 +71,17 @@ #include #define DRV_DESCRIPTION "Intel SGX Driver" -#define DRV_VERSION "0.11" - -#define ENCL_SIZE_MAX_64 (64ULL * 1024ULL * 1024ULL * 1024ULL) -#define ENCL_SIZE_MAX_32 (2ULL * 1024ULL * 1024ULL * 1024ULL) +#define DRV_VERSION "0.10" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR("Jarkko Sakkinen "); MODULE_VERSION(DRV_VERSION); #ifndef X86_FEATURE_SGX -#define X86_FEATURE_SGX (9 * 32 + 2) + #define X86_FEATURE_SGX (9 * 32 + 2) #endif +#define FEATURE_CONTROL_SGX_ENABLE (1<<18) + /* * Global data. */ @@ -90,11 +90,11 @@ struct workqueue_struct *sgx_add_page_wq; #define SGX_MAX_EPC_BANKS 8 struct sgx_epc_bank sgx_epc_banks[SGX_MAX_EPC_BANKS]; int sgx_nr_epc_banks; -u64 sgx_encl_size_max_32 = ENCL_SIZE_MAX_32; -u64 sgx_encl_size_max_64 = ENCL_SIZE_MAX_64; +u64 sgx_encl_size_max_32; +u64 sgx_encl_size_max_64; u64 sgx_xfrm_mask = 0x3; -u32 sgx_ssaframesize_tbl[64]; -bool sgx_has_sgx2; +u32 sgx_misc_reserved; +u32 sgx_xsave_size_tbl[64]; #ifdef CONFIG_COMPAT long sgx_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) @@ -159,91 +159,17 @@ static const struct file_operations sgx_fops = { }; static struct miscdevice sgx_dev = { + .minor = MISC_DYNAMIC_MINOR, .name = "isgx", .fops = &sgx_fops, .mode = 0666, }; -static int sgx_init_platform(void) -{ - unsigned int eax, ebx, ecx, edx; - unsigned long size; - int i; - - cpuid(0, &eax, &ebx, &ecx, &edx); - if (eax < SGX_CPUID) { - pr_err("intel_sgx: CPUID is missing the SGX leaf instruction\n"); - return -ENODEV; - } - - if (!boot_cpu_has(X86_FEATURE_SGX)) { - pr_err("intel_sgx: CPU is missing the SGX feature\n"); - return -ENODEV; - } - - cpuid_count(SGX_CPUID, 0x0, &eax, &ebx, &ecx, &edx); - if (!(eax & 1)) { - pr_err("intel_sgx: CPU does not support the SGX 1.0 instruction set\n"); - return -ENODEV; - } - - if (boot_cpu_has(X86_FEATURE_OSXSAVE)) { - cpuid_count(SGX_CPUID, 0x1, &eax, &ebx, &ecx, &edx); - sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx; - for (i = 2; i < 64; i++) { - cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx); - if ((1 << i) & sgx_xfrm_mask) - sgx_ssaframesize_tbl[i] = - (168 + eax + ebx + PAGE_SIZE - 1) / - PAGE_SIZE; - } - } - - cpuid_count(SGX_CPUID, 0x0, &eax, &ebx, &ecx, &edx); - if (edx & 0xFFFF) { -#ifdef CONFIG_X86_64 - sgx_encl_size_max_64 = 1ULL << ((edx >> 8) & 0xFF); -#endif - sgx_encl_size_max_32 = 1ULL << (edx & 0xFF); - } - - sgx_nr_epc_banks = 0; - do { - cpuid_count(SGX_CPUID, sgx_nr_epc_banks + 2, - &eax, &ebx, &ecx, &edx); - if (eax & 0xf) { - sgx_epc_banks[sgx_nr_epc_banks].start = - (((u64) (ebx & 0xfffff)) << 32) + - (u64) (eax & 0xfffff000); - size = (((u64) (edx & 0xfffff)) << 32) + - (u64) (ecx & 0xfffff000); - sgx_epc_banks[sgx_nr_epc_banks].end = - sgx_epc_banks[sgx_nr_epc_banks].start + size; - if (!sgx_epc_banks[sgx_nr_epc_banks].start) - return -ENODEV; - sgx_nr_epc_banks++; - } else { - break; - } - } while (sgx_nr_epc_banks < SGX_MAX_EPC_BANKS); - - /* There should be at least one EPC area or something is wrong. */ - if (!sgx_nr_epc_banks) { - WARN_ON(1); - return 1; - } - - return 0; -} - static int sgx_pm_suspend(struct device *dev) { struct sgx_tgid_ctx *ctx; struct sgx_encl *encl; - kthread_stop(ksgxswapd_tsk); - ksgxswapd_tsk = NULL; - list_for_each_entry(ctx, &sgx_tgid_ctx_list, list) { list_for_each_entry(encl, &ctx->encl_list, encl_list) { sgx_invalidate(encl, false); @@ -255,132 +181,148 @@ static int sgx_pm_suspend(struct device *dev) return 0; } -static int sgx_pm_resume(struct device *dev) -{ - ksgxswapd_tsk = kthread_run(ksgxswapd, NULL, "kswapd"); - return 0; -} - -static SIMPLE_DEV_PM_OPS(sgx_drv_pm, sgx_pm_suspend, sgx_pm_resume); +static SIMPLE_DEV_PM_OPS(sgx_drv_pm, sgx_pm_suspend, NULL); -static int sgx_dev_init(struct device *dev) +static int sgx_dev_init(struct device *parent) { - unsigned int wq_flags; + unsigned int eax, ebx, ecx, edx; + unsigned long pa; + unsigned long size; int ret; int i; pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n"); - if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) - return -ENODEV; + cpuid_count(SGX_CPUID, SGX_CPUID_CAPABILITIES, &eax, &ebx, &ecx, &edx); + /* Only allow misc bits supported by the driver. */ + sgx_misc_reserved = ~ebx | SGX_MISC_RESERVED_MASK; +#ifdef CONFIG_X86_64 + sgx_encl_size_max_64 = 1ULL << ((edx >> 8) & 0xFF); +#endif + sgx_encl_size_max_32 = 1ULL << (edx & 0xFF); - ret = sgx_init_platform(); - if (ret) - return ret; + if (boot_cpu_has(X86_FEATURE_OSXSAVE)) { + cpuid_count(SGX_CPUID, SGX_CPUID_ATTRIBUTES, &eax, &ebx, &ecx, + &edx); + sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx; + + for (i = 2; i < 64; i++) { + cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx); + if ((1 << i) & sgx_xfrm_mask) + sgx_xsave_size_tbl[i] = eax + ebx; + } + } + + for (i = 0; i < SGX_MAX_EPC_BANKS; i++) { + cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC_BANKS, &eax, &ebx, + &ecx, &edx); + if (!(eax & 0xf)) + break; + + pa = ((u64)(ebx & 0xfffff) << 32) + (u64)(eax & 0xfffff000); + size = ((u64)(edx & 0xfffff) << 32) + (u64)(ecx & 0xfffff000); + + dev_info(parent, "EPC bank 0x%lx-0x%lx\n", pa, pa + size); + + sgx_epc_banks[i].pa = pa; + sgx_epc_banks[i].size = size; + } - pr_info("intel_sgx: Number of EPCs %d\n", sgx_nr_epc_banks); + sgx_nr_epc_banks = i; for (i = 0; i < sgx_nr_epc_banks; i++) { - pr_info("intel_sgx: EPC memory range 0x%lx-0x%lx\n", - sgx_epc_banks[i].start, sgx_epc_banks[i].end); #ifdef CONFIG_X86_64 - sgx_epc_banks[i].mem = ioremap_cache(sgx_epc_banks[i].start, - sgx_epc_banks[i].end - sgx_epc_banks[i].start); - if (!sgx_epc_banks[i].mem) { + sgx_epc_banks[i].va = (unsigned long) + ioremap_cache(sgx_epc_banks[i].pa, + sgx_epc_banks[i].size); + if (!sgx_epc_banks[i].va) { sgx_nr_epc_banks = i; ret = -ENOMEM; goto out_iounmap; } #endif - ret = sgx_page_cache_init(sgx_epc_banks[i].start, - sgx_epc_banks[i].end - sgx_epc_banks[i].start); + ret = sgx_add_epc_bank(sgx_epc_banks[i].pa, + sgx_epc_banks[i].size, i); if (ret) { - sgx_nr_epc_banks = i+1; + sgx_nr_epc_banks = i + 1; goto out_iounmap; } } - wq_flags = WQ_UNBOUND | WQ_FREEZABLE; -#ifdef WQ_NON_REENETRANT - wq_flags |= WQ_NON_REENTRANT; -#endif - sgx_add_page_wq = alloc_workqueue("intel_sgx-add-page-wq", wq_flags, 1); + ret = sgx_page_cache_init(); + if (ret) + goto out_iounmap; + + sgx_add_page_wq = alloc_workqueue("intel_sgx-add-page-wq", + WQ_UNBOUND | WQ_FREEZABLE, 1); if (!sgx_add_page_wq) { pr_err("intel_sgx: alloc_workqueue() failed\n"); ret = -ENOMEM; goto out_iounmap; } - sgx_dev.parent = dev; + sgx_dev.parent = parent; ret = misc_register(&sgx_dev); if (ret) { pr_err("intel_sgx: misc_register() failed\n"); goto out_workqueue; } + if (ret) + goto out_workqueue; + return 0; out_workqueue: destroy_workqueue(sgx_add_page_wq); out_iounmap: #ifdef CONFIG_X86_64 for (i = 0; i < sgx_nr_epc_banks; i++) - iounmap(sgx_epc_banks[i].mem); + iounmap((void *)sgx_epc_banks[i].va); #endif return ret; } static atomic_t sgx_init_flag = ATOMIC_INIT(0); - static int sgx_drv_probe(struct platform_device *pdev) { unsigned int eax, ebx, ecx, edx; - int i; - - if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) - return -ENODEV; - + unsigned long fc; if (atomic_cmpxchg(&sgx_init_flag, 0, 1)) { pr_warn("intel_sgx: second initialization call skipped\n"); return 0; } - cpuid(0, &eax, &ebx, &ecx, &edx); - if (eax < SGX_CPUID) { - pr_err("intel_sgx: CPUID is missing the SGX leaf instruction\n"); + + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) return -ENODEV; - } if (!boot_cpu_has(X86_FEATURE_SGX)) { - pr_err("intel_sgx: CPU is missing the SGX feature\n"); + pr_err("intel_sgx: the CPU is missing SGX\n"); return -ENODEV; } - cpuid_count(SGX_CPUID, 0x0, &eax, &ebx, &ecx, &edx); - if (!(eax & 1)) { - pr_err("intel_sgx: CPU does not support the SGX 1.0 instruction set\n"); + rdmsrl(MSR_IA32_FEATURE_CONTROL, fc); + + if (!(fc & FEATURE_CONTROL_LOCKED)) { + pr_err("intel_sgx: the feature control MSR is not locked\n"); return -ENODEV; } - sgx_has_sgx2 = (eax & 2) != 0; + if (!(fc & FEATURE_CONTROL_SGX_ENABLE)) { + pr_err("intel_sgx: SGX is not enabled\n"); + return -ENODEV; + } - if (boot_cpu_has(X86_FEATURE_OSXSAVE)) { - cpuid_count(SGX_CPUID, 0x1, &eax, &ebx, &ecx, &edx); - sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx; - for (i = 2; i < 64; i++) { - cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx); - if ((1 << i) & sgx_xfrm_mask) - sgx_ssaframesize_tbl[i] = - (168 + eax + ebx + PAGE_SIZE - 1) / - PAGE_SIZE; - } + cpuid(0, &eax, &ebx, &ecx, &edx); + if (eax < SGX_CPUID) { + pr_err("intel_sgx: CPUID is missing the SGX leaf\n"); + return -ENODEV; } - cpuid_count(SGX_CPUID, 0x0, &eax, &ebx, &ecx, &edx); - if (edx & 0xFFFF) { -#ifdef CONFIG_X86_64 - sgx_encl_size_max_64 = 2ULL << (edx & 0xFF); -#endif - sgx_encl_size_max_32 = 2ULL << ((edx >> 8) & 0xFF); + cpuid_count(SGX_CPUID, SGX_CPUID_CAPABILITIES, &eax, &ebx, &ecx, &edx); + if (!(eax & 1)) { + pr_err("intel_sgx: CPU does not support the SGX1 instructions\n"); + return -ENODEV; } return sgx_dev_init(&pdev->dev); @@ -396,10 +338,11 @@ static int sgx_drv_remove(struct platform_device *pdev) } misc_deregister(&sgx_dev); + destroy_workqueue(sgx_add_page_wq); #ifdef CONFIG_X86_64 for (i = 0; i < sgx_nr_epc_banks; i++) - iounmap(sgx_epc_banks[i].mem); + iounmap((void *)sgx_epc_banks[i].va); #endif sgx_page_cache_teardown(); @@ -424,9 +367,6 @@ static struct platform_driver sgx_drv = { }, }; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) -module_platform_driver(sgx_drv); -#else static struct platform_device *pdev; int init_sgx_module(void) { @@ -446,6 +386,5 @@ void cleanup_sgx_module(void) module_init(init_sgx_module); module_exit(cleanup_sgx_module); -#endif MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sgx_page_cache.c b/sgx_page_cache.c index 728ad90..8472037 100644 --- a/sgx_page_cache.c +++ b/sgx_page_cache.c @@ -4,7 +4,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -21,7 +21,7 @@ * * BSD LICENSE * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -63,7 +63,7 @@ #include #include #include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) #include #else #include @@ -78,14 +78,14 @@ static DEFINE_SPINLOCK(sgx_free_list_lock); LIST_HEAD(sgx_tgid_ctx_list); DEFINE_MUTEX(sgx_tgid_ctx_mutex); +atomic_t sgx_va_pages_cnt = ATOMIC_INIT(0); static unsigned int sgx_nr_total_epc_pages; static unsigned int sgx_nr_free_pages; static unsigned int sgx_nr_low_pages = SGX_NR_LOW_EPC_PAGES_DEFAULT; static unsigned int sgx_nr_high_pages; -struct task_struct *ksgxswapd_tsk; +static struct task_struct *ksgxswapd_tsk; static DECLARE_WAIT_QUEUE_HEAD(ksgxswapd_waitq); - static int sgx_test_and_clear_young_cb(pte_t *ptep, pgtable_t token, unsigned long addr, void *data) { @@ -112,9 +112,14 @@ static int sgx_test_and_clear_young_cb(pte_t *ptep, pgtable_t token, */ int sgx_test_and_clear_young(struct sgx_encl_page *page, struct sgx_encl *encl) { - struct vm_area_struct *vma = sgx_find_vma(encl, page->addr); + struct vm_area_struct *vma; + int ret; - if (!vma) + ret = sgx_encl_find(encl->mm, page->addr, &vma); + if (ret) + return 0; + + if (encl != vma->vm_private_data) return 0; return apply_to_page_range(vma->vm_mm, page->addr, PAGE_SIZE, @@ -197,7 +202,7 @@ static void sgx_isolate_pages(struct sgx_encl *encl, struct list_head *dst, unsigned long nr_to_scan) { - struct sgx_encl_page *entry; + struct sgx_epc_page *entry; int i; mutex_lock(&encl->lock); @@ -210,70 +215,25 @@ static void sgx_isolate_pages(struct sgx_encl *encl, break; entry = list_first_entry(&encl->load_list, - struct sgx_encl_page, - load_list); + struct sgx_epc_page, + list); - if (!sgx_test_and_clear_young(entry, encl) && - !(entry->flags & SGX_ENCL_PAGE_RESERVED)) { - entry->flags |= SGX_ENCL_PAGE_RESERVED; - list_move_tail(&entry->load_list, dst); + if (!sgx_test_and_clear_young(entry->encl_page, encl) && + !(entry->encl_page->flags & SGX_ENCL_PAGE_RESERVED)) { + entry->encl_page->flags |= SGX_ENCL_PAGE_RESERVED; + list_move_tail(&entry->list, dst); } else { - list_move_tail(&entry->load_list, &encl->load_list); + list_move_tail(&entry->list, &encl->load_list); } } out: mutex_unlock(&encl->lock); } -static void sgx_eblock(struct sgx_encl *encl, - struct sgx_epc_page *epc_page) -{ - void *vaddr; - int ret; - - vaddr = sgx_get_page(epc_page); - ret = __eblock((unsigned long)vaddr); - sgx_put_page(vaddr); - - if (ret) { - sgx_crit(encl, "EBLOCK returned %d\n", ret); - sgx_invalidate(encl, true); - } - -} - -bool sgx_etrack(struct sgx_encl *encl, unsigned int epoch) -{ - void *epc; - int ret; - bool ipi = false; - - /* If someone already called etrack in the meantime */ - if (epoch < encl->shadow_epoch) - return false; - - epc = sgx_get_page(encl->secs_page.epc_page); - ret = __etrack(epc); - sgx_put_page(epc); - encl->shadow_epoch++; - - 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)); - ipi = true; - } else if (ret) { - sgx_crit(encl, "ETRACK returned %d\n", ret); - sgx_invalidate(encl, true); - } - - return ipi; -} - static int __sgx_ewb(struct sgx_encl *encl, struct sgx_encl_page *encl_page) { - struct sgx_page_info pginfo; + struct sgx_pageinfo pginfo; struct page *backing; struct page *pcmd; unsigned long pcmd_offset; @@ -353,41 +313,40 @@ static void sgx_evict_page(struct sgx_encl_page *entry, static void sgx_write_pages(struct sgx_encl *encl, struct list_head *src) { - struct sgx_encl_page *entry; - struct sgx_encl_page *tmp; + struct sgx_epc_page *entry; + struct sgx_epc_page *tmp; struct vm_area_struct *vma; + int ret; if (list_empty(src)) return; - entry = list_first_entry(src, struct sgx_encl_page, load_list); + entry = list_first_entry(src, struct sgx_epc_page, list); mutex_lock(&encl->lock); /* EBLOCK */ - list_for_each_entry_safe(entry, tmp, src, load_list) { - vma = sgx_find_vma(encl, entry->addr); - if (vma) { - zap_vma_ptes(vma, entry->addr, PAGE_SIZE); - } + list_for_each_entry_safe(entry, tmp, src, list) { + ret = sgx_encl_find(encl->mm, entry->encl_page->addr, &vma); + if (!ret && encl == vma->vm_private_data) + zap_vma_ptes(vma, entry->encl_page->addr, PAGE_SIZE); - sgx_eblock(encl, entry->epc_page); + sgx_eblock(encl, entry); } /* ETRACK */ - sgx_etrack(encl, encl->shadow_epoch); + sgx_etrack(encl); /* EWB */ while (!list_empty(src)) { - entry = list_first_entry(src, struct sgx_encl_page, - load_list); - list_del(&entry->load_list); - sgx_evict_page(entry, encl); + entry = list_first_entry(src, struct sgx_epc_page, list); + list_del(&entry->list); + sgx_evict_page(entry->encl_page, encl); encl->secs_child_cnt--; } if (!encl->secs_child_cnt && (encl->flags & SGX_ENCL_INITIALIZED)) { - sgx_evict_page(&encl->secs_page, encl); + sgx_evict_page(&encl->secs, encl); encl->flags |= SGX_ENCL_SECS_EVICTED; } @@ -418,12 +377,17 @@ static void sgx_swap_pages(unsigned long nr_to_scan) kref_put(&ctx->refcount, sgx_tgid_ctx_release); } -int ksgxswapd(void *p) +static int ksgxswapd(void *p) { + set_freezable(); + while (!kthread_should_stop()) { - wait_event_interruptible(ksgxswapd_waitq, - kthread_should_stop() || - sgx_nr_free_pages < sgx_nr_high_pages); + if (try_to_freeze()) + continue; + + wait_event_freezable(ksgxswapd_waitq, + kthread_should_stop() || + sgx_nr_free_pages < sgx_nr_high_pages); if (sgx_nr_free_pages < sgx_nr_high_pages) sgx_swap_pages(SGX_NR_SWAP_CLUSTER_MAX); @@ -433,7 +397,7 @@ int ksgxswapd(void *p) return 0; } -int sgx_page_cache_init(resource_size_t start, unsigned long size) +int sgx_add_epc_bank(resource_size_t start, unsigned long size, int bank) { unsigned long i; struct sgx_epc_page *new_epc_page, *entry; @@ -443,42 +407,53 @@ int sgx_page_cache_init(resource_size_t start, unsigned long size) new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL); if (!new_epc_page) goto err_freelist; - new_epc_page->pa = start + i; + new_epc_page->pa = (start + i) | bank; spin_lock(&sgx_free_list_lock); - list_add_tail(&new_epc_page->free_list, &sgx_free_list); + list_add_tail(&new_epc_page->list, &sgx_free_list); sgx_nr_total_epc_pages++; sgx_nr_free_pages++; spin_unlock(&sgx_free_list_lock); } - sgx_nr_high_pages = 2 * sgx_nr_low_pages; - ksgxswapd_tsk = kthread_run(ksgxswapd, NULL, "ksgxswapd"); - return 0; err_freelist: list_for_each_safe(parser, temp, &sgx_free_list) { spin_lock(&sgx_free_list_lock); - entry = list_entry(parser, struct sgx_epc_page, free_list); - list_del(&entry->free_list); + entry = list_entry(parser, struct sgx_epc_page, list); + list_del(&entry->list); spin_unlock(&sgx_free_list_lock); kfree(entry); } return -ENOMEM; } +int sgx_page_cache_init(void) +{ + struct task_struct *tmp; + + sgx_nr_high_pages = 2 * sgx_nr_low_pages; + + tmp = kthread_run(ksgxswapd, NULL, "ksgxswapd"); + if (!IS_ERR(tmp)) + ksgxswapd_tsk = tmp; + return PTR_ERR_OR_ZERO(tmp); +} + void sgx_page_cache_teardown(void) { struct sgx_epc_page *entry; struct list_head *parser, *temp; - if (ksgxswapd_tsk) + if (ksgxswapd_tsk) { kthread_stop(ksgxswapd_tsk); + ksgxswapd_tsk = NULL; + } spin_lock(&sgx_free_list_lock); list_for_each_safe(parser, temp, &sgx_free_list) { - entry = list_entry(parser, struct sgx_epc_page, free_list); - list_del(&entry->free_list); + entry = list_entry(parser, struct sgx_epc_page, list); + list_del(&entry->list); kfree(entry); } spin_unlock(&sgx_free_list_lock); @@ -492,8 +467,8 @@ static struct sgx_epc_page *sgx_alloc_page_fast(void) if (!list_empty(&sgx_free_list)) { entry = list_first_entry(&sgx_free_list, struct sgx_epc_page, - free_list); - list_del(&entry->free_list); + list); + list_del(&entry->list); sgx_nr_free_pages--; } @@ -523,6 +498,11 @@ struct sgx_epc_page *sgx_alloc_page(unsigned int flags) if (entry) break; + /* We need at minimum two pages for the #PF handler. */ + if (atomic_read(&sgx_va_pages_cnt) > + (sgx_nr_total_epc_pages - 2)) + return ERR_PTR(-ENOMEM); + if (flags & SGX_ALLOC_ATOMIC) { entry = ERR_PTR(-EBUSY); break; @@ -542,26 +522,18 @@ struct sgx_epc_page *sgx_alloc_page(unsigned int flags) return entry; } -EXPORT_SYMBOL(sgx_alloc_page); /** * sgx_free_page - free an EPC page * - * EREMOVE an EPC page and insert it back to the list of free pages. Optionally, - * an enclave can be given as a parameter. If the enclave is given, the - * resulting error is printed out loud as a critical error. It is an indicator - * of a driver bug if that would happen. - * - * If the enclave is not given as a parameter (like in the case when VMM uses - * this function)), it is fully up to the caller to deal with the return value, - * including printing it to the klog if it wants to do such a thing. + * EREMOVE an EPC page and insert it back to the list of free pages. + * If EREMOVE fails, the error is printed out loud as a critical error. + * It is an indicator of a driver bug if that would happen. * - * @entry: an EPC page - * @encl: the enclave who owns the EPC page (optional) - * - * Return: SGX error code + * @entry: any EPC page + * @encl: enclave that owns the given EPC page */ -int sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl) +void sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl) { void *epc; int ret; @@ -570,41 +542,26 @@ int sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl) ret = __eremove(epc); sgx_put_page(epc); - if (ret) { - if (encl) - sgx_crit(encl, "EREMOVE returned %d\n", ret); - - return ret; - } + if (ret) + sgx_crit(encl, "EREMOVE returned %d\n", ret); spin_lock(&sgx_free_list_lock); - list_add(&entry->free_list, &sgx_free_list); + list_add(&entry->list, &sgx_free_list); sgx_nr_free_pages++; spin_unlock(&sgx_free_list_lock); - - return 0; } -EXPORT_SYMBOL(sgx_free_page); void *sgx_get_page(struct sgx_epc_page *entry) { #ifdef CONFIG_X86_32 return kmap_atomic_pfn(PFN_DOWN(entry->pa)); #else - int i; - - for (i = 0; i < sgx_nr_epc_banks; i++) { - if (entry->pa < sgx_epc_banks[i].end && - entry->pa >= sgx_epc_banks[i].start) { - return sgx_epc_banks[i].mem + - (entry->pa - sgx_epc_banks[i].start); - } - } + int i = ((entry->pa) & ~PAGE_MASK); - return NULL; + return (void *)(sgx_epc_banks[i].va + + ((entry->pa & PAGE_MASK) - sgx_epc_banks[i].pa)); #endif } -EXPORT_SYMBOL(sgx_get_page); void sgx_put_page(void *epc_page_vaddr) { @@ -613,4 +570,3 @@ void sgx_put_page(void *epc_page_vaddr) #else #endif } -EXPORT_SYMBOL(sgx_put_page); diff --git a/sgx_user.h b/sgx_user.h index d268b45..a15f87b 100644 --- a/sgx_user.h +++ b/sgx_user.h @@ -53,8 +53,6 @@ * * Jarkko Sakkinen * Suresh Siddha - * Serge Ayoun - * Shay Katz-zamir */ #ifndef _UAPI_ASM_X86_SGX_H @@ -71,16 +69,6 @@ _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 @@ -99,10 +87,9 @@ #define SGX_CHILD_PRESENT 13 #define SGX_ENCLAVE_ACT 14 #define SGX_ENTRYEPOCH_LOCKED 15 -#define SGX_INVALID_LICENSE 16 +#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 @@ -119,7 +106,7 @@ */ struct sgx_enclave_create { __u64 src; -} __packed; +} __attribute__((__packed__)); /** * struct sgx_enclave_add_page - parameter structure for the @@ -134,41 +121,19 @@ struct sgx_enclave_add_page { __u64 src; __u64 secinfo; __u16 mrmask; -} __packed; +} __attribute__((__packed__)); /** * struct sgx_enclave_init - parameter structure for the * %SGX_IOC_ENCLAVE_INIT ioctl * @addr: address in the ELRANGE * @sigstruct: address for the page data - * @einittoken: address for the SECINFO data + * @einittoken: EINITTOKEN */ struct sgx_enclave_init { __u64 addr; __u64 sigstruct; __u64 einittoken; -} __packed; - -struct sgx_enclave_destroy { - __u64 addr; -} __packed; - - -/* - * SGX2.0 definitions - */ - -#define SGX_GROW_UP_FLAG 1 -#define SGX_GROW_DOWN_FLAG 2 - -struct sgx_range { - unsigned long start_addr; - unsigned int nr_pages; -}; - -struct sgx_modification_param { - struct sgx_range range; - unsigned long flags; -}; +} __attribute__((__packed__)); #endif /* _UAPI_ASM_X86_SGX_H */ diff --git a/sgx_util.c b/sgx_util.c index 16276f9..ff0e40a 100644 --- a/sgx_util.c +++ b/sgx_util.c @@ -4,7 +4,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -21,7 +21,7 @@ * * BSD LICENSE * - * Copyright(c) 2016 Intel Corporation. + * 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 @@ -61,12 +61,11 @@ #include "sgx.h" #include #include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) - #include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) + #include #else - #include + #include #endif -#include "linux/file.h" struct page *sgx_get_backing(struct sgx_encl *encl, struct sgx_encl_page *entry, @@ -101,23 +100,13 @@ void sgx_put_backing(struct page *backing_page, bool write) put_page(backing_page); } -struct vm_area_struct *sgx_find_vma(struct sgx_encl *encl, unsigned long addr) -{ - struct vm_area_struct *vma; - - vma = find_vma(encl->mm, addr); - if (vma && encl == vma->vm_private_data) - return vma; - - sgx_dbg(encl, "cannot find VMA at 0x%lx\n", addr); - return NULL; -} - void sgx_zap_tcs_ptes(struct sgx_encl *encl, struct vm_area_struct *vma) { + struct sgx_epc_page *tmp; struct sgx_encl_page *entry; - list_for_each_entry(entry, &encl->load_list, load_list) { + list_for_each_entry(tmp, &encl->load_list, list) { + entry = tmp->encl_page; if ((entry->flags & SGX_ENCL_PAGE_TCS) && entry->addr >= vma->vm_start && entry->addr < vma->vm_end) @@ -129,11 +118,12 @@ void sgx_invalidate(struct sgx_encl *encl, bool flush_cpus) { struct vm_area_struct *vma; unsigned long addr; + int ret; for (addr = encl->base; addr < (encl->base + encl->size); addr = vma->vm_end) { - vma = sgx_find_vma(encl, addr); - if (vma) + ret = sgx_encl_find(encl->mm, addr, &vma); + if (!ret && encl == vma->vm_private_data) sgx_zap_tcs_ptes(encl, vma); else break; @@ -145,7 +135,7 @@ void sgx_invalidate(struct sgx_encl *encl, bool flush_cpus) sgx_flush_cpus(encl); } -void sgx_ipi_cb(void *info) +static void sgx_ipi_cb(void *info) { } @@ -154,47 +144,15 @@ void sgx_flush_cpus(struct sgx_encl *encl) on_each_cpu_mask(mm_cpumask(encl->mm), sgx_ipi_cb, NULL, 1); } -/** - * sgx_find_encl - find an enclave - * @mm: mm struct of the current process - * @addr: address in the ELRANGE - * @vma: the VMA that is located in the given address - * - * Finds an enclave identified by the given address. Gives back the VMA, that is - * part of the enclave, located in that address. - */ -int sgx_find_encl(struct mm_struct *mm, unsigned long addr, - struct vm_area_struct **vma) -{ - struct sgx_encl *encl; - - *vma = find_vma(mm, addr); - if (!(*vma) || (*vma)->vm_ops != &sgx_vm_ops || - addr < (*vma)->vm_start) - return -EINVAL; - - encl = (*vma)->vm_private_data; - if (!encl) { - pr_debug("%s: VMA exists but there is no enclave at 0x%p\n", - __func__, (void *)addr); - return -EINVAL; - } - - if (encl->flags & SGX_ENCL_SUSPEND) - return SGX_POWER_LOST_ENCLAVE; - - return 0; -} - -int sgx_eldu(struct sgx_encl *encl, - struct sgx_encl_page *encl_page, - struct sgx_epc_page *epc_page, - bool is_secs) +static 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; unsigned long pcmd_offset; - struct sgx_page_info pginfo; + struct sgx_pageinfo pginfo; void *secs_ptr = NULL; void *epc_ptr; void *va_ptr; @@ -219,7 +177,7 @@ int sgx_eldu(struct sgx_encl *encl, } if (!is_secs) - secs_ptr = sgx_get_page(encl->secs_page.epc_page); + secs_ptr = sgx_get_page(encl->secs.epc_page); epc_ptr = sgx_get_page(epc_page); va_ptr = sgx_get_page(encl_page->va_page->epc_page); @@ -253,8 +211,8 @@ int sgx_eldu(struct sgx_encl *encl, } static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, - unsigned long addr, unsigned int flags, - struct vm_fault *vmf) + unsigned long addr, + unsigned int flags) { struct sgx_encl *encl = vma->vm_private_data; struct sgx_encl_page *entry; @@ -262,8 +220,6 @@ 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. @@ -274,14 +230,6 @@ 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_augment_encl(vma, addr, write); - goto out; - } - - /* No entry found can not happen in 'reloading an evicted page' - * flow. - */ if (!entry) { rc = -EFAULT; goto out; @@ -328,11 +276,11 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, goto out; } - rc = sgx_eldu(encl, &encl->secs_page, secs_epc_page, true); + rc = sgx_eldu(encl, &encl->secs, secs_epc_page, true); if (rc) goto out; - encl->secs_page.epc_page = secs_epc_page; + encl->secs.epc_page = secs_epc_page; encl->flags &= ~SGX_ENCL_SECS_EVICTED; /* Do not free */ @@ -351,6 +299,7 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, */ encl->secs_child_cnt++; + epc_page->encl_page = entry; entry->epc_page = epc_page; if (reserve) @@ -358,7 +307,7 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, /* Do not free */ epc_page = NULL; - list_add_tail(&entry->load_list, &encl->load_list); + list_add_tail(&entry->epc_page->list, &encl->load_list); rc = vm_insert_pfn(vma, entry->addr, PFN_DOWN(entry->epc_page->pa)); if (rc) { @@ -382,13 +331,12 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma, unsigned long addr, - unsigned int flags, - struct vm_fault *vmf) + unsigned int flags) { struct sgx_encl_page *entry; do { - entry = sgx_do_fault(vma, addr, flags, vmf); + entry = sgx_do_fault(vma, addr, flags); if (!(flags & SGX_FAULT_RESERVE)) break; } while (PTR_ERR(entry) == -EBUSY); @@ -396,54 +344,33 @@ struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma, return entry; } -void sgx_encl_release(struct kref *ref) +void sgx_eblock(struct sgx_encl *encl, struct sgx_epc_page *epc_page) { - struct sgx_encl_page *entry; - struct sgx_va_page *va_page; - struct sgx_encl *encl = container_of(ref, struct sgx_encl, refcount); - struct radix_tree_iter iter; - void **slot; - - mutex_lock(&sgx_tgid_ctx_mutex); - if (!list_empty(&encl->encl_list)) - list_del(&encl->encl_list); - mutex_unlock(&sgx_tgid_ctx_mutex); - - if (encl->mmu_notifier.ops) - mmu_notifier_unregister_no_release(&encl->mmu_notifier, - encl->mm); - - radix_tree_for_each_slot(slot, &encl->page_tree, &iter, 0) { - entry = *slot; - if (entry->epc_page) { - list_del(&entry->load_list); - sgx_free_page(entry->epc_page, encl); - } - radix_tree_delete(&encl->page_tree, entry->addr >> PAGE_SHIFT); - kfree(entry); - } - - while (!list_empty(&encl->va_pages)) { - va_page = list_first_entry(&encl->va_pages, - struct sgx_va_page, list); - list_del(&va_page->list); - sgx_free_page(va_page->epc_page, encl); - kfree(va_page); - } + void *vaddr; + int ret; - if (encl->secs_page.epc_page) - sgx_free_page(encl->secs_page.epc_page, encl); + vaddr = sgx_get_page(epc_page); + ret = __eblock((unsigned long)vaddr); + sgx_put_page(vaddr); - encl->secs_page.epc_page = NULL; + if (ret) { + sgx_crit(encl, "EBLOCK returned %d\n", ret); + sgx_invalidate(encl, true); + } - if (encl->tgid_ctx) - kref_put(&encl->tgid_ctx->refcount, sgx_tgid_ctx_release); +} - if (encl->backing) - fput(encl->backing); +void sgx_etrack(struct sgx_encl *encl) +{ + void *epc; + int ret; - if (encl->pcmd) - fput(encl->pcmd); + epc = sgx_get_page(encl->secs.epc_page); + ret = __etrack(epc); + sgx_put_page(epc); - kfree(encl); + 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 d76b948..dae9eb9 100644 --- a/sgx_vma.c +++ b/sgx_vma.c @@ -72,15 +72,10 @@ static void sgx_vma_open(struct vm_area_struct *vma) { struct sgx_encl *encl = vma->vm_private_data; + 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. */ @@ -90,11 +85,13 @@ static void sgx_vma_open(struct vm_area_struct *vma) static void sgx_vma_close(struct vm_area_struct *vma) { struct sgx_encl *encl = vma->vm_private_data; + if (!encl) return; mutex_lock(&encl->lock); 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); } @@ -116,7 +113,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, vmf); + entry = sgx_fault_page(vma, addr, 0); if (!IS_ERR(entry) || PTR_ERR(entry) == -EBUSY) return VM_FAULT_NOPAGE; @@ -215,7 +212,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, NULL); + SGX_FAULT_RESERVE); if (IS_ERR(entry)) { ret = PTR_ERR(entry); entry = NULL; From fc0cb151466bc6197506ab7e6dc5e3f516ca8d7a Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Mon, 27 Nov 2017 00:15:00 -0500 Subject: [PATCH 06/50] SGX 2.0 Implementation Rebased 2.0 patch applies to linux-sgx-driver:master commit-id 03435d33de0bcca6c5777f23ac161249b9158f1e Authors: Serge Ayoun Angie Chinchilla Shay Katz-zamir Cedric Xing Signed-off-by: Angie Chinchilla --- 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 #include #include +#include #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 + * 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 + * Angie Chinchilla + * Shay Katz-zamir + * Cedric Xing + */ + +#include "sgx.h" +#include +#include + +#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 #include -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 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, 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 #define DRV_DESCRIPTION "Intel SGX Driver" -#define DRV_VERSION "0.10" +#define DRV_VERSION "0.11" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR("Jarkko Sakkinen "); @@ -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 @@ static int sgx_eldu(struct sgx_encl *encl, 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 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, 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; From 7490f2e8c934e68b2c451bc79839afefff74eb50 Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Thu, 30 Nov 2017 16:14:33 -0500 Subject: [PATCH 07/50] check in sgx2.patch for latest rebase Signed-off-by: Angie Chinchilla --- inker2ext/sgx2.patch | 1076 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1076 insertions(+) create mode 100644 inker2ext/sgx2.patch diff --git a/inker2ext/sgx2.patch b/inker2ext/sgx2.patch new file mode 100644 index 0000000..b3ee708 --- /dev/null +++ b/inker2ext/sgx2.patch @@ -0,0 +1,1076 @@ +From fc0cb151466bc6197506ab7e6dc5e3f516ca8d7a Mon Sep 17 00:00:00 2001 +From: Angie Chinchilla +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 +Angie Chinchilla +Shay Katz-zamir +Cedric Xing + +Signed-off-by: Angie Chinchilla +--- + 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 + #include + #include ++#include + #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 ++ * 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 ++ * Angie Chinchilla ++ * Shay Katz-zamir ++ * Cedric Xing ++ */ ++ ++#include "sgx.h" ++#include ++#include ++ ++#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 + #include + +-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 + + #define DRV_DESCRIPTION "Intel SGX Driver" +-#define DRV_VERSION "0.10" ++#define DRV_VERSION "0.11" + + MODULE_DESCRIPTION(DRV_DESCRIPTION); + MODULE_AUTHOR("Jarkko Sakkinen "); +@@ -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 + From 1544cce64821f42a1d0111353926506537116cdd Mon Sep 17 00:00:00 2001 From: lzha101 Date: Wed, 27 Dec 2017 12:46:01 +0800 Subject: [PATCH 08/50] Update README Signed-off-by: Zhang Lili lili.z.zhang@intel.com --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index faa7cb6..b104739 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ The [linux-sgx-driver](https://github.com/01org/linux-sgx-driver) project hosts Within the linux-sgx-driver project, two versions of the out-of-tree driver are provided. Both versions are compatible with the linux-sgx PSW and SDK: - SGX 2.0 Linux Driver (sgx2) - * The sgx2 branch of the linux-sgx-driver project contains the SGX 2.0 Linux Driver. This driver has additional support for SGX 2.0-based features available in upcoming CPUs. This driver has the same behavior as the SGX Linux Driver (master) on CPUs without SGX 2.0 support. -- SGX Linux Driver (master) - * The master branch of the linux-sgx-driver project tracks the proposed upstream version of the SGX driver and does not yet support SGX 2.0-based features. + * The sgx2 branch of the linux-sgx-driver project contains the SGX 2.0 Linux Driver. This driver has additional support for SGX 2.0-based features available in upcoming CPUs. This driver has the same behavior as the SGX 1.5 Linux Driver (master) on CPUs without SGX 2.0 support. +- SGX 1.5 Linux Driver (master) + * The master branch of the linux-sgx-driver project tracks the proposed upstream version of the SGX 1.5 driver and does not yet support SGX 2.0-based features. License @@ -40,13 +40,15 @@ Build and Install the Intel(R) SGX Driver ### Prerequisites - Ensure that you have the following required operating systems: * Ubuntu* Desktop-16.04-LTS 64bits - * Red Hat Enterprise Linux Server release 7.2 64bits - * CentOS 7.3.1611 64bits + * Red Hat Enterprise Linux Server release 7.4 64bits + * CentOS 7.4.1708 64bits + * SUSE Linux Enterprise Server 12 64bits - Ensure that you have the following required hardware: - * 6th Generation Intel(R) Core(TM) Processor (code named Skylake) - * 7th Generation Intel(R) Core(TM) Processor (code named Kaby Lake) + * 6th Generation Intel(R) Core(TM) Processor or newer - Configure the system with the **SGX hardware enabled** option. +**Note:** Refer to [Intel SGX Programming reference guide](https://software.intel.com/sites/default/files/managed/48/88/329298-002.pdf) section 1.7.2 to make sure your cpu has the SGX feature. + ### Build the Intel(R) SGX Driver **Note:** To use the SGX 2.0 driver, checkout or download the sgx2 branch and then follow the build instructions. From 11f5228d670edac28fddd52702e55a0c2527bd1a Mon Sep 17 00:00:00 2001 From: lzha101 Date: Wed, 27 Dec 2017 16:27:15 +0800 Subject: [PATCH 09/50] Update README for SUSE Signed-off-by: Zhang Lili lili.z.zhang@intel.com --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b104739..92eae21 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,10 @@ On Red Hat Enterprise Linux Server or CentOS, need to run below command on each ``` $ sudo /sbin/modprobe isgx ``` +On SUSE, need to add '--allow-unsupported' flag when executing 'modprobe' command during the SGX driver intallation and on each reboot +``` +$ sudo /sbin/modprobe isgx --allow-unsupported +``` ### Uninstall the Intel(R) SGX Driver Before uninstall the Intel(R) SGX driver, make sure the aesmd service is stopped. See the topic, Start or Stop aesmd Service, on how to stop the aesmd service. From 1bf506e50c9c2baa9d3e55a276ee56a5c9157911 Mon Sep 17 00:00:00 2001 From: lzha101 Date: Thu, 11 Jan 2018 13:43:17 +0800 Subject: [PATCH 10/50] Update README.md Signed-off-by: Zhang Lili lili.z.zhang@intel.com --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 92eae21..2d094a2 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,8 @@ Build and Install the Intel(R) SGX Driver ### Prerequisites - Ensure that you have the following required operating systems: - * Ubuntu* Desktop-16.04-LTS 64bits + * Ubuntu* 16.04.3 LTS Desktop 64bits + * Ubuntu* 16.04.3 LTS Server 64bits * Red Hat Enterprise Linux Server release 7.4 64bits * CentOS 7.4.1708 64bits * SUSE Linux Enterprise Server 12 64bits @@ -47,7 +48,7 @@ Build and Install the Intel(R) SGX Driver * 6th Generation Intel(R) Core(TM) Processor or newer - Configure the system with the **SGX hardware enabled** option. -**Note:** Refer to [Intel SGX Programming reference guide](https://software.intel.com/sites/default/files/managed/48/88/329298-002.pdf) section 1.7.2 to make sure your cpu has the SGX feature. +**Note:** Refer to the *"Intel® SGX Resource Enumeration Leaves"* section in the [Intel SGX Programming reference guide](https://software.intel.com/sites/default/files/managed/48/88/329298-002.pdf) to make sure your cpu has the SGX feature. ### Build the Intel(R) SGX Driver **Note:** To use the SGX 2.0 driver, checkout or download the sgx2 branch and then follow the build instructions. From f25da30ce957af45809ec7aaa582ac970bd31d4c Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Mon, 22 Jan 2018 09:57:42 -0500 Subject: [PATCH 11/50] Update README.md Port README.md update from master --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 2d094a2..78812ed 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,30 @@ Build and Install the Intel(R) SGX Driver - Ensure that you have the following required hardware: * 6th Generation Intel(R) Core(TM) Processor or newer - Configure the system with the **SGX hardware enabled** option. +- To build the driver, the version of installed kernel headers must match the active kernel version on the system. + * On Ubuntu + * To check if matching kernel headers are installed: + ``` + $ dpkg-query -s linux-headers-$(uname -r) + ``` + * To install matching headers: + ``` + $ sudo apt-get install linux-headers-$(uname -r) + ``` + * On CentOS and RHEL + * To check if matching kernel headers are installed: + ``` + $ ls /usr/src/kernels/$(uname -r) + ``` + * To install matching headers: + ``` + $ sudo yum install kernel-devel + ``` + * After the above command, if the matching headers are still missing in /usr/src/kernels, try update kernel and reboot using commands below. Then choose updated kernel on boot menu. + ``` + $ sudo yum install kernel + $ sudo reboot + ``` **Note:** Refer to the *"Intel® SGX Resource Enumeration Leaves"* section in the [Intel SGX Programming reference guide](https://software.intel.com/sites/default/files/managed/48/88/329298-002.pdf) to make sure your cpu has the SGX feature. From 0ab94372659d80d8bd0b22f5daa415a9ea0b6b14 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 6 Apr 2018 13:07:48 -0700 Subject: [PATCH 12/50] intel_sgx: use mmu_notifier_unregister w/o "no_release" Replace the call to mmu_notifier_unregister_no_release() with a call to the basic mmu_notifier_unregister(). The no_release variant was not added until kernel 3.17 and using it prevents building the driver in Debian 8 (and earlier). Back when usge of the MMU notifier was added to the SGX driver, the MMU release callback, sgx_mmu_notifier_release(), included acquiring mmap_sem for read, i.e. down_read(&mm->mmap_sem). This caused a deadlock if we called mmu_notifier_unregister() in sgx_encl_release() because the semaphore is already write-locked by munmap(). Eventually we stopped acquiring mmap_sem in sgx_mmu_notifier_release(), but kept using the no_release unregister variant as invoking release on a dying enclave was unnecessary and added an extra lock/unlock sequence. TL;DR: Calling mmu_notifier_unregister_no_release() was necessary to avoid deadlock in an old incarnation of the driver, but the current driver plays nice with the release variant. Signed-off-by: Sean Christopherson --- sgx_encl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sgx_encl.c b/sgx_encl.c index ccab446..17f7035 100644 --- a/sgx_encl.c +++ b/sgx_encl.c @@ -965,8 +965,7 @@ 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); + mmu_notifier_unregister(&encl->mmu_notifier, encl->mm); radix_tree_for_each_slot(slot, &encl->page_tree, &iter, 0) { entry = *slot; From d1bf12614b7c8d38b8ac6992bbc2b54fa2673929 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Tue, 24 Apr 2018 09:47:04 -0400 Subject: [PATCH 13/50] Removing conflicting compilation flags Signed-off-by: Serge Ayoun --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c88f38c..6bb4cd8 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: - $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) CFLAGS_MODULE="-DDEBUG -g -O0" modules + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules install: default $(MAKE) INSTALL_MOD_DIR=kernel/drivers/intel/sgx -C $(KDIR) M=$(PWD) modules_install From e9c9d5b7024f87689e9d30afc13109e3615b74fb Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Mon, 20 Aug 2018 14:50:37 +0300 Subject: [PATCH 14/50] Calling PF handler from isolate_range was not protected: down_read(mmap_sem) added isolate_range does not always extract the right vma ptr: code fix Signed-off-by: Serge Ayoun --- sgx_encl2.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sgx_encl2.c b/sgx_encl2.c index 6a5556d..9628267 100644 --- a/sgx_encl2.c +++ b/sgx_encl2.c @@ -234,12 +234,15 @@ static int isolate_range(struct sgx_encl *encl, 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; + down_read(&encl->mm->mmap_sem); for (; address < end; address += PAGE_SIZE) { + ret = sgx_encl_find(encl->mm, address, &vma); + if (ret || encl != vma->vm_private_data) { + up_read(&encl->mm->mmap_sem); + return -EINVAL; + } + encl_page = ERR_PTR(-EBUSY); while (encl_page == ERR_PTR(-EBUSY)) /* bring back page in case it was evicted */ @@ -247,6 +250,7 @@ static int isolate_range(struct sgx_encl *encl, SGX_FAULT_RESERVE, NULL); if (IS_ERR(encl_page)) { + up_read(&encl->mm->mmap_sem); sgx_err(encl, "sgx: No page found at address 0x%lx\n", address); return PTR_ERR(encl_page); @@ -261,6 +265,7 @@ static int isolate_range(struct sgx_encl *encl, mutex_unlock(&encl->lock); } + up_read(&encl->mm->mmap_sem); return 0; } From d1e0393ab21919bd7be2ca59eb7f9da05ef26733 Mon Sep 17 00:00:00 2001 From: Angie Chinchilla Date: Wed, 17 Oct 2018 13:09:38 -0400 Subject: [PATCH 15/50] Update License.txt to 3-c BSD/GPL v2, to match src Signed-off-by: Angie Chinchilla --- License.txt | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/License.txt b/License.txt index 0defa1c..b11d116 100644 --- a/License.txt +++ b/License.txt @@ -1,4 +1,47 @@ +Copyright (C) 2018 Intel Corporation + +This software is licensed under +(a) a 3-clause BSD license; or alternatively +(b) the GPL v2 license + +-- A. BSD-3-Clause ---------------------------- +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. 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. +3. Neither the name of the copyright holder 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 HOLDER 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. + +-- B. GPL-2.0 ---------------------------- +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License, as published +by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . +------------------------------ -Intel(R) SGX driver is licensed under GNU General Public License, version 2 (GPL-2.0) -https://opensource.org/licenses/GPL-2.0 +SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) From d452d4f402372d1c6a8fc6fbc5d132d7a0fa77ff Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Mon, 29 Oct 2018 10:04:05 +0200 Subject: [PATCH 16/50] In order to cope with KSS feature: . Updating sgx_secs structure to reflect configid and configsvn members. . Releasing SGX_ATTR_RESERVED bit mask 7. Signed-off-by: Serge Ayoun --- sgx_arch.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sgx_arch.h b/sgx_arch.h index a609fd6..1c77f5f 100644 --- a/sgx_arch.h +++ b/sgx_arch.h @@ -74,12 +74,12 @@ enum sgx_attribute { SGX_ATTR_EINITTOKENKEY = 0x20, }; -#define SGX_ATTR_RESERVED_MASK 0xFFFFFFFFFFFFFFC9L +#define SGX_ATTR_RESERVED_MASK 0xFFFFFFFFFFFFFF49L #define SGX_SECS_RESERVED1_SIZE 24 #define SGX_SECS_RESERVED2_SIZE 32 -#define SGX_SECS_RESERVED3_SIZE 96 -#define SGX_SECS_RESERVED4_SIZE 3836 +#define SGX_SECS_RESERVED3_SIZE 32 +#define SGX_SECS_RESERVED4_SIZE 3834 struct sgx_secs { uint64_t size; @@ -92,9 +92,11 @@ struct sgx_secs { uint32_t mrenclave[8]; uint8_t reserved2[SGX_SECS_RESERVED2_SIZE]; uint32_t mrsigner[8]; + uint32_t configid[16]; uint8_t reserved3[SGX_SECS_RESERVED3_SIZE]; uint16_t isvvprodid; uint16_t isvsvn; + uint16_t configsvn; uint8_t reserved4[SGX_SECS_RESERVED4_SIZE]; }; From b51ecbfc9991690d463659f36f1b1248d7b146b5 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Thu, 24 Jan 2019 15:36:42 +0000 Subject: [PATCH 17/50] vm_insert_pfn replaced by vmf_insert_pfn from kernel 4.20 Signed-off-by: Serge Ayoun --- sgx_encl.c | 4 ++++ sgx_encl2.c | 4 ++++ sgx_util.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/sgx_encl.c b/sgx_encl.c index 17f7035..8d7680f 100644 --- a/sgx_encl.c +++ b/sgx_encl.c @@ -250,7 +250,11 @@ static bool sgx_process_add_page_req(struct sgx_add_page_req *req, return false; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + ret = vmf_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); +#else ret = vm_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); +#endif if (ret) { sgx_put_backing(backing, 0); return false; diff --git a/sgx_encl2.c b/sgx_encl2.c index 9628267..8e6fa9b 100644 --- a/sgx_encl2.c +++ b/sgx_encl2.c @@ -169,7 +169,11 @@ struct sgx_encl_page *sgx_encl_augment(struct vm_area_struct *vma, goto out; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + ret = vmf_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); +#else ret = vm_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); +#endif sgx_put_page(epc_va); sgx_put_page(secs_va); if (ret) { diff --git a/sgx_util.c b/sgx_util.c index fd5022a..9faa59b 100644 --- a/sgx_util.c +++ b/sgx_util.c @@ -319,7 +319,11 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, epc_page = NULL; list_add_tail(&entry->epc_page->list, &encl->load_list); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + rc = vmf_insert_pfn(vma, entry->addr, PFN_DOWN(entry->epc_page->pa)); +#else rc = vm_insert_pfn(vma, entry->addr, PFN_DOWN(entry->epc_page->pa)); +#endif if (rc) { /* Kill the enclave if vm_insert_pfn fails; failure only occurs * if there is a driver bug or an unrecoverable issue, e.g. OOM. From aa765e15d29d5df7c8f24134661e5104aeb5dd59 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Sun, 3 Feb 2019 16:57:12 +0000 Subject: [PATCH 18/50] Enclave virtual address range should never be defined as MAP_PRIVATE. Signed-off-by: Serge Ayoun --- sgx_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sgx_main.c b/sgx_main.c index 7b7c384..da540bb 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -119,7 +120,7 @@ static unsigned long sgx_get_unmapped_area(struct file *file, unsigned long pgoff, unsigned long flags) { - if (len < 2 * PAGE_SIZE || (len & (len - 1))) + if (len < 2 * PAGE_SIZE || (len & (len - 1)) || flags & MAP_PRIVATE) return -EINVAL; /* On 64-bit architecture, allow mmap() to exceed 32-bit encl From 56b7f9e5d6761692d5566a17535e9dd4712762e4 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Tue, 5 Feb 2019 09:38:12 +0000 Subject: [PATCH 19/50] Kernel 4.20 and later: vmf_insert_pfn returns VM_FAULT_NOPAGE in success case Signed-off-by: Serge Ayoun --- sgx_encl.c | 3 ++- sgx_encl2.c | 5 ++++- sgx_util.c | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sgx_encl.c b/sgx_encl.c index 8d7680f..a03c30a 100644 --- a/sgx_encl.c +++ b/sgx_encl.c @@ -252,10 +252,11 @@ static bool sgx_process_add_page_req(struct sgx_add_page_req *req, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) ret = vmf_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); + if (ret != VM_FAULT_NOPAGE) { #else ret = vm_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); -#endif if (ret) { +#endif sgx_put_backing(backing, 0); return false; } diff --git a/sgx_encl2.c b/sgx_encl2.c index 8e6fa9b..0df9b00 100644 --- a/sgx_encl2.c +++ b/sgx_encl2.c @@ -171,12 +171,15 @@ struct sgx_encl_page *sgx_encl_augment(struct vm_area_struct *vma, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) ret = vmf_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); + sgx_put_page(epc_va); + sgx_put_page(secs_va); + if (ret != VM_FAULT_NOPAGE) { #else ret = vm_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); -#endif sgx_put_page(epc_va); sgx_put_page(secs_va); if (ret) { +#endif pr_err("sgx: vm_insert_pfn failure with ret=%d\n", ret); goto out; } diff --git a/sgx_util.c b/sgx_util.c index 9faa59b..e9742d3 100644 --- a/sgx_util.c +++ b/sgx_util.c @@ -321,10 +321,11 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) rc = vmf_insert_pfn(vma, entry->addr, PFN_DOWN(entry->epc_page->pa)); + if (rc != VM_FAULT_NOPAGE) { #else rc = vm_insert_pfn(vma, entry->addr, PFN_DOWN(entry->epc_page->pa)); -#endif if (rc) { +#endif /* Kill the enclave if vm_insert_pfn fails; failure only occurs * if there is a driver bug or an unrecoverable issue, e.g. OOM. */ From 24011ecbf94be1204d881155e023b6271233a8b5 Mon Sep 17 00:00:00 2001 From: "Iyer, Naveen" Date: Mon, 22 Apr 2019 18:22:22 -0700 Subject: [PATCH 20/50] sgx_vma: return unsigned int from sgx_vma_fault For kernel v5.1.x, compiling the out-of-tree 'isgx' driver led to the following error: sgx_vma.c:241:11: error: initialization of 'vm_fault_t (*)(struct vm_fault *)' {aka 'unsigned int (*)(struct vm_fault *)'} from incompatible pointer type 'int (*)(struct vm_fault *)' [-Werror=incompatible-pointer-types] Hence, added return type of unsigned int to sgx_vma_fault for kernel v5.1. Signed-off-by: Iyer, Naveen --- sgx_vma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sgx_vma.c b/sgx_vma.c index dae9eb9..0c8392f 100644 --- a/sgx_vma.c +++ b/sgx_vma.c @@ -96,7 +96,11 @@ static void sgx_vma_close(struct vm_area_struct *vma) kref_put(&encl->refcount, sgx_encl_release); } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,1,0)) +static unsigned int sgx_vma_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) static int sgx_vma_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; From d076fc3515e6fc705495ec97b4c8ed89edd157f3 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Thu, 2 May 2019 11:23:08 +0300 Subject: [PATCH 21/50] For kernel 5.1 and higher, sgx_vma_fault returns unsigned int. Change propagated from master branch. Signed-off-by: Serge Ayoun --- sgx_vma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sgx_vma.c b/sgx_vma.c index bcd1047..34ec7bb 100644 --- a/sgx_vma.c +++ b/sgx_vma.c @@ -102,7 +102,11 @@ static void sgx_vma_close(struct vm_area_struct *vma) kref_put(&encl->refcount, sgx_encl_release); } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,1,0)) +static unsigned int sgx_vma_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) static int sgx_vma_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; From d8621de0dac963df4a3207460ef952d1e5152b40 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Mon, 6 May 2019 15:17:39 +0300 Subject: [PATCH 22/50] Version number is 2.5.0 Signed-off-by: Serge Ayoun --- sgx_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sgx_main.c b/sgx_main.c index da540bb..ebbb168 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -72,7 +72,7 @@ #include #define DRV_DESCRIPTION "Intel SGX Driver" -#define DRV_VERSION "0.11" +#define DRV_VERSION "2.5.0" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR("Jarkko Sakkinen "); From 44adf289ead269f8d56a99ef5980decc3c74707c Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Wed, 15 May 2019 15:31:52 +0300 Subject: [PATCH 23/50] Resetting rc after calling vmf_insert_pfn since it returns VM_FAULT_NOPAGE upon success and for kernels 4.20 and later Signed-off-by: Serge Ayoun --- sgx_util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sgx_util.c b/sgx_util.c index e9742d3..25b18a9 100644 --- a/sgx_util.c +++ b/sgx_util.c @@ -334,6 +334,7 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, goto out; } + rc = 0; sgx_test_and_clear_young(entry, encl); out: mutex_unlock(&encl->lock); From dc891dbd9367308b84ac9bc8e4169d1492a51970 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Wed, 15 May 2019 15:57:36 +0300 Subject: [PATCH 24/50] README file updated: master branch (SGX 1.5) not supported anymore. Branch sgx2 (SGX 1.5 and SGX 2.0) should be used from now. Signed-off-by: Serge Ayoun --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 23b10f7..381c9d9 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,14 @@ The Linux SGX software stack is comprised of the Intel(R) SGX driver, the Intel( The [linux-sgx-driver](https://github.com/01org/linux-sgx-driver) project hosts the out-of-tree driver for the Linux Intel(R) SGX software stack, which will be used until the driver upstreaming process is complete. Within the linux-sgx-driver project, two versions of the out-of-tree driver are provided. Both versions are compatible with the linux-sgx PSW and SDK: -- SGX 2.0 Linux Driver (sgx2) +- SGX 2.0 Linux Driver (sgx2 branch) * The sgx2 branch of the linux-sgx-driver project contains the SGX 2.0 Linux Driver. This driver has additional support for SGX 2.0-based features available in upcoming CPUs. This driver has the same behavior as the SGX 1.5 Linux Driver (master) on CPUs without SGX 2.0 support. -- SGX 1.5 Linux Driver (master) +- SGX 1.5 Linux Driver (master branch) * The master branch of the linux-sgx-driver project tracks the proposed upstream version of the SGX 1.5 driver and does not yet support SGX 2.0-based features. +IMPORTANT: +--------- +Starting from 5/10/2019, the master branch (which supports only SGX 1.5-based features) is deprecated and is not supported anymore. Please use the sgx2 branch; it is a super set of the master branch. License ------- From fbbc01ae8c337d546c61afa2a902bf62e2a438b5 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Wed, 15 May 2019 16:02:59 +0300 Subject: [PATCH 25/50] README file updated: master branch (SGX 1.5) not supported anymore. Branch sgx2 (SGX 1.5 and SGX 2.0) should be used from now. Signed-off-by: Serge Ayoun --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 78812ed..381c9d9 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,14 @@ The Linux SGX software stack is comprised of the Intel(R) SGX driver, the Intel( The [linux-sgx-driver](https://github.com/01org/linux-sgx-driver) project hosts the out-of-tree driver for the Linux Intel(R) SGX software stack, which will be used until the driver upstreaming process is complete. Within the linux-sgx-driver project, two versions of the out-of-tree driver are provided. Both versions are compatible with the linux-sgx PSW and SDK: -- SGX 2.0 Linux Driver (sgx2) +- SGX 2.0 Linux Driver (sgx2 branch) * The sgx2 branch of the linux-sgx-driver project contains the SGX 2.0 Linux Driver. This driver has additional support for SGX 2.0-based features available in upcoming CPUs. This driver has the same behavior as the SGX 1.5 Linux Driver (master) on CPUs without SGX 2.0 support. -- SGX 1.5 Linux Driver (master) +- SGX 1.5 Linux Driver (master branch) * The master branch of the linux-sgx-driver project tracks the proposed upstream version of the SGX 1.5 driver and does not yet support SGX 2.0-based features. +IMPORTANT: +--------- +Starting from 5/10/2019, the master branch (which supports only SGX 1.5-based features) is deprecated and is not supported anymore. Please use the sgx2 branch; it is a super set of the master branch. License ------- @@ -32,7 +35,7 @@ The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch i Documentation ------------- - [Intel(R) SGX for Linux\* OS](https://01.org/intel-softwareguard-extensions) project home page on [01.org](http://01.org) -- [Intel(R) SGX Programming Reference](https://software.intel.com/sites/default/files/managed/48/88/329298-002.pdf) +- [Intel(R) SGX Programming Reference](https://software.intel.com/en-us/articles/intel-sdm) Build and Install the Intel(R) SGX Driver ----------------------------------------- @@ -66,13 +69,15 @@ Build and Install the Intel(R) SGX Driver ``` $ sudo yum install kernel-devel ``` - * After the above command, if the matching headers are still missing in /usr/src/kernels, try update kernel and reboot using commands below. Then choose updated kernel on boot menu. + * After the above command, if the matching headers are still missing in /usr/src/kernels, try update kernel and reboot usig commands below. Then choose updated kernel on boot menu. ``` $ sudo yum install kernel $ sudo reboot ``` -**Note:** Refer to the *"Intel® SGX Resource Enumeration Leaves"* section in the [Intel SGX Programming reference guide](https://software.intel.com/sites/default/files/managed/48/88/329298-002.pdf) to make sure your cpu has the SGX feature. + +**Note:** Refer to the *"Intel® SGX Resource Enumeration Leaves"* section in the [Intel SGX Programming reference guide](https://software.intel.com/en-us/articles/intel-sdm) to make sure your cpu has the SGX feature. + ### Build the Intel(R) SGX Driver **Note:** To use the SGX 2.0 driver, checkout or download the sgx2 branch and then follow the build instructions. @@ -95,7 +100,7 @@ $ sudo /sbin/modprobe isgx On Red Hat Enterprise Linux Server or CentOS, need to run below command on each reboot ``` $ sudo /sbin/modprobe isgx -``` +``` On SUSE, need to add '--allow-unsupported' flag when executing 'modprobe' command during the SGX driver intallation and on each reboot ``` $ sudo /sbin/modprobe isgx --allow-unsupported From b34df8936a95fc619c68ea7bf7bae253b65edf8e Mon Sep 17 00:00:00 2001 From: Zhang Lili Z Date: Thu, 30 May 2019 18:47:03 +0800 Subject: [PATCH 26/50] Fix configid offset in secs. Signed-off-by: Zhang Lili Z --- sgx_arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sgx_arch.h b/sgx_arch.h index 1c77f5f..c90c11d 100644 --- a/sgx_arch.h +++ b/sgx_arch.h @@ -92,8 +92,8 @@ struct sgx_secs { uint32_t mrenclave[8]; uint8_t reserved2[SGX_SECS_RESERVED2_SIZE]; uint32_t mrsigner[8]; - uint32_t configid[16]; uint8_t reserved3[SGX_SECS_RESERVED3_SIZE]; + uint32_t configid[16]; uint16_t isvvprodid; uint16_t isvsvn; uint16_t configsvn; From 41c7e7fbb55207e6c21f77d3e0b9bd7da059fbd8 Mon Sep 17 00:00:00 2001 From: Serge Ayoun Date: Thu, 25 Jul 2019 05:26:34 -0400 Subject: [PATCH 27/50] elfutils-libelf-devel is a prerequisite for RedHat 8.0 README file updated Signed-off-by: Serge Ayoun --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 381c9d9..5bcfcda 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Build and Install the Intel(R) SGX Driver * Ubuntu* 16.04.3 LTS Desktop 64bits * Ubuntu* 16.04.3 LTS Server 64bits * Red Hat Enterprise Linux Server release 7.4 64bits + * Red Hat Enterprise Linux Server release 8.0 64bits * CentOS 7.4.1708 64bits * SUSE Linux Enterprise Server 12 64bits - Ensure that you have the following required hardware: @@ -74,6 +75,10 @@ Build and Install the Intel(R) SGX Driver $ sudo yum install kernel $ sudo reboot ``` + * On RHEL 8.0 elfutils-libelf-devel package is required: + ``` + $ sudo yum install elfutils-libelf-devel + ``` **Note:** Refer to the *"Intel® SGX Resource Enumeration Leaves"* section in the [Intel SGX Programming reference guide](https://software.intel.com/en-us/articles/intel-sdm) to make sure your cpu has the SGX feature. From ff88f3d0eceeeac8aa53517f69479bb2a9d5c8d3 Mon Sep 17 00:00:00 2001 From: Ayoun Serge Date: Mon, 12 Aug 2019 14:34:01 +0300 Subject: [PATCH 28/50] Ubuntu 18.04 support added to README Signed-off-by: Ayoun Serge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5bcfcda..30ee4b3 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ Build and Install the Intel(R) SGX Driver - Ensure that you have the following required operating systems: * Ubuntu* 16.04.3 LTS Desktop 64bits * Ubuntu* 16.04.3 LTS Server 64bits + * Ubuntu* 18.04 LTS Desktop 64bits + * Ubuntu* 18.04 LTS Server 64bits * Red Hat Enterprise Linux Server release 7.4 64bits * Red Hat Enterprise Linux Server release 8.0 64bits * CentOS 7.4.1708 64bits From efcde02427d53df61afbddc4d19b99dab128d0d0 Mon Sep 17 00:00:00 2001 From: Ayoun Serge Date: Mon, 23 Sep 2019 10:58:24 +0300 Subject: [PATCH 29/50] Build error fixes for kernel 5.3 and later apply_to_page_range() API signature was changed Makefile does not support SUBDIR anymore Signed-off-by: Ayoun Serge --- Makefile | 2 +- sgx_page_cache.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6bb4cd8..9b10ffa 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: - $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules + $(MAKE) -C $(KDIR) M=$(PWD) modules install: default $(MAKE) INSTALL_MOD_DIR=kernel/drivers/intel/sgx -C $(KDIR) M=$(PWD) modules_install diff --git a/sgx_page_cache.c b/sgx_page_cache.c index b4bc985..ed7c6be 100644 --- a/sgx_page_cache.c +++ b/sgx_page_cache.c @@ -86,8 +86,11 @@ static unsigned int sgx_nr_high_pages; static struct task_struct *ksgxswapd_tsk; static DECLARE_WAIT_QUEUE_HEAD(ksgxswapd_waitq); -static int sgx_test_and_clear_young_cb(pte_t *ptep, pgtable_t token, - unsigned long addr, void *data) +static int sgx_test_and_clear_young_cb(pte_t *ptep, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)) + pgtable_t token, +#endif + unsigned long addr, void *data) { pte_t pte; int ret; From fae3ce573e55a9144a8459f1d44d1d9c3ab9c527 Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Wed, 9 Oct 2019 10:10:42 -0500 Subject: [PATCH 30/50] Version 2.6 Signed-off-by: Huang, Haitao <4699115+haitaohuang@users.noreply.github.com> --- sgx_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sgx_main.c b/sgx_main.c index ebbb168..639a362 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -72,7 +72,7 @@ #include #define DRV_DESCRIPTION "Intel SGX Driver" -#define DRV_VERSION "2.5.0" +#define DRV_VERSION "2.6.0" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR("Jarkko Sakkinen "); From 51c4821b8a4fa0cba69f532474a13c298c5b4037 Mon Sep 17 00:00:00 2001 From: "Huang, Haitao" <4699115+haitaohuang@users.noreply.github.com> Date: Wed, 30 Oct 2019 10:56:38 -0500 Subject: [PATCH 31/50] README: switch to master branch for main development Also updated to refer to DCAP driver for tracking proposed upstream version Signed-off-by: Huang, Haitao <4699115+haitaohuang@users.noreply.github.com> --- README.md | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 30ee4b3..c03e0ab 100644 --- a/README.md +++ b/README.md @@ -11,27 +11,22 @@ The Linux SGX software stack is comprised of the Intel(R) SGX driver, the Intel( The [linux-sgx-driver](https://github.com/01org/linux-sgx-driver) project hosts the out-of-tree driver for the Linux Intel(R) SGX software stack, which will be used until the driver upstreaming process is complete. -Within the linux-sgx-driver project, two versions of the out-of-tree driver are provided. Both versions are compatible with the linux-sgx PSW and SDK: -- SGX 2.0 Linux Driver (sgx2 branch) - * The sgx2 branch of the linux-sgx-driver project contains the SGX 2.0 Linux Driver. This driver has additional support for SGX 2.0-based features available in upcoming CPUs. This driver has the same behavior as the SGX 1.5 Linux Driver (master) on CPUs without SGX 2.0 support. -- SGX 1.5 Linux Driver (master branch) - * The master branch of the linux-sgx-driver project tracks the proposed upstream version of the SGX 1.5 driver and does not yet support SGX 2.0-based features. - IMPORTANT: --------- -Starting from 5/10/2019, the master branch (which supports only SGX 1.5-based features) is deprecated and is not supported anymore. Please use the sgx2 branch; it is a super set of the master branch. +Starting 12/12/2019, the sgx2 branch is now merged into master. The sgx2 branch +will be deprecated. All development and updates will be done on master branch going forward. Please use master branch only. + +The master branch will support both SGX 2.0 and SGX 1.5 features. + +Note this OOT driver may diverge from the proposed upstream version for in-kernel +SGX support over time. The [DCAP +driver](https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/master/driver) +will track more closely with proposed upstream in-kernel support. License ------- See License.txt for details. -Contributing -------- -Starting from 05/2017, we are importing the sgx driver code from the in-kernel sgx repository located at git-hub: https://github.com/jsakkine-intel/linux-sgx.git. Any contribution should be done there. Future versions of the sgx driver code will be imported later on. The motivation behind this decision is to maintain a single source code of the sgx linux driver. -An additional directory inker2ext/ has been created, it contains a script and a patch file that can be used in order to separately generate the code base of the sgx external module; it can be used in case someone wants the newest sgx driver as an external module and does not want to wait for next update. - -The sgx2 branch hosts an initial implementation supporting SGX 2.0. This patch is maintained in inker2ext/sgx2.patch in the 2.0 branch and will be periodically rebased to take updates from the linux-sgx-driver:master branch. Contributions for this patch should be managed directly through the linux-sgx-driver project on Github. - Documentation ------------- - [Intel(R) SGX for Linux\* OS](https://01.org/intel-softwareguard-extensions) project home page on [01.org](http://01.org) @@ -87,7 +82,6 @@ Build and Install the Intel(R) SGX Driver ### Build the Intel(R) SGX Driver -**Note:** To use the SGX 2.0 driver, checkout or download the sgx2 branch and then follow the build instructions. To build Intel(R) SGX driver, change the directory to the driver path and enter the following command: ``` From 287083fcce9560d99eff0f4bf2eb18d1927e20f7 Mon Sep 17 00:00:00 2001 From: haitaohuang <4699115+haitaohuang@users.noreply.github.com> Date: Thu, 23 Jan 2020 10:45:30 -0600 Subject: [PATCH 32/50] Update README after deleting sgx2 branch Removed mentioning of sgx2 branch and update comments to emphasize differences between kernel, DCAP and this driver. --- README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c03e0ab..af823e9 100644 --- a/README.md +++ b/README.md @@ -13,15 +13,11 @@ The [linux-sgx-driver](https://github.com/01org/linux-sgx-driver) project hosts IMPORTANT: --------- -Starting 12/12/2019, the sgx2 branch is now merged into master. The sgx2 branch -will be deprecated. All development and updates will be done on master branch going forward. Please use master branch only. +This driver supports SGX 2.0 features, and works with latest Intel(R) SGX PSW on CPUs without Flexible Launch Control (FLC). +As upstreaming patches for kernel currently does not support SGX 2.0 features, and will not support non-FLC CPUs, this driver is diverged and will remain diverged from the proposed upstreaming version. -The master branch will support both SGX 2.0 and SGX 1.5 features. - -Note this OOT driver may diverge from the proposed upstream version for in-kernel -SGX support over time. The [DCAP -driver](https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/master/driver) -will track more closely with proposed upstream in-kernel support. +The [DCAP driver](https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/master/driver) +will track more closely with upstream in-kernel support. License ------- From 329facdacaca1f8608a98af13bc3f5a22e52d000 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Wed, 26 Feb 2020 15:11:49 -0500 Subject: [PATCH 33/50] Rename MSR_IA32_FEATURE_CONTROL and FEATURE_CONTROL_LOCKED They have new names in more recent kernels. We check for the old defines, however, in order to prevent breaking on older kernels. Also, rename FEATURE_CONTROL_SGX_ENABLE to match the new naming. Signed-off-by: Nathaniel McCallum --- sgx_main.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sgx_main.c b/sgx_main.c index 639a362..36d9d1d 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -74,6 +74,14 @@ #define DRV_DESCRIPTION "Intel SGX Driver" #define DRV_VERSION "2.6.0" +#ifndef MSR_IA32_FEAT_CTL +#define MSR_IA32_FEAT_CTL MSR_IA32_FEATURE_CONTROL +#endif + +#ifndef FEAT_CTL_LOCKED +#define FEAT_CTL_LOCKED FEATURE_CONTROL_LOCKED +#endif + MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR("Jarkko Sakkinen "); MODULE_VERSION(DRV_VERSION); @@ -81,7 +89,7 @@ MODULE_VERSION(DRV_VERSION); #define X86_FEATURE_SGX (9 * 32 + 2) #endif -#define FEATURE_CONTROL_SGX_ENABLE (1<<18) +#define FEAT_CTL_SGX_ENABLED (1<<18) /* * Global data. @@ -303,14 +311,14 @@ static int sgx_drv_probe(struct platform_device *pdev) return -ENODEV; } - rdmsrl(MSR_IA32_FEATURE_CONTROL, fc); + rdmsrl(MSR_IA32_FEAT_CTL, fc); - if (!(fc & FEATURE_CONTROL_LOCKED)) { + if (!(fc & FEAT_CTL_LOCKED)) { pr_err("intel_sgx: the feature control MSR is not locked\n"); return -ENODEV; } - if (!(fc & FEATURE_CONTROL_SGX_ENABLE)) { + if (!(fc & FEAT_CTL_SGX_ENABLED)) { pr_err("intel_sgx: SGX is not enabled\n"); return -ENODEV; } From d92c57d5c45edaa4e11c29fe54a1c2fd2f2edb4a Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Thu, 27 Feb 2020 12:40:25 -0600 Subject: [PATCH 34/50] Fix warning on 5.6 kernel Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- sgx_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sgx_main.c b/sgx_main.c index 36d9d1d..170dc8a 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -88,9 +88,9 @@ MODULE_VERSION(DRV_VERSION); #ifndef X86_FEATURE_SGX #define X86_FEATURE_SGX (9 * 32 + 2) #endif - +#ifndef FEAT_CTL_SGX_ENABLED #define FEAT_CTL_SGX_ENABLED (1<<18) - +#endif /* * Global data. */ From 17697b50d3e64abbe7f2ce17e41c180c6bc5717b Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Thu, 27 Feb 2020 12:40:54 -0600 Subject: [PATCH 35/50] Run depmod separately during install Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 9b10ffa..74ec5d7 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ default: install: default $(MAKE) INSTALL_MOD_DIR=kernel/drivers/intel/sgx -C $(KDIR) M=$(PWD) modules_install + depmod -A sh -c "cat /etc/modules | grep -Fxq isgx || echo isgx >> /etc/modules" endif From 4e1dd1b13665cf70dce6336258512680573355b6 Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Fri, 29 May 2020 17:38:36 -0500 Subject: [PATCH 36/50] Update README.md Clarify intended usage of this driver Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index af823e9..91172ff 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,11 @@ The [linux-sgx-driver](https://github.com/01org/linux-sgx-driver) project hosts IMPORTANT: --------- -This driver supports SGX 2.0 features, and works with latest Intel(R) SGX PSW on CPUs without Flexible Launch Control (FLC). -As upstreaming patches for kernel currently does not support SGX 2.0 features, and will not support non-FLC CPUs, this driver is diverged and will remain diverged from the proposed upstreaming version. +This driver can be used to support earlier SGX-capable CPUs without Flexible Launch Control (FLC). However, please note that the ABI of this driver is diverged from the upstreaming SGX kernel patches and extra effort may be required to migrate software using this driver to future kernels with SGX support. To minimize ABI divergence and better align all SGX software stack with future SGX enabled kernel, no new features will be added to this driver. Support for distro/kernel versions other than those listed here will be considered on a case-by-case basis. -The [DCAP driver](https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/master/driver) -will track more closely with upstream in-kernel support. +The [DCAP driver]( https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/master/driver) has been developed to track closely with the upstreaming kernel patches, and support all SGX CPUs with FLC. Therefore, we recommend SGX community to start using the DCAP driver to minimize future impact from adopting new mainline kernels with SGX support. + +For new feature requests/patches, please submit them directly to the [linux-sgx mailing list](http://vger.kernel.org/vger-lists.html#linux-sgx) License ------- From cf8b3d26ce9b3bfbe7d74e00390d28344fa5d548 Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Tue, 12 May 2020 03:03:30 +0000 Subject: [PATCH 37/50] Fix build for RHEL 8.2 Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- sgx.h | 2 +- sgx_encl.c | 9 ++------- sgx_encl2.c | 9 +-------- sgx_page_cache.c | 8 +++++++- sgx_util.c | 34 +++++++++++++++++++++++++++------- sgx_vma.c | 28 ++++++++++++++++++++++------ 6 files changed, 60 insertions(+), 30 deletions(-) diff --git a/sgx.h b/sgx.h index 46dfc0f..590464d 100644 --- a/sgx.h +++ b/sgx.h @@ -275,5 +275,5 @@ int sgx_eldu(struct sgx_encl *encl, struct sgx_encl_page *encl_page, 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); - +int sgx_vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, resource_size_t pa); #endif /* __ARCH_X86_INTEL_SGX_H__ */ diff --git a/sgx_encl.c b/sgx_encl.c index a03c30a..6815c43 100644 --- a/sgx_encl.c +++ b/sgx_encl.c @@ -250,13 +250,8 @@ static bool sgx_process_add_page_req(struct sgx_add_page_req *req, return false; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) - ret = vmf_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); - if (ret != VM_FAULT_NOPAGE) { -#else - ret = vm_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); - if (ret) { -#endif + ret = sgx_vm_insert_pfn(vma, encl_page->addr, epc_page->pa); + if (ret != VM_FAULT_NOPAGE) { sgx_put_backing(backing, 0); return false; } diff --git a/sgx_encl2.c b/sgx_encl2.c index 0df9b00..2f5064f 100644 --- a/sgx_encl2.c +++ b/sgx_encl2.c @@ -169,17 +169,10 @@ struct sgx_encl_page *sgx_encl_augment(struct vm_area_struct *vma, goto out; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) - ret = vmf_insert_pfn(vma, encl_page->addr, PFN_DOWN(epc_page->pa)); + ret = sgx_vm_insert_pfn(vma, encl_page->addr, epc_page->pa); sgx_put_page(epc_va); sgx_put_page(secs_va); if (ret != VM_FAULT_NOPAGE) { -#else - 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) { -#endif pr_err("sgx: vm_insert_pfn failure with ret=%d\n", ret); goto out; } diff --git a/sgx_page_cache.c b/sgx_page_cache.c index ed7c6be..3770ad4 100644 --- a/sgx_page_cache.c +++ b/sgx_page_cache.c @@ -88,7 +88,13 @@ static DECLARE_WAIT_QUEUE_HEAD(ksgxswapd_waitq); static int sgx_test_and_clear_young_cb(pte_t *ptep, #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)) - pgtable_t token, + #if( defined(RHEL_RELEASE_VERSION) && defined(RHEL_RELEASE_CODE)) + #if (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(8, 1)) + pgtable_t token, + #endif + #else + pgtable_t token, + #endif #endif unsigned long addr, void *data) { diff --git a/sgx_util.c b/sgx_util.c index 25b18a9..38013e2 100644 --- a/sgx_util.c +++ b/sgx_util.c @@ -66,6 +66,31 @@ #else #include #endif +int sgx_vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, resource_size_t pa) +{ + int rc; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + rc = vmf_insert_pfn(vma, addr, PFN_DOWN(pa)); +#else + #if( defined(RHEL_RELEASE_VERSION) && defined(RHEL_RELEASE_CODE)) + #if (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(8, 1)) + rc = vmf_insert_pfn(vma, addr, PFN_DOWN(pa)); + #else //8.1 or below + rc = vm_insert_pfn(vma, addr, PFN_DOWN(pa)); + if (!rc){ + rc = VM_FAULT_NOPAGE; + } + #endif + #else + rc = vm_insert_pfn(vma, addr, PFN_DOWN(pa)); + if (!rc){ + rc = VM_FAULT_NOPAGE; + } + #endif +#endif + return rc; +} struct page *sgx_get_backing(struct sgx_encl *encl, struct sgx_encl_page *entry, @@ -318,14 +343,9 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, /* Do not free */ epc_page = NULL; list_add_tail(&entry->epc_page->list, &encl->load_list); + rc = sgx_vm_insert_pfn(vma, entry->addr, entry->epc_page->pa); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) - rc = vmf_insert_pfn(vma, entry->addr, PFN_DOWN(entry->epc_page->pa)); - if (rc != VM_FAULT_NOPAGE) { -#else - rc = vm_insert_pfn(vma, entry->addr, PFN_DOWN(entry->epc_page->pa)); - if (rc) { -#endif + if (rc != VM_FAULT_NOPAGE) { /* Kill the enclave if vm_insert_pfn fails; failure only occurs * if there is a driver bug or an unrecoverable issue, e.g. OOM. */ diff --git a/sgx_vma.c b/sgx_vma.c index 34ec7bb..a62eb59 100644 --- a/sgx_vma.c +++ b/sgx_vma.c @@ -105,17 +105,33 @@ static void sgx_vma_close(struct vm_area_struct *vma) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,1,0)) static unsigned int sgx_vma_fault(struct vm_fault *vmf) { - struct vm_area_struct *vma = vmf->vma; -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) + struct vm_area_struct *vma = vmf->vma; +#else + #if( defined(RHEL_RELEASE_VERSION) && defined(RHEL_RELEASE_CODE)) + #if (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(8, 1)) +static unsigned int sgx_vma_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + #elif (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8, 0)) static int sgx_vma_fault(struct vm_fault *vmf) { - struct vm_area_struct *vma = vmf->vma; -#else + struct vm_area_struct *vma = vmf->vma; + #else // 7.x static int sgx_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { + #endif + #else + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)) +static int sgx_vma_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + #else +static int sgx_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + #endif + #endif #endif - - + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) unsigned long addr = (unsigned long)vmf->address; #else From a021c08bb7e5668d49438e2189b7148aa97c475b Mon Sep 17 00:00:00 2001 From: Tianjia Zhang Date: Fri, 17 Jul 2020 16:33:33 +0800 Subject: [PATCH 38/50] Remove unnecessary if conditional statements Obviously, this if check is redundant. Remove it. Signed-off-by: Tianjia Zhang --- sgx_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sgx_main.c b/sgx_main.c index 170dc8a..9129837 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -278,9 +278,6 @@ static int sgx_dev_init(struct device *parent) goto out_workqueue; } - if (ret) - goto out_workqueue; - return 0; out_workqueue: destroy_workqueue(sgx_add_page_wq); From 93797b0ba2c9760f1488b89726221d681d5554f7 Mon Sep 17 00:00:00 2001 From: Tianjia Zhang Date: Fri, 17 Jul 2020 16:56:58 +0800 Subject: [PATCH 39/50] Clean page_cache on failed exit path in sgx_dev_init() Signed-off-by: Tianjia Zhang --- sgx_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sgx_main.c b/sgx_main.c index 9129837..3e9661e 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -268,7 +268,7 @@ static int sgx_dev_init(struct device *parent) if (!sgx_add_page_wq) { pr_err("intel_sgx: alloc_workqueue() failed\n"); ret = -ENOMEM; - goto out_iounmap; + goto out_page_cache; } sgx_dev.parent = parent; @@ -281,6 +281,8 @@ static int sgx_dev_init(struct device *parent) return 0; out_workqueue: destroy_workqueue(sgx_add_page_wq); +out_page_cache: + sgx_page_cache_teardown(); out_iounmap: #ifdef CONFIG_X86_64 for (i = 0; i < sgx_nr_epc_banks; i++) From 92cdb8d2d66f5ae692258bbc309b207708099f57 Mon Sep 17 00:00:00 2001 From: Tianjia Zhang Date: Fri, 17 Jul 2020 18:34:45 +0800 Subject: [PATCH 40/50] Delete unnecessary sgx_compat_ioctl() Signed-off-by: Tianjia Zhang --- sgx_main.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sgx_main.c b/sgx_main.c index 3e9661e..0c93635 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -106,13 +106,6 @@ 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) -{ - return sgx_ioctl(filep, cmd, arg); -} -#endif - static int sgx_mmap(struct file *file, struct vm_area_struct *vma) { vma->vm_ops = &sgx_vm_ops; @@ -162,7 +155,7 @@ static const struct file_operations sgx_fops = { .owner = THIS_MODULE, .unlocked_ioctl = sgx_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = sgx_compat_ioctl, + .compat_ioctl = sgx_ioctl, #endif .mmap = sgx_mmap, .get_unmapped_area = sgx_get_unmapped_area, From 0a6d266794adaf8126c2f19dab32189702e3cec1 Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Tue, 4 Aug 2020 13:56:33 -0500 Subject: [PATCH 41/50] Fix signed integer overflow on shift Shifting a signed integer value of 1 by 31 or more bits will cause overflow and can lead to undefined behaviour. Fix this by adding a UL suffix to ensure an unsigned long is being shifted. Signed-off-by: Colin Ian King colin.king@canonical.com Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- sgx_encl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sgx_encl.c b/sgx_encl.c index 6815c43..44439c8 100644 --- a/sgx_encl.c +++ b/sgx_encl.c @@ -339,7 +339,7 @@ static u32 sgx_calc_ssaframesize(u32 miscselect, u64 xfrm) int i; for (i = 2; i < 64; i++) { - if (!((1 << i) & xfrm)) + if (!((1UL << i) & xfrm)) continue; size = SGX_SSA_GPRS_SIZE + sgx_xsave_size_tbl[i]; From 35ef6b1a5324652d049c64c0153777062a6cb06a Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Wed, 2 Sep 2020 12:59:57 -0500 Subject: [PATCH 42/50] Update version to 2.11 Note this is used in Intel PSW release 2.11 Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- sgx_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sgx_main.c b/sgx_main.c index 0c93635..aa99564 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -72,7 +72,7 @@ #include #define DRV_DESCRIPTION "Intel SGX Driver" -#define DRV_VERSION "2.6.0" +#define DRV_VERSION "2.11.0" #ifndef MSR_IA32_FEAT_CTL #define MSR_IA32_FEAT_CTL MSR_IA32_FEATURE_CONTROL From 276c5c6a064d22358542f5e0aa96b1c0ace5d695 Mon Sep 17 00:00:00 2001 From: Don Porter Date: Wed, 2 Sep 2020 14:26:40 -0400 Subject: [PATCH 43/50] Fix compilation on 5.8 kernel (#120) * Fix compilation on 5.8 kernel Signed-off-by: Don Porter * Address review comments * Address review comments --- sgx_encl.c | 30 ++++++++++++++++++++++++++---- sgx_encl2.c | 19 ++++++++++++++++++- sgx_ioctl.c | 9 +++++++++ sgx_page_cache.c | 9 +++++++++ 4 files changed, 62 insertions(+), 5 deletions(-) diff --git a/sgx_encl.c b/sgx_encl.c index 44439c8..04a1b9c 100644 --- a/sgx_encl.c +++ b/sgx_encl.c @@ -316,7 +316,11 @@ static void sgx_add_page_worker(struct work_struct *work) goto next; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_lock(encl->mm); +#else down_read(&encl->mm->mmap_sem); +#endif mutex_lock(&encl->lock); if (!sgx_process_add_page_req(req, epc_page)) { @@ -325,7 +329,11 @@ static void sgx_add_page_worker(struct work_struct *work) } mutex_unlock(&encl->lock); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_unlock(encl->mm); +#else up_read(&encl->mm->mmap_sem); +#endif next: kfree(req); @@ -639,31 +647,45 @@ int sgx_encl_create(struct sgx_secs *secs) goto out; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_lock(current->mm); +#else down_read(¤t->mm->mmap_sem); +#endif ret = sgx_encl_find(current->mm, secs->base, &vma); if (ret != -ENOENT) { if (!ret) ret = -EINVAL; - up_read(¤t->mm->mmap_sem); - goto out; + goto out_locked; } if (vma->vm_start != secs->base || vma->vm_end != (secs->base + secs->size) /* vma->vm_pgoff != 0 */) { ret = -EINVAL; - up_read(¤t->mm->mmap_sem); - goto out; + goto out_locked; } vma->vm_private_data = encl; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_unlock(current->mm); +#else up_read(¤t->mm->mmap_sem); +#endif mutex_lock(&sgx_tgid_ctx_mutex); list_add_tail(&encl->encl_list, &encl->tgid_ctx->encl_list); mutex_unlock(&sgx_tgid_ctx_mutex); return 0; +out_locked: +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_unlock(current->mm); +#else + up_read(¤t->mm->mmap_sem); +#endif + out: if (encl) kref_put(&encl->refcount, sgx_encl_release); diff --git a/sgx_encl2.c b/sgx_encl2.c index 2f5064f..0122efd 100644 --- a/sgx_encl2.c +++ b/sgx_encl2.c @@ -234,12 +234,22 @@ static int isolate_range(struct sgx_encl *encl, address = rg->start_addr; end = address + rg->nr_pages * PAGE_SIZE; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_lock(encl->mm); +#else down_read(&encl->mm->mmap_sem); +#endif + for (; address < end; address += PAGE_SIZE) { ret = sgx_encl_find(encl->mm, address, &vma); if (ret || encl != vma->vm_private_data) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_unlock(encl->mm); +#else up_read(&encl->mm->mmap_sem); +#endif return -EINVAL; } @@ -250,7 +260,11 @@ static int isolate_range(struct sgx_encl *encl, SGX_FAULT_RESERVE, NULL); if (IS_ERR(encl_page)) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_unlock(encl->mm); +#else up_read(&encl->mm->mmap_sem); +#endif sgx_err(encl, "sgx: No page found at address 0x%lx\n", address); return PTR_ERR(encl_page); @@ -264,8 +278,11 @@ static int isolate_range(struct sgx_encl *encl, encl_page->flags &= ~SGX_ENCL_PAGE_RESERVED; mutex_unlock(&encl->lock); } - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_unlock(encl->mm); +#else up_read(&encl->mm->mmap_sem); +#endif return 0; } diff --git a/sgx_ioctl.c b/sgx_ioctl.c index 0b3476d..56ab1e6 100644 --- a/sgx_ioctl.c +++ b/sgx_ioctl.c @@ -82,7 +82,11 @@ int sgx_get_encl(unsigned long addr, struct sgx_encl **encl) if (addr & (PAGE_SIZE - 1)) return -EINVAL; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_lock(mm); +#else down_read(&mm->mmap_sem); +#endif ret = sgx_encl_find(mm, addr, &vma); if (!ret) { @@ -94,7 +98,12 @@ int sgx_get_encl(unsigned long addr, struct sgx_encl **encl) kref_get(&(*encl)->refcount); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_unlock(mm); +#else up_read(&mm->mmap_sem); +#endif + return ret; } diff --git a/sgx_page_cache.c b/sgx_page_cache.c index 3770ad4..77bea6e 100644 --- a/sgx_page_cache.c +++ b/sgx_page_cache.c @@ -376,10 +376,19 @@ static void sgx_swap_pages(unsigned long nr_to_scan) if (!encl) goto out; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_lock(encl->mm); +#else down_read(&encl->mm->mmap_sem); +#endif + sgx_isolate_pages(encl, &cluster, nr_to_scan); sgx_write_pages(encl, &cluster); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) + mmap_read_unlock(encl->mm); +#else up_read(&encl->mm->mmap_sem); +#endif kref_put(&encl->refcount, sgx_encl_release); out: From 438248400c6ae28c2d14b5e5abf05bbf4faa72a3 Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Sat, 12 Sep 2020 16:44:52 -0500 Subject: [PATCH 44/50] Clean more files Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- .gitignore | 1 + Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1adf5a1..a4dfd7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.ko *.o *.cmd +*.mod *.mod.* *.symvers *.order diff --git a/Makefile b/Makefile index 74ec5d7..c0963fc 100644 --- a/Makefile +++ b/Makefile @@ -23,4 +23,4 @@ install: default endif clean: - rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd + rm -vrf *.o *.ko *.order *.symvers *.mod.c .tmp_versions .*o.cmd *.mod From 1bc987f81bcd7df856ddf14bced69c2e20feb9d3 Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Sat, 12 Sep 2020 16:41:06 -0500 Subject: [PATCH 45/50] Reset MSRs for SGX launch enclave signing key public hash during init Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- sgx.h | 6 ++++++ sgx_main.c | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/sgx.h b/sgx.h index 590464d..62c19da 100644 --- a/sgx.h +++ b/sgx.h @@ -79,6 +79,12 @@ #define SGX_EDMM_SPIN_COUNT 20 #define SGX_VA_SLOT_COUNT 512 +#ifndef MSR_IA32_SGXLEPUBKEYHASH0 + #define MSR_IA32_SGXLEPUBKEYHASH0 0x0000008C + #define MSR_IA32_SGXLEPUBKEYHASH1 0x0000008D + #define MSR_IA32_SGXLEPUBKEYHASH2 0x0000008E + #define MSR_IA32_SGXLEPUBKEYHASH3 0x0000008F +#endif struct sgx_epc_page { resource_size_t pa; diff --git a/sgx_main.c b/sgx_main.c index aa99564..4ff4e2b 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -184,6 +184,15 @@ static int sgx_pm_suspend(struct device *dev) return 0; } +static void sgx_reset_pubkey_hash(void *failed) +{ + if (wrmsrl_safe(MSR_IA32_SGXLEPUBKEYHASH0, 0xa6053e051270b7acULL) || + wrmsrl_safe(MSR_IA32_SGXLEPUBKEYHASH1, 0x6cfbe8ba8b3b413dULL) || + wrmsrl_safe(MSR_IA32_SGXLEPUBKEYHASH2, 0xc4916d99f2b3735dULL) || + wrmsrl_safe(MSR_IA32_SGXLEPUBKEYHASH3, 0xd4f8c05909f9bb3bULL)) + *(int *)failed = -EIO; +} + static SIMPLE_DEV_PM_OPS(sgx_drv_pm, sgx_pm_suspend, NULL); static int sgx_dev_init(struct device *parent) @@ -193,6 +202,7 @@ static int sgx_dev_init(struct device *parent) unsigned long size; int ret; int i; + int msr_reset_failed = 0; pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n"); @@ -271,6 +281,11 @@ static int sgx_dev_init(struct device *parent) goto out_workqueue; } + on_each_cpu(sgx_reset_pubkey_hash, &msr_reset_failed, 1); + if (msr_reset_failed) { + pr_info("intel_sgx: can not reset SGX LE public key hash MSRs\n"); + } + return 0; out_workqueue: destroy_workqueue(sgx_add_page_wq); From 3a4f6ac598f89a3ba3c423335841fe250495f4b9 Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Mon, 9 Nov 2020 15:09:08 -0600 Subject: [PATCH 46/50] Update supported OSes by referring to releases Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- README.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 91172ff..62d4529 100644 --- a/README.md +++ b/README.md @@ -32,15 +32,7 @@ Build and Install the Intel(R) SGX Driver ----------------------------------------- ### Prerequisites -- Ensure that you have the following required operating systems: - * Ubuntu* 16.04.3 LTS Desktop 64bits - * Ubuntu* 16.04.3 LTS Server 64bits - * Ubuntu* 18.04 LTS Desktop 64bits - * Ubuntu* 18.04 LTS Server 64bits - * Red Hat Enterprise Linux Server release 7.4 64bits - * Red Hat Enterprise Linux Server release 8.0 64bits - * CentOS 7.4.1708 64bits - * SUSE Linux Enterprise Server 12 64bits +- Ensure that you have an operating system version supported as listed in releases: https://01.org/intel-software-guard-extensions/downloads - Ensure that you have the following required hardware: * 6th Generation Intel(R) Core(TM) Processor or newer - Configure the system with the **SGX hardware enabled** option. @@ -54,7 +46,7 @@ Build and Install the Intel(R) SGX Driver ``` $ sudo apt-get install linux-headers-$(uname -r) ``` - * On CentOS and RHEL + * On CentOS, RHEL or Fedora * To check if matching kernel headers are installed: ``` $ ls /usr/src/kernels/$(uname -r) From ed2c256929962db1a8805db53bed09bb8f2f4de3 Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Fri, 16 Apr 2021 20:12:10 +0000 Subject: [PATCH 47/50] Use cpuid instead of boot_cpu_has to check cpu features For non-FLC platforms, Linux kernel 5.11 or above disables sgx feature flag so boot_cpu_has is not usable. Signed-off-by: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> --- sgx_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sgx_main.c b/sgx_main.c index 4ff4e2b..ca52821 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -313,7 +313,8 @@ static int sgx_drv_probe(struct platform_device *pdev) if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) return -ENODEV; - if (!boot_cpu_has(X86_FEATURE_SGX)) { + cpuid(7, &eax, &ebx, &ecx, &edx); + if(!((ebx >> 2) & 0x1)){ pr_err("intel_sgx: the CPU is missing SGX\n"); return -ENODEV; } From 54c9c4c1fe30f459abe7c4b9c153ed2967973c22 Mon Sep 17 00:00:00 2001 From: lzha101 Date: Wed, 10 Nov 2021 13:45:04 +0800 Subject: [PATCH 48/50] Add SECURITY.md Signed-off-by: Zhang Lili lili.z.zhang@intel.com --- SECURITY.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..209f8fb --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,12 @@ +# Security Policy + +## Report a Vulnerability + +Please report security issues or vulnerabilities to the [Intel Security Center]. + +For more information on how Intel works to resolve security issues, see +[Vulnerability Handling Guidelines]. + +[Intel Security Center]:https://www.intel.com/security + +[Vulnerability Handling Guidelines]:https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html From b6f5b4a62d75ee9beb4f4ae16c86640f8c5e62ae Mon Sep 17 00:00:00 2001 From: Haitao Huang <4699115+haitaohuang@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:45:25 -0600 Subject: [PATCH 49/50] Update README.md for documentation download links Signed-off-by: Haitao Huang --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 62d4529..029a68e 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ See License.txt for details. Documentation ------------- -- [Intel(R) SGX for Linux\* OS](https://01.org/intel-softwareguard-extensions) project home page on [01.org](http://01.org) +- [Intel(R) SGX for Linux\* OS](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html) - [Intel(R) SGX Programming Reference](https://software.intel.com/en-us/articles/intel-sdm) Build and Install the Intel(R) SGX Driver ----------------------------------------- ### Prerequisites -- Ensure that you have an operating system version supported as listed in releases: https://01.org/intel-software-guard-extensions/downloads +- Ensure that you have an operating system version supported as listed for specific releases: [https://01.org/intel-software-guard-extensions/downloads](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html#downloads) - Ensure that you have the following required hardware: * 6th Generation Intel(R) Core(TM) Processor or newer - Configure the system with the **SGX hardware enabled** option. From 2f69bc44869a23691001148bce16d26f77ba030a Mon Sep 17 00:00:00 2001 From: Pierre Gronlier Date: Mon, 19 Feb 2024 10:48:05 +0100 Subject: [PATCH 50/50] fix compilation on 6.5 and shift op reuse the patch from https://github.com/intel/linux-sgx-driver/pull/151 and fix "shift exponent 32 is too large for 32-bit type 'int'" when loading the isgx module --- sgx_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sgx_main.c b/sgx_main.c index ca52821..f280587 100644 --- a/sgx_main.c +++ b/sgx_main.c @@ -109,9 +109,9 @@ bool sgx_has_sgx2; static int sgx_mmap(struct file *file, struct vm_area_struct *vma) { vma->vm_ops = &sgx_vm_ops; - vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO | - VM_DONTCOPY; - + vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO | + VM_DONTCOPY); + return 0; } @@ -221,7 +221,7 @@ static int sgx_dev_init(struct device *parent) for (i = 2; i < 64; i++) { cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx); - if ((1 << i) & sgx_xfrm_mask) + if ((1ULL << i) & sgx_xfrm_mask) sgx_xsave_size_tbl[i] = eax + ebx; } }