diff --git a/Pal/src/host/Linux-SGX/db_files.c b/Pal/src/host/Linux-SGX/db_files.c index b6d44574..f0ea9898 100644 --- a/Pal/src/host/Linux-SGX/db_files.c +++ b/Pal/src/host/Linux-SGX/db_files.c @@ -412,7 +412,6 @@ static int file_map(PAL_HANDLE handle, void** addr, int prot, uint64_t offset, u sgx_stub_t* stubs = (sgx_stub_t*)handle->file.stubs; uint64_t total = handle->file.total; void* mem = *addr; - void* umem; int ret; /* @@ -451,6 +450,7 @@ static int file_map(PAL_HANDLE handle, void** addr, int prot, uint64_t offset, u map_end = ALLOC_ALIGN_UP(end); } + void* umem = NULL; ret = ocall_mmap_untrusted(handle->file.fd, map_start, map_end - map_start, PROT_READ, &umem); if (IS_ERR(ret)) { SGX_DBG(DBG_E, "file_map - ocall returned %d\n", ret); diff --git a/Pal/src/host/Linux-SGX/db_rtld.c b/Pal/src/host/Linux-SGX/db_rtld.c index 1763a05c..ca37abfa 100644 --- a/Pal/src/host/Linux-SGX/db_rtld.c +++ b/Pal/src/host/Linux-SGX/db_rtld.c @@ -145,7 +145,7 @@ void _DkDebugAddMap(struct link_map* map) { shdr = __alloca(shdrsz); unsigned long s = ALLOC_ALIGN_DOWN(ehdr->e_shoff); unsigned long e = ALLOC_ALIGN_UP(ehdr->e_shoff + shdrsz); - void* umem; + void* umem = NULL; ocall_mmap_untrusted(fd, s, e - s, PROT_READ, &umem); memcpy(shdr, umem + ehdr->e_shoff - s, shdrsz); ocall_munmap_untrusted(umem, e - s); @@ -167,7 +167,7 @@ void _DkDebugAddMap(struct link_map* map) { shstrtab = __alloca(shstrsz); unsigned long s = ALLOC_ALIGN_DOWN(shstroff); unsigned long e = ALLOC_ALIGN_UP(shstroff + shstrsz); - void* umem; + void* umem = NULL; ocall_mmap_untrusted(fd, s, e - s, PROT_READ, &umem); memcpy((void*)shstrtab, umem + shstroff - s, shstrsz); ocall_munmap_untrusted(umem, e - s); diff --git a/Pal/src/host/Linux-SGX/enclave_framework.c b/Pal/src/host/Linux-SGX/enclave_framework.c index d551c2d5..ab024113 100644 --- a/Pal/src/host/Linux-SGX/enclave_framework.c +++ b/Pal/src/host/Linux-SGX/enclave_framework.c @@ -359,7 +359,7 @@ int load_trusted_file(PAL_HANDLE file, sgx_stub_t** stubptr, uint64_t* sizeptr, * caller's responsibility to unmap those areas after use */ *sizeptr = tf->size; if (*sizeptr) { - ret = ocall_mmap_untrusted(fd, 0, tf->size, PROT_READ, umem); + ret = ocall_mmap_untrusted(fd, /*offset=*/0, tf->size, PROT_READ, umem); if (IS_ERR(ret)) { *umem = NULL; ret = unix_to_pal_error(ERRNO(ret)); diff --git a/Pal/src/host/Linux-SGX/enclave_ocalls.c b/Pal/src/host/Linux-SGX/enclave_ocalls.c index 37e383e9..c74a429b 100644 --- a/Pal/src/host/Linux-SGX/enclave_ocalls.c +++ b/Pal/src/host/Linux-SGX/enclave_ocalls.c @@ -153,15 +153,38 @@ int ocall_mmap_untrusted(int fd, uint64_t offset, size_t size, unsigned short pr return -EPERM; } + if (!mem || (*mem && !sgx_is_completely_outside_enclave(*mem, size))) { + sgx_reset_ustack(old_ustack); + return -EINVAL; + } + + if (*mem && !IS_ALLOC_ALIGNED_PTR(*mem)) { + /* fixed address must be correctly aligned */ + sgx_reset_ustack(old_ustack); + return -EINVAL; + } + WRITE_ONCE(ms->ms_fd, fd); WRITE_ONCE(ms->ms_offset, offset); WRITE_ONCE(ms->ms_size, size); WRITE_ONCE(ms->ms_prot, prot); + WRITE_ONCE(ms->ms_mem, *mem); retval = sgx_exitless_ocall(OCALL_MMAP_UNTRUSTED, ms); + if (IS_ERR(retval) && !IS_UNIX_ERR(retval)) { + sgx_reset_ustack(old_ustack); + return -EPERM; + } + + void* returned_mem = READ_ONCE(ms->ms_mem); + if (*mem && returned_mem != *mem) { + /* requested to mmap at a fixed address but OCALL returned another address */ + sgx_reset_ustack(old_ustack); + return -EPERM; + } if (!retval) { - if (!sgx_copy_ptr_to_enclave(mem, READ_ONCE(ms->ms_mem), size)) { + if (!sgx_copy_ptr_to_enclave(mem, returned_mem, size)) { sgx_reset_ustack(old_ustack); return -EPERM; } @@ -191,6 +214,8 @@ int ocall_munmap_untrusted(const void* mem, size_t size) { WRITE_ONCE(ms->ms_size, size); retval = sgx_exitless_ocall(OCALL_MUNMAP_UNTRUSTED, ms); + if (IS_ERR(retval) && !IS_UNIX_ERR(retval)) + retval = -EPERM; sgx_reset_ustack(old_ustack); return retval; @@ -209,15 +234,20 @@ int ocall_munmap_untrusted(const void* mem, size_t size) { * indicates whether explicit munmap is needed at the end of such OCALL. */ static int ocall_mmap_untrusted_cache(size_t size, void** mem, bool* need_munmap) { + int ret; + + *mem = NULL; *need_munmap = false; + struct untrusted_area* cache = &get_tcb_trts()->untrusted_area_cache; + uint64_t in_use = 0; if (!__atomic_compare_exchange_n(&cache->in_use, &in_use, 1, /*weak=*/false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { /* AEX signal handling case: cache is in use, so make explicit mmap/munmap */ - int retval = ocall_mmap_untrusted(-1, 0, size, PROT_READ | PROT_WRITE, mem); - if (IS_ERR(retval)) { - return retval; + ret = ocall_mmap_untrusted(/*fd=*/-1, /*offset=*/0, size, PROT_READ | PROT_WRITE, mem); + if (IS_ERR(ret)) { + return ret; } *need_munmap = true; return 0; @@ -229,16 +259,16 @@ static int ocall_mmap_untrusted_cache(size_t size, void** mem, bool* need_munmap *mem = cache->mem; return 0; } - int retval = ocall_munmap_untrusted(cache->mem, cache->size); - if (IS_ERR(retval)) { + ret = ocall_munmap_untrusted(cache->mem, cache->size); + if (IS_ERR(ret)) { cache->valid = false; __atomic_store_n(&cache->in_use, 0, __ATOMIC_RELAXED); - return retval; + return ret; } } - int retval = ocall_mmap_untrusted(-1, 0, size, PROT_READ | PROT_WRITE, mem); - if (IS_ERR(retval)) { + ret = ocall_mmap_untrusted(/*fd=*/-1, /*offset=*/0, size, PROT_READ | PROT_WRITE, mem); + if (IS_ERR(ret)) { cache->valid = false; __atomic_store_n(&cache->in_use, 0, __ATOMIC_RELAXED); } else { @@ -246,7 +276,7 @@ static int ocall_mmap_untrusted_cache(size_t size, void** mem, bool* need_munmap cache->mem = *mem; cache->size = size; } - return retval; + return ret; } static void ocall_munmap_untrusted_cache(void* mem, size_t size, bool need_munmap) { diff --git a/Pal/src/host/Linux-SGX/enclave_untrusted.c b/Pal/src/host/Linux-SGX/enclave_untrusted.c index 70c95667..470ec1c1 100644 --- a/Pal/src/host/Linux-SGX/enclave_untrusted.c +++ b/Pal/src/host/Linux-SGX/enclave_untrusted.c @@ -19,9 +19,8 @@ static size_t g_page_size = PRESET_PAGESIZE; static inline void* __malloc(int size) { void* addr = NULL; - - ocall_mmap_untrusted(-1, 0, size, PROT_READ | PROT_WRITE, &addr); - return addr; + int ret = ocall_mmap_untrusted(/*fd=*/-1, /*offset=*/0, size, PROT_READ | PROT_WRITE, &addr); + return IS_ERR(ret) ? NULL : addr; } #define system_malloc(size) __malloc(size) diff --git a/Pal/src/host/Linux-SGX/sgx_enclave.c b/Pal/src/host/Linux-SGX/sgx_enclave.c index c7e5ef7f..81dff515 100644 --- a/Pal/src/host/Linux-SGX/sgx_enclave.c +++ b/Pal/src/host/Linux-SGX/sgx_enclave.c @@ -90,13 +90,14 @@ static long sgx_ocall_exit(void* pms) { static long sgx_ocall_mmap_untrusted(void* pms) { ms_ocall_mmap_untrusted_t* ms = (ms_ocall_mmap_untrusted_t*)pms; void* addr; - ODEBUG(OCALL_MMAP_UNTRUSTED, ms); - addr = (void*)INLINE_SYSCALL(mmap, 6, NULL, ms->ms_size, - ms->ms_prot, - (ms->ms_fd == -1) ? MAP_ANONYMOUS | MAP_PRIVATE - : MAP_FILE | MAP_SHARED, - ms->ms_fd, ms->ms_offset); + + /* NOTE: enclave never asks for fixed address 0x0, so ms_mem == NULL means "no fixed addr" */ + int flags = ms->ms_mem ? MAP_FIXED : 0; + flags |= (ms->ms_fd == -1) ? MAP_ANONYMOUS | MAP_PRIVATE : MAP_FILE | MAP_SHARED; + + addr = (void*)INLINE_SYSCALL(mmap, 6, ms->ms_mem, ms->ms_size, ms->ms_prot, flags, ms->ms_fd, + ms->ms_offset); if (IS_ERR_P(addr)) return -ERRNO_P(addr);