[Pal/Linux-SGX] Allow ocall_mmap_untrusted() with fixed address

This functionality is currently not used by Linux-SGX PAL but will be
required in the IOCTL emulation in future commits. Also, function
signatures of ocall_mmap_untrusted() and ocall_munmap_untrusted() now
resemble the signatures of mmap() and munmap().
This commit is contained in:
Dmitrii Kuvaiskii
2021-01-04 05:42:24 -08:00
parent 05ed29f52d
commit 95cd78c3c8
9 changed files with 92 additions and 53 deletions
+5 -3
View File
@@ -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;
/*
@@ -421,7 +420,8 @@ static int file_map(PAL_HANDLE handle, void** addr, int prot, uint64_t offset, u
* does not request a specific address.
*/
if (!mem && !stubs && !(prot & PAL_PROT_WRITECOPY)) {
ret = ocall_mmap_untrusted(handle->file.fd, offset, size, PAL_PROT_TO_LINUX(prot), &mem);
ret = ocall_mmap_untrusted(&mem, size, PAL_PROT_TO_LINUX(prot), MAP_SHARED, handle->file.fd,
offset);
if (!IS_ERR(ret))
*addr = mem;
return IS_ERR(ret) ? unix_to_pal_error(ERRNO(ret)) : ret;
@@ -451,7 +451,9 @@ static int file_map(PAL_HANDLE handle, void** addr, int prot, uint64_t offset, u
map_end = ALLOC_ALIGN_UP(end);
}
ret = ocall_mmap_untrusted(handle->file.fd, map_start, map_end - map_start, PROT_READ, &umem);
void* umem = NULL;
ret = ocall_mmap_untrusted(&umem, map_end - map_start, PROT_READ, MAP_SHARED, handle->file.fd,
map_start);
if (IS_ERR(ret)) {
SGX_DBG(DBG_E, "file_map - ocall returned %d\n", ret);
return unix_to_pal_error(ERRNO(ret));
+4 -4
View File
@@ -145,8 +145,8 @@ 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;
ocall_mmap_untrusted(fd, s, e - s, PROT_READ, &umem);
void* umem = NULL;
ocall_mmap_untrusted(&umem, e - s, PROT_READ, MAP_SHARED, fd, s);
memcpy(shdr, umem + ehdr->e_shoff - s, shdrsz);
ocall_munmap_untrusted(umem, e - s);
}
@@ -167,8 +167,8 @@ 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;
ocall_mmap_untrusted(fd, s, e - s, PROT_READ, &umem);
void* umem = NULL;
ocall_mmap_untrusted(&umem, e - s, PROT_READ, MAP_SHARED, fd, s);
memcpy((void*)shstrtab, umem + shstroff - s, shstrsz);
ocall_munmap_untrusted(umem, e - s);
}
+1 -1
View File
@@ -381,7 +381,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(umem, tf->size, PROT_READ, MAP_SHARED, fd, /*offset=*/0);
if (IS_ERR(ret)) {
*umem = NULL;
ret = unix_to_pal_error(ERRNO(ret));
+66 -26
View File
@@ -158,7 +158,7 @@ noreturn void ocall_exit(int exitcode, int is_exitgroup) {
}
}
int ocall_mmap_untrusted(int fd, uint64_t offset, size_t size, unsigned short prot, void** mem) {
int ocall_mmap_untrusted(void** addrptr, size_t size, int prot, int flags, int fd, off_t offset) {
int retval = 0;
ms_ocall_mmap_untrusted_t* ms;
@@ -169,49 +169,82 @@ int ocall_mmap_untrusted(int fd, uint64_t offset, size_t size, unsigned short pr
return -EPERM;
}
WRITE_ONCE(ms->ms_fd, fd);
WRITE_ONCE(ms->ms_offset, offset);
if (!addrptr) {
sgx_reset_ustack(old_ustack);
return -EINVAL;
}
void* requested_addr = *addrptr;
if (flags & MAP_FIXED) {
if (!sgx_is_completely_outside_enclave(requested_addr, size) ||
!IS_ALLOC_ALIGNED_PTR(requested_addr)) {
sgx_reset_ustack(old_ustack);
return -EINVAL;
}
} else {
requested_addr = NULL; /* for sanity */
}
WRITE_ONCE(ms->ms_addr, requested_addr);
WRITE_ONCE(ms->ms_size, size);
WRITE_ONCE(ms->ms_prot, prot);
WRITE_ONCE(ms->ms_flags, flags);
WRITE_ONCE(ms->ms_fd, fd);
WRITE_ONCE(ms->ms_offset, offset);
do {
retval = sgx_exitless_ocall(OCALL_MMAP_UNTRUSTED, ms);
} while (retval == -EINTR);
if (!retval) {
if (!sgx_copy_ptr_to_enclave(mem, READ_ONCE(ms->ms_mem), size)) {
if (IS_ERR(retval)) {
sgx_reset_ustack(old_ustack);
return IS_UNIX_ERR(retval) ? retval : -EPERM;
}
void* returned_addr = READ_ONCE(ms->ms_addr);
if (flags & MAP_FIXED) {
/* addrptr already contains the mmap'ed address, no need to update it */
if (returned_addr != requested_addr) {
sgx_reset_ustack(old_ustack);
return -EPERM;
}
} else {
/* update addrptr with the mmap'ed address */
if (!sgx_copy_ptr_to_enclave(addrptr, returned_addr, size)) {
sgx_reset_ustack(old_ustack);
return -EPERM;
}
}
sgx_reset_ustack(old_ustack);
return retval;
return 0;
}
int ocall_munmap_untrusted(const void* mem, size_t size) {
int ocall_munmap_untrusted(const void* addr, size_t size) {
int retval = 0;
ms_ocall_munmap_untrusted_t* ms;
void* old_ustack = sgx_prepare_ustack();
if (!sgx_is_completely_outside_enclave(mem, size)) {
sgx_reset_ustack(old_ustack);
if (!sgx_is_completely_outside_enclave(addr, size) || !IS_ALLOC_ALIGNED_PTR(addr))
return -EINVAL;
}
void* old_ustack = sgx_prepare_ustack();
ms = sgx_alloc_on_ustack_aligned(sizeof(*ms), alignof(*ms));
if (!ms) {
sgx_reset_ustack(old_ustack);
return -EPERM;
}
WRITE_ONCE(ms->ms_mem, mem);
WRITE_ONCE(ms->ms_addr, addr);
WRITE_ONCE(ms->ms_size, size);
do {
retval = sgx_exitless_ocall(OCALL_MUNMAP_UNTRUSTED, ms);
} while (retval == -EINTR);
if (IS_ERR(retval) && !IS_UNIX_ERR(retval))
retval = -EPERM;
sgx_reset_ustack(old_ustack);
return retval;
}
@@ -228,16 +261,22 @@ int ocall_munmap_untrusted(const void* mem, size_t size) {
* handling do not use the cache and always explicitly mmap/munmap untrusted memory; 'need_munmap'
* 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) {
static int ocall_mmap_untrusted_cache(size_t size, void** addrptr, bool* need_munmap) {
int ret;
*addrptr = 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(addrptr, size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, /*fd=*/-1, /*offset=*/0);
if (IS_ERR(ret)) {
return ret;
}
*need_munmap = true;
return 0;
@@ -246,32 +285,33 @@ static int ocall_mmap_untrusted_cache(size_t size, void** mem, bool* need_munmap
/* normal execution case: cache was not in use, so use it/allocate new one for reuse */
if (cache->valid) {
if (cache->size >= size) {
*mem = cache->mem;
*addrptr = cache->addr;
return 0;
}
int retval = ocall_munmap_untrusted(cache->mem, cache->size);
if (IS_ERR(retval)) {
ret = ocall_munmap_untrusted(cache->addr, 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(addrptr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
/*fd=*/-1, /*offset=*/0);
if (IS_ERR(ret)) {
cache->valid = false;
__atomic_store_n(&cache->in_use, 0, __ATOMIC_RELAXED);
} else {
cache->valid = true;
cache->mem = *mem;
cache->addr = *addrptr;
cache->size = size;
}
return retval;
return ret;
}
static void ocall_munmap_untrusted_cache(void* mem, size_t size, bool need_munmap) {
static void ocall_munmap_untrusted_cache(void* addr, size_t size, bool need_munmap) {
if (need_munmap) {
ocall_munmap_untrusted(mem, size);
ocall_munmap_untrusted(addr, size);
/* there is not much we can do in case of error */
} else {
struct untrusted_area* cache = &get_tcb_trts()->untrusted_area_cache;
+2 -2
View File
@@ -14,9 +14,9 @@
noreturn void ocall_exit(int exitcode, int is_exitgroup);
int ocall_mmap_untrusted(int fd, uint64_t offset, uint64_t size, unsigned short prot, void** mem);
int ocall_mmap_untrusted(void** addrptr, size_t size, int prot, int flags, int fd, off_t offset);
int ocall_munmap_untrusted(const void* mem, uint64_t size);
int ocall_munmap_untrusted(const void* addr, size_t size);
int ocall_cpuid(unsigned int leaf, unsigned int subleaf, unsigned int values[4]);
+3 -3
View File
@@ -19,9 +19,9 @@ 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(&addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
/*fd=*/-1, /*offset=*/0);
return IS_ERR(ret) ? NULL : addr;
}
#define system_malloc(size) __malloc(size)
+6 -5
View File
@@ -73,15 +73,16 @@ typedef struct {
} ms_ocall_exit_t;
typedef struct {
int ms_fd;
uint64_t ms_offset;
void* ms_addr;
size_t ms_size;
unsigned short ms_prot;
void* ms_mem;
int ms_prot;
int ms_flags;
int ms_fd;
off_t ms_offset;
} ms_ocall_mmap_untrusted_t;
typedef struct {
const void* ms_mem;
const void* ms_addr;
size_t ms_size;
} ms_ocall_munmap_untrusted_t;
+4 -8
View File
@@ -96,25 +96,21 @@ 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,
addr = (void*)INLINE_SYSCALL(mmap, 6, ms->ms_addr, ms->ms_size, ms->ms_prot, ms->ms_flags,
ms->ms_fd, ms->ms_offset);
if (IS_ERR_P(addr))
return -ERRNO_P(addr);
ms->ms_mem = addr;
ms->ms_addr = addr;
return 0;
}
static long sgx_ocall_munmap_untrusted(void* pms) {
ms_ocall_munmap_untrusted_t* ms = (ms_ocall_munmap_untrusted_t*)pms;
ODEBUG(OCALL_MUNMAP_UNTRUSTED, ms);
INLINE_SYSCALL(munmap, 2, ALLOC_ALIGN_DOWN_PTR(ms->ms_mem),
ALLOC_ALIGN_UP_PTR(ms->ms_mem + ms->ms_size) - ALLOC_ALIGN_DOWN_PTR(ms->ms_mem));
INLINE_SYSCALL(munmap, 2, ms->ms_addr, ms->ms_size);
return 0;
}
+1 -1
View File
@@ -6,7 +6,7 @@
#include "pal.h"
struct untrusted_area {
void* mem;
void* addr;
size_t size;
uint64_t in_use; /* must be uint64_t, because SET_ENCLAVE_TLS() currently supports only 8-byte
* types. TODO: fix this. */