From e4e63e6c5f48886a3037dc69ae7a929d8d985dd7 Mon Sep 17 00:00:00 2001 From: Alex Thomas Date: Fri, 8 Mar 2019 00:56:52 -0800 Subject: [PATCH] Splitting up Create Enclave to three modules (#1) --- keystone-enclave.c | 1 + keystone-ioctl.c | 464 +++++++++++++++++++++++++-------------------- keystone-page.c | 4 + keystone-rtld.c | 28 ++- keystone.h | 9 +- keystone_user.h | 72 ++++--- 6 files changed, 341 insertions(+), 237 deletions(-) diff --git a/keystone-enclave.c b/keystone-enclave.c index c38630ba2..4defc5d57 100644 --- a/keystone-enclave.c +++ b/keystone-enclave.c @@ -103,6 +103,7 @@ enclave_t* create_enclave(unsigned long min_pages) INIT_LIST_HEAD(&epm->epm_free_list); epm->pa = __pa(epm_vaddr); + pr_info("epm->pa: 0x%px\n", epm->pa); epm->order = order; epm_init(epm, epm_vaddr, count); enclave->epm = epm; diff --git a/keystone-ioctl.c b/keystone-ioctl.c index 815784fb1..2b4482e3e 100644 --- a/keystone-ioctl.c +++ b/keystone-ioctl.c @@ -8,230 +8,286 @@ #include -int keystone_create_enclave(struct file* filp, unsigned long arg) -{ - int ret; - - /* create parameters */ - struct keystone_ioctl_create_enclave *enclp = (struct keystone_ioctl_create_enclave*) arg; - - // User ELF - void* __user user_elf_ptr = (void*) enclp->user_elf_ptr; - size_t user_elf_size = enclp->user_elf_size; - size_t user_stack_size = enclp->user_stack_size; - - // Runtime ELF - void* __user runtime_elf_ptr = (void*) enclp->runtime_elf_ptr; - size_t runtime_elf_size = enclp->runtime_elf_size; - size_t runtime_stack_size = enclp->runtime_stack_size; - - // Untrusted mmap size - void* untrusted_ptr = (void*) enclp->params.untrusted_ptr; - size_t untrusted_size = enclp->params.untrusted_size; - - // runtime parameters - struct keystone_sbi_create_t create_args; - - enclave_t* enclave; - - /* local variables */ - unsigned long rt_offset; - unsigned long min_pages = calculate_required_pages(user_elf_size, user_stack_size, runtime_elf_size, runtime_stack_size); - struct utm_t* utm; - - /* argument validity */ - if (!user_elf_ptr || !runtime_elf_ptr || !user_elf_size || !runtime_elf_size){ - ret = -EINVAL; - goto error_no_free; - } - - - enclave = create_enclave(min_pages); - if(enclave == NULL){ - ret = -ENOMEM; - goto error_no_free; - } - - /* initialize runtime */ - ret = -EFAULT; - if (keystone_rtld_init_runtime(enclave, runtime_elf_ptr, runtime_elf_size, runtime_stack_size, &rt_offset)) { - keystone_err("failed to initialize runtime\n"); - goto error_destroy_enclave; - } - - /* initialize user app */ - if (keystone_rtld_init_app(enclave, user_elf_ptr, user_elf_size, user_stack_size, rt_offset)) { - keystone_err("failed to initialize app\n"); - goto error_destroy_enclave; - } - - /* Untrusted Memory */ - utm = kmalloc(sizeof(struct utm_t), GFP_KERNEL); - if (!utm) { - ret = -ENOMEM; - goto error_destroy_enclave; - } - - ret = utm_init(utm, untrusted_size); - if (ret != 0) - goto error_destroy_enclave; - - filp->private_data = utm; - enclave->utm = utm; - - if (keystone_rtld_init_untrusted(enclave, untrusted_ptr, untrusted_size)) { - keystone_err("failed to initialize untrusted memory\n"); - goto error_destroy_enclave; - } - - /* SBI Call */ - create_args.epm_region.paddr = enclave->epm->pa; - create_args.epm_region.size = enclave->epm->total; - create_args.utm_region.paddr = __pa(utm->ptr); - create_args.utm_region.size = utm->size; - - create_args.params = enclp->params; - - // SM will write the eid to enclave_t.eid - create_args.eid_pptr = (unsigned int*)__pa(&enclave->eid); - ret = SBI_CALL_1(SBI_SM_CREATE_ENCLAVE, __pa(&create_args)); - if (ret) - { - keystone_err("keystone_create_enclave: SBI call failed\n"); - goto error_destroy_enclave; - } - - /* allocate UID */ - enclp->eid = enclave_idr_alloc(enclave); - - /* We cleanup the free lists here since the kernel will no longer be - managing them, they are part of the enclave now. */ - utm_clean_free_list(utm); - epm_clean_free_list(enclave->epm); - - return 0; - - error_destroy_enclave: - /* This can handle partial initialization failure */ - destroy_enclave(enclave); - - error_no_free: - return ret; +int keystone_create_enclave(struct file *filp, unsigned long arg) { + int ret = 0; + + pr_info("Creating enclave.."); + /* create parameters */ + struct keystone_ioctl_create_enclave *enclp = (struct keystone_ioctl_create_enclave*) arg; + /* What needs to be done in kernel? + * 1) Create enclave + * 2) Allocate memory for each segment in program header and setup stack + * 3) + * + * */ + + enclave_t *enclave; +// pr_info("arg_ptr: %px\n", enclp); +// pr_info("kernel min_pages: %llu\n", enclp->min_pages); + //Required to be in kernel to create enclave page + enclave = create_enclave(enclp->min_pages); + if (enclave == NULL) { + ret = -ENOMEM; + goto error_no_free; + } + + /* allocate UID */ + enclp->eid = enclave_idr_alloc(enclave); + + error_no_free: + return ret; +} + + +int keystone_finalize_enclave(struct file *filp, unsigned long arg){ + + pr_info("Finalizing...\n"); + int ret; + enclave_t *enclave; + struct utm_t* utm; + + struct keystone_ioctl_create_enclave *enclp = (struct keystone_ioctl_create_enclave*) arg; + + // Untrusted mmap size + void* untrusted_ptr = (void*) enclp->params.untrusted_ptr; + long long unsigned untrusted_size = enclp->params.untrusted_size; + + enclave = get_enclave_by_id(enclp->eid); + + /* initialize runtime */ + ret = -EFAULT; + + /* Untrusted Memory + * Shared memory between host and enclave(?) + * Probably only done in kernel-space (only the kernel can interact w/ SM) + * */ + + utm = kmalloc(sizeof(struct utm_t), GFP_KERNEL); + if (!utm) { + ret = -ENOMEM; + pr_info("Failed utm kalloc...\n"); + goto error_destroy_enclave; + } + + + ret = utm_init(utm, untrusted_size); + + if (ret != 0){ + pr_info("Failed to init utm...\n"); + goto error_destroy_enclave; + } + + + filp->private_data = utm; + enclave->utm = utm; + +// pr_info("filp: %px\n", filp); +// pr_info("filp->private_data: %px\n", filp->private_data); +// pr_info("enclave;: %px\n", enclave); +// pr_info("enclave->utm: %px\n", enclave->utm); +// pr_info("untrusted_size: %llu\n", untrusted_size); +// pr_info("untrusted_ptr: %px\n", untrusted_ptr); + + + if (keystone_rtld_init_untrusted(enclave, untrusted_ptr, untrusted_size)) { + keystone_err("failed to initialize untrusted memory\n"); + goto error_destroy_enclave; + } + + /* End untrusted memory allocation */ + + // runtime parameters + struct keystone_sbi_create_t create_args; + + /* SBI Call */ + + create_args.epm_region.paddr = enclave->epm->pa; + create_args.epm_region.size = enclave->epm->total; + create_args.utm_region.paddr = __pa(utm->ptr); + create_args.utm_region.size = utm->size; + + create_args.params = enclp->params; + + // SM will write the eid to enclave_t.eid + create_args.eid_pptr = (unsigned int *) __pa(&enclave->eid); + + pr_info("create_args.epm_region.paddr: 0x%px\n", create_args.epm_region.paddr); + pr_info("create_args.epm_region.size: %d\n", create_args.epm_region.size); + pr_info("create_args.utm_region.paddr: 0x%px\n", create_args.utm_region.paddr); + pr_info("create_args.utm_region.size: %d\n", create_args.utm_region.size); + + ret = SBI_CALL_1(SBI_SM_CREATE_ENCLAVE, __pa(&create_args)); + if (ret) { + keystone_err("keystone_create_enclave: SBI call failed\n"); + goto error_destroy_enclave; + } + + pr_info("Finished SBI call"); + + /* We cleanup the free lists here since the kernel will no longer be + managing them, they are part of the enclave now. */ + utm_clean_free_list(utm); + epm_clean_free_list(enclave->epm); + + return 0; + + error_destroy_enclave: + /* This can handle partial initialization failure */ + destroy_enclave(enclave); + + return ret; + + } -int keystone_destroy_enclave(struct file* filp, unsigned long arg) -{ - int ret; - struct keystone_ioctl_create_enclave *enclp = (struct keystone_ioctl_create_enclave*) arg; - unsigned long ueid = enclp->eid; - enclave_t* enclave; - enclave = get_enclave_by_id(ueid); - - if(!enclave) - { - keystone_err("invalid enclave id\n"); - return -EINVAL; - } - ret = SBI_CALL_1(SBI_SM_DESTROY_ENCLAVE, enclave->eid); - if(ret) { - keystone_err("fatal: cannot destroy enclave: SBI failed\n"); + +int keystone_add_page(unsigned long arg){ + int ret = 0; + struct addr_packed *addr = (struct addr_packed *) arg; + unsigned long ueid = addr->eid; + unsigned int mode = addr->mode; + enclave_t *enclave; + enclave = get_enclave_by_id(ueid); + vaddr_t epm_page; + switch(mode){ + case RT_NOEXEC: + epm_alloc_rt_page_noexec(enclave->epm, addr->va); + break; + case USER_NOEXEC: + epm_alloc_user_page_noexec(enclave->epm, addr->va); + break; + case RT_FULL: + epm_page = epm_alloc_rt_page(enclave->epm, addr->va); + if(copy_from_user((void*)epm_page, (void *) addr->copied, PAGE_SIZE) != 0) + ret = -ENOEXEC; + break; + case USER_FULL: + epm_page = epm_alloc_user_page(enclave->epm, addr->va); + if(copy_from_user((void*)epm_page, (void *) addr->copied, PAGE_SIZE) != 0) + ret = -ENOEXEC; + break; + default: + ret = -ENOSYS; + } return ret; - } +} + - destroy_enclave(enclave); - enclave_idr_remove(ueid); +int keystone_destroy_enclave(struct file *filp, unsigned long arg) { + int ret; + struct keystone_ioctl_create_enclave *enclp = (struct keystone_ioctl_create_enclave *) arg; + unsigned long ueid = enclp->eid; + enclave_t *enclave; + enclave = get_enclave_by_id(ueid); - return 0; + if (!enclave) { + keystone_err("invalid enclave id\n"); + return -EINVAL; + } + ret = SBI_CALL_1(SBI_SM_DESTROY_ENCLAVE, enclave->eid); + if (ret) { + keystone_err("fatal: cannot destroy enclave: SBI failed\n"); + return ret; + } + + destroy_enclave(enclave); + enclave_idr_remove(ueid); + + return 0; } -int keystone_run_enclave(struct file* filp, unsigned long arg) -{ - int ret = 0; - struct keystone_ioctl_run_enclave *run = (struct keystone_ioctl_run_enclave*) arg; - unsigned long ueid = run->eid; - enclave_t* enclave; - enclave = get_enclave_by_id(ueid); - - if(!enclave) - { - keystone_err("invalid enclave id\n"); - return -EINVAL; - } - - ret = SBI_CALL_1(SBI_SM_RUN_ENCLAVE, enclave->eid); - /* if the enclave is timer-interrupted, just resume the enclave */ - while(ret == ENCLAVE_INTERRUPTED) - { - keystone_handle_interrupts(); - ret = SBI_CALL_1(SBI_SM_RESUME_ENCLAVE, enclave->eid); - } +int keystone_run_enclave(struct file *filp, unsigned long arg) { + int ret = 0; + struct keystone_ioctl_run_enclave *run = (struct keystone_ioctl_run_enclave *) arg; + unsigned long ueid = run->eid; + enclave_t *enclave; + enclave = get_enclave_by_id(ueid); + + if (!enclave) { + keystone_err("invalid enclave id\n"); + return -EINVAL; + } + + ret = SBI_CALL_1(SBI_SM_RUN_ENCLAVE, enclave->eid); + /* if the enclave is timer-interrupted, just resume the enclave */ + while (ret == ENCLAVE_INTERRUPTED) { + keystone_handle_interrupts(); + ret = SBI_CALL_1(SBI_SM_RESUME_ENCLAVE, enclave->eid); + } - return ret; + return ret; } -int keystone_resume_enclave(struct file* filp, unsigned long arg) -{ - int ret = 0; - struct keystone_ioctl_run_enclave *resume = (struct keystone_ioctl_run_enclave*) arg; - unsigned long ueid = resume->eid; - enclave_t* enclave; - enclave = get_enclave_by_id(ueid); - - if(!enclave) - { - keystone_err("invalid enclave id\n"); - return -EINVAL; - } - - ret = SBI_CALL_1(SBI_SM_RESUME_ENCLAVE, enclave->eid); - while(ret == ENCLAVE_INTERRUPTED) - { - keystone_handle_interrupts(); +int keystone_resume_enclave(struct file *filp, unsigned long arg) { + int ret = 0; + struct keystone_ioctl_run_enclave *resume = (struct keystone_ioctl_run_enclave *) arg; + unsigned long ueid = resume->eid; + enclave_t *enclave; + enclave = get_enclave_by_id(ueid); + + if (!enclave) { + keystone_err("invalid enclave id\n"); + return -EINVAL; + } + ret = SBI_CALL_1(SBI_SM_RESUME_ENCLAVE, enclave->eid); - } + while (ret == ENCLAVE_INTERRUPTED) { + keystone_handle_interrupts(); + ret = SBI_CALL_1(SBI_SM_RESUME_ENCLAVE, enclave->eid); + } - return ret; + return ret; } -long keystone_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - long ret; - char data[256]; - size_t ioc_size; +long keystone_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { + long ret; + char data[256]; + size_t ioc_size; + +// pr_info("keystone_enclave: keystone_ioctl() command = %d\n",cmd); +// pr_info("keystone_enclave:arg addr = %px\n", arg); + + if (!arg) + return -EINVAL; - //pr_info("keystone_enclave: keystone_ioctl() command = %d\n",cmd); + ioc_size = _IOC_SIZE(cmd); +// pr_info("ioc_size: %d\n", ioc_size); + ioc_size = ioc_size > sizeof(data) ? sizeof(data) : ioc_size; - if(!arg) - return -EINVAL; - - ioc_size = _IOC_SIZE(cmd); - ioc_size = ioc_size > sizeof(data) ? sizeof(data) : ioc_size; - if(copy_from_user(data, (void __user*) arg, ioc_size)) + + if (copy_from_user(data,(void __user + *) arg, ioc_size)) return -EFAULT; - switch(cmd) - { - case KEYSTONE_IOC_CREATE_ENCLAVE: - ret = keystone_create_enclave(filep, (unsigned long) data); - break; - case KEYSTONE_IOC_DESTROY_ENCLAVE: - ret = keystone_destroy_enclave(filep, (unsigned long) data); - break; - case KEYSTONE_IOC_RUN_ENCLAVE: - ret = keystone_run_enclave(filep, (unsigned long) data); - break; - case KEYSTONE_IOC_RESUME_ENCLAVE: - ret = keystone_resume_enclave(filep, (unsigned long) data); - break; - default: - return -ENOSYS; - } - - if(copy_to_user((void __user*) arg, data, ioc_size)) + switch (cmd) { + case KEYSTONE_IOC_CREATE_ENCLAVE: + ret = keystone_create_enclave(filep, (unsigned long) data); + break; + case KEYSTONE_IOC_ADD_PAGE: + ret = keystone_add_page((unsigned long) data); + break; + case KEYSTONE_IOC_FINALIZE_ENCLAVE: + ret = keystone_finalize_enclave(filep, (unsigned long) data); + break; + case KEYSTONE_IOC_DESTROY_ENCLAVE: + ret = keystone_destroy_enclave(filep, (unsigned long) data); + break; + case KEYSTONE_IOC_RUN_ENCLAVE: + ret = keystone_run_enclave(filep, (unsigned long) data); + break; + case KEYSTONE_IOC_RESUME_ENCLAVE: + ret = keystone_resume_enclave(filep, (unsigned long) data); + break; + default: + return -ENOSYS; + } + + if (copy_to_user((void __user + *) arg, data, ioc_size)) return -EFAULT; - - return ret; + + return ret; } diff --git a/keystone-page.c b/keystone-page.c index 046e22a68..40e5c51aa 100644 --- a/keystone-page.c +++ b/keystone-page.c @@ -132,6 +132,8 @@ int utm_init(utm_t* utm, size_t untrusted_size) utm->ptr = (void*) __get_free_pages(GFP_HIGHUSER, order); if (!utm->ptr) { + pr_info("%lu\n", order); + keystone_warn("Fail, get free-page\n"); return -ENOMEM; } @@ -217,12 +219,14 @@ vaddr_t epm_alloc_page(epm_t* epm, vaddr_t addr, unsigned long flags) { pte_t* pte = __ept_walk_create(&epm->epm_free_list, epm->root_page_table, addr); vaddr_t page_addr = get_free_page(&epm->epm_free_list); +// pr_info("pte: %px, addr: %px\n", pte, addr); *pte = pte_create(ppn(page_addr), flags | PTE_V); return page_addr; } vaddr_t epm_alloc_rt_page_noexec(epm_t* epm, vaddr_t addr) { +// pr_info("va: %px", addr); return epm_alloc_page(epm, addr, PTE_D | PTE_A | PTE_R | PTE_W); } diff --git a/keystone-rtld.c b/keystone-rtld.c index b09ae54bd..71f67f401 100644 --- a/keystone-rtld.c +++ b/keystone-rtld.c @@ -86,13 +86,13 @@ void rtld_vm_mmap(epm_t* epm, vaddr_t encl_addr, unsigned long size, for(va=va_start, k=0; va < va_end; va += PAGE_SIZE, k++) { vaddr_t epm_page; + //Returns address of va back, maps va to a new page in enclave private memory epm_page = epm_alloc_rt_page(epm, va); //pr_info("encl_mmap va: 0x%lx, target: 0x%lx\n", va, epm_page); if(copy_from_user((void*)epm_page, rt_ptr + pos, PAGE_SIZE)){ keystone_err("failed to copy runtime\n"); } pos += PAGE_SIZE; - //debug_dump(epm_page, PAGE_SIZE); } } @@ -111,8 +111,7 @@ int keystone_app_load_elf_section_NOBITS(epm_t* epm, } return ret; - - + } int keystone_app_load_elf_region(epm_t* epm, void* __user elf_usr_region, @@ -252,8 +251,8 @@ int keystone_rtld_init_app(enclave_t* enclave, void* __user app_ptr, size_t app_ epm = enclave->epm; /* setup enclave stack */ - for (vaddr = stack_offset - PAGE_UP(app_stack_sz); - vaddr < stack_offset; + for (vaddr = stack_offset - PAGE_UP(app_stack_sz); + vaddr < stack_offset; vaddr += PAGE_SIZE) { epm_alloc_user_page_noexec(epm, vaddr); } @@ -274,6 +273,11 @@ int keystone_rtld_init_runtime(enclave_t* enclave, void* __user rt_ptr, size_t r epm = enclave->epm; + + /* rt_ptr = ELF runtime pointer + * + * + * */ error = -ENOEXEC; if(copy_from_user(&elf_ex, rt_ptr, sizeof(struct elfhdr)) != 0){ keystone_err("failed to read runtime header\n"); @@ -316,6 +320,12 @@ int keystone_rtld_init_runtime(enclave_t* enclave, void* __user rt_ptr, size_t r keystone_warn("keystone runtime includes an inconsistent program header\n"); continue; } + /* + * p_filesz = Number of bytes of segment + * p_memsz = Number of bytes in the memory segment of ELF + * p_memsz >= p_filesz, since this segment may have a bss + * + * */ vaddr = eppnt->p_vaddr; if(vaddr < *rt_offset) { *rt_offset = vaddr; @@ -324,9 +334,11 @@ int keystone_rtld_init_runtime(enclave_t* enclave, void* __user rt_ptr, size_t r if(size > eppnt->p_memsz) { pr_info("unexpected mismatch in elf program header: filesz %ld, memsz %llu\n", size, eppnt->p_memsz); } + + //Requires kernel privileges to do rtld_vm_mmap(epm, vaddr, size, rt_ptr, eppnt); } - + //Requires kernel privileges to do rtld_setup_stack(epm, -1UL, PAGE_UP(rt_stack_sz)); error = 0; @@ -338,6 +350,10 @@ int keystone_rtld_init_runtime(enclave_t* enclave, void* __user rt_ptr, size_t r int keystone_rtld_init_untrusted(enclave_t* enclave, void* untrusted_va, size_t untrusted_size) { + + /* Enclave has access to a shared memory buffer w/ host + * + * */ vaddr_t va; vaddr_t va_start = PAGE_DOWN((vaddr_t) untrusted_va); vaddr_t va_end = PAGE_UP((vaddr_t)untrusted_va + untrusted_size); diff --git a/keystone.h b/keystone.h index 9ebf85f4a..704443ccd 100644 --- a/keystone.h +++ b/keystone.h @@ -93,6 +93,7 @@ typedef struct keystone_enclave_t } enclave_t; + // global debug functions void debug_dump(char* ptr, unsigned long size); @@ -135,10 +136,10 @@ void epm_free_page(epm_t* epm, vaddr_t addr); unsigned long calculate_required_pages( - unsigned long eapp_sz, - unsigned long eapp_stack_sz, - unsigned long rt_sz, - unsigned long rt_stack_sz); + unsigned long eapp_sz, + unsigned long eapp_stack_sz, + unsigned long rt_sz, + unsigned long rt_stack_sz); #define keystone_info(fmt, ...) \ pr_info("keystone_enclave: " fmt, ##__VA_ARGS__) diff --git a/keystone_user.h b/keystone_user.h index 19accf097..b816d8ef5 100644 --- a/keystone_user.h +++ b/keystone_user.h @@ -19,37 +19,63 @@ _IOR(KEYSTONE_IOC_MAGIC, 0x04, struct keystone_ioctl_run_enclave) #define KEYSTONE_IOC_RESUME_ENCLAVE \ _IOR(KEYSTONE_IOC_MAGIC, 0x05, struct keystone_ioctl_run_enclave) +#define KEYSTONE_IOC_ADD_PAGE \ + _IOR(KEYSTONE_IOC_MAGIC, 0x06, struct addr_packed) +#define KEYSTONE_IOC_FINALIZE_ENCLAVE \ + _IOR(KEYSTONE_IOC_MAGIC, 0x07, struct keystone_ioctl_create_enclave) + + + +#define RT_NOEXEC 0 +#define USER_NOEXEC 1 +#define RT_FULL 2 +#define USER_FULL 3 + +#undef ELF_CLASS +#define ELF_CLASS ELFCLASS32 + struct runtime_params_t { - __u64 runtime_entry; - __u64 user_entry; - __u64 untrusted_ptr; - __u64 untrusted_size; + __u64 runtime_entry; + __u64 user_entry; + __u64 untrusted_ptr; + __u64 untrusted_size; }; struct keystone_ioctl_create_enclave { - __u64 eid; - - // User ELF - __u64 user_elf_ptr; - __u64 user_elf_size; - __u64 user_stack_size; - - // Runtime ELF - __u64 runtime_elf_ptr; - __u64 runtime_elf_size; - __u64 runtime_stack_size; - - // Runtime Parameters - struct runtime_params_t params; + __u64 eid; + + //Min page required + __u64 min_pages; + + // Runtime Parameters + struct runtime_params_t params; + }; struct keystone_ioctl_run_enclave { - __u64 eid; - __u64 entry; - __u64 args_ptr; - __u64 args_size; - __u64 ret; + __u64 eid; + __u64 entry; + __u64 args_ptr; + __u64 args_size; + __u64 ret; }; +struct addr_packed { + vaddr_t va; + vaddr_t copied; + unsigned int eid; + unsigned int mode; +}; + +struct mapped_meta { + struct addr_packed *meta; + int num_pages; + unsigned int eid; + unsigned int mode; +}; + + + + #endif