Implement memory access bound check with hardware trap for 64-bit platforms (#293)
Also implement native stack overflow check with hardware trap for 64-bit platforms Refine classic interpreter and fast interpreter to improve performance Update document
This commit is contained in:
@ -42,19 +42,21 @@ os_free(void *ptr)
|
||||
}
|
||||
|
||||
void *
|
||||
os_mmap(void *hint, unsigned int size, int prot, int flags)
|
||||
os_mmap(void *hint, size_t size, int prot, int flags)
|
||||
{
|
||||
return BH_MALLOC(size);
|
||||
if ((uint64)size >= UINT32_MAX)
|
||||
return NULL;
|
||||
return BH_MALLOC((uint32)size);
|
||||
}
|
||||
|
||||
void
|
||||
os_munmap(void *addr, uint32 size)
|
||||
os_munmap(void *addr, size_t size)
|
||||
{
|
||||
return BH_FREE(addr);
|
||||
}
|
||||
|
||||
int
|
||||
os_mprotect(void *addr, uint32 size, int prot)
|
||||
os_mprotect(void *addr, size_t size, int prot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -48,6 +48,38 @@ typedef pthread_mutex_t korp_mutex;
|
||||
typedef pthread_cond_t korp_cond;
|
||||
typedef pthread_t korp_thread;
|
||||
|
||||
#if WASM_DISABLE_HW_BOUND_CHECK == 0
|
||||
#if defined(BUILD_TARGET_X86_64) \
|
||||
|| defined(BUILD_TARGET_AMD_64) \
|
||||
|| defined(BUILD_TARGET_AARCH64)
|
||||
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#define OS_ENABLE_HW_BOUND_CHECK
|
||||
|
||||
#define os_thread_local_attribute __thread
|
||||
|
||||
typedef jmp_buf korp_jmpbuf;
|
||||
|
||||
#define os_setjmp setjmp
|
||||
#define os_longjmp longjmp
|
||||
#define os_alloca alloca
|
||||
|
||||
#define os_getpagesize getpagesize
|
||||
|
||||
typedef void (*os_signal_handler)(void *sig_addr);
|
||||
|
||||
int os_signal_init(os_signal_handler handler);
|
||||
|
||||
void os_signal_destroy();
|
||||
|
||||
void os_signal_unmask();
|
||||
|
||||
void os_sigreturn();
|
||||
#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */
|
||||
#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include "platform_api_vmcore.h"
|
||||
|
||||
void *
|
||||
os_mmap(void *hint, uint32 size, int prot, int flags)
|
||||
os_mmap(void *hint, size_t size, int prot, int flags)
|
||||
{
|
||||
int map_prot = PROT_NONE;
|
||||
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
|
||||
@ -17,7 +17,12 @@ os_mmap(void *hint, uint32 size, int prot, int flags)
|
||||
page_size = getpagesize();
|
||||
request_size = (size + page_size - 1) & ~(page_size - 1);
|
||||
|
||||
if (request_size >= UINT32_MAX)
|
||||
if ((size_t)request_size < size)
|
||||
/* integer overflow */
|
||||
return NULL;
|
||||
|
||||
if (request_size > 16 * (uint64)UINT32_MAX)
|
||||
/* At most 16 G is allowed */
|
||||
return NULL;
|
||||
|
||||
if (prot & MMAP_PROT_READ)
|
||||
@ -53,7 +58,7 @@ os_mmap(void *hint, uint32 size, int prot, int flags)
|
||||
}
|
||||
|
||||
void
|
||||
os_munmap(void *addr, uint32 size)
|
||||
os_munmap(void *addr, size_t size)
|
||||
{
|
||||
uint64 page_size = getpagesize();
|
||||
uint64 request_size = (size + page_size - 1) & ~(page_size - 1);
|
||||
@ -67,9 +72,11 @@ os_munmap(void *addr, uint32 size)
|
||||
}
|
||||
|
||||
int
|
||||
os_mprotect(void *addr, uint32 size, int prot)
|
||||
os_mprotect(void *addr, size_t size, int prot)
|
||||
{
|
||||
int map_prot = PROT_NONE;
|
||||
uint64 page_size = getpagesize();
|
||||
uint64 request_size = (size + page_size - 1) & ~(page_size - 1);
|
||||
|
||||
if (!addr)
|
||||
return 0;
|
||||
@ -83,7 +90,7 @@ os_mprotect(void *addr, uint32 size, int prot)
|
||||
if (prot & MMAP_PROT_EXEC)
|
||||
map_prot |= PROT_EXEC;
|
||||
|
||||
return mprotect(addr, size, map_prot);
|
||||
return mprotect(addr, request_size, map_prot);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -21,7 +21,7 @@ static void *os_thread_wrapper(void *arg)
|
||||
thread_wrapper_arg * targ = arg;
|
||||
thread_start_routine_t start_func = targ->start;
|
||||
void *thread_arg = targ->arg;
|
||||
printf("THREAD CREATE %p\n", &targ);
|
||||
os_printf("THREAD CREATED %p\n", &targ);
|
||||
targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff);
|
||||
BH_FREE(targ);
|
||||
start_func(thread_arg);
|
||||
@ -41,8 +41,8 @@ int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
|
||||
pthread_attr_init(&tattr);
|
||||
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
|
||||
if (pthread_attr_setstacksize(&tattr, stack_size) != 0) {
|
||||
printf("Invalid thread stack size %u. Min stack size on Linux = %u",
|
||||
stack_size, PTHREAD_STACK_MIN);
|
||||
os_printf("Invalid thread stack size %u. Min stack size on Linux = %u",
|
||||
stack_size, PTHREAD_STACK_MIN);
|
||||
pthread_attr_destroy(&tattr);
|
||||
return BHT_ERROR;
|
||||
}
|
||||
@ -123,7 +123,7 @@ int os_mutex_lock(korp_mutex *mutex)
|
||||
assert(mutex);
|
||||
ret = pthread_mutex_lock(mutex);
|
||||
if (0 != ret) {
|
||||
printf("vm mutex lock failed (ret=%d)!\n", ret);
|
||||
os_printf("vm mutex lock failed (ret=%d)!\n", ret);
|
||||
exit(-1);
|
||||
}
|
||||
return ret;
|
||||
@ -140,7 +140,7 @@ int os_mutex_unlock(korp_mutex *mutex)
|
||||
assert(mutex);
|
||||
ret = pthread_mutex_unlock(mutex);
|
||||
if (0 != ret) {
|
||||
printf("vm mutex unlock failed (ret=%d)!\n", ret);
|
||||
os_printf("vm mutex unlock failed (ret=%d)!\n", ret);
|
||||
exit(-1);
|
||||
}
|
||||
return ret;
|
||||
@ -241,15 +241,16 @@ uint8 *os_thread_get_stack_boundary()
|
||||
pthread_attr_t attr;
|
||||
uint8 *addr = NULL;
|
||||
size_t stack_size, guard_size;
|
||||
int page_size = getpagesize();
|
||||
|
||||
#ifdef __linux__
|
||||
if (pthread_getattr_np(self, &attr) == 0) {
|
||||
pthread_attr_getstack(&attr, (void**)&addr, &stack_size);
|
||||
pthread_attr_getguardsize(&attr, &guard_size);
|
||||
pthread_attr_destroy(&attr);
|
||||
if (guard_size < 4 * 1024)
|
||||
/* Reserved 4 KB guard size at least for safety */
|
||||
guard_size = 4 * 1024;
|
||||
if (guard_size < (size_t)page_size)
|
||||
/* Reserved 1 guard page at least for safety */
|
||||
guard_size = (size_t)page_size;
|
||||
addr += guard_size;
|
||||
}
|
||||
(void)stack_size;
|
||||
@ -257,10 +258,150 @@ uint8 *os_thread_get_stack_boundary()
|
||||
if ((addr = (uint8*)pthread_get_stackaddr_np(self))) {
|
||||
stack_size = pthread_get_stacksize_np(self);
|
||||
addr -= stack_size;
|
||||
/* Reserved 4 KB guard size at least for safety */
|
||||
addr += 4 * 1024;
|
||||
/* Reserved 1 guard page at least for safety */
|
||||
addr += page_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
|
||||
#define SIG_ALT_STACK_SIZE (32 * 1024)
|
||||
|
||||
/* The signal alternate stack base addr */
|
||||
static uint8 *sigalt_stack_base_addr;
|
||||
|
||||
/* The signal handler passed to os_signal_init() */
|
||||
static os_signal_handler signal_handler;
|
||||
|
||||
static void
|
||||
mask_signals(int how)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGSEGV);
|
||||
sigaddset(&set, SIGBUS);
|
||||
pthread_sigmask(how, &set, NULL);
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) static void
|
||||
signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext)
|
||||
{
|
||||
int i;
|
||||
void *sig_addr = sig_info->si_addr;
|
||||
|
||||
mask_signals(SIG_BLOCK);
|
||||
|
||||
if (signal_handler
|
||||
&& (sig_num == SIGSEGV || sig_num == SIGBUS)) {
|
||||
signal_handler(sig_addr);
|
||||
}
|
||||
|
||||
/* signal unhandled */
|
||||
switch (sig_num) {
|
||||
case SIGSEGV:
|
||||
os_printf("unhandled SIGSEGV, si_addr: %p\n", sig_addr);
|
||||
break;
|
||||
case SIGBUS:
|
||||
os_printf("unhandled SIGBUS, si_addr: %p\n", sig_addr);
|
||||
break;
|
||||
default:
|
||||
os_printf("unhandle signal %d, si_addr: %p\n",
|
||||
sig_num, sig_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* divived by 0 to make it abort */
|
||||
i = os_printf(" ");
|
||||
os_printf("%d\n", i / (i - 1));
|
||||
/* access NULL ptr to make it abort */
|
||||
os_printf("%d\n", *(uint32*)(uintptr_t)(i - 1));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
os_signal_init(os_signal_handler handler)
|
||||
{
|
||||
int ret = -1;
|
||||
struct sigaction sig_act;
|
||||
stack_t sigalt_stack_info;
|
||||
uint32 map_size = SIG_ALT_STACK_SIZE;
|
||||
uint8 *map_addr;
|
||||
|
||||
/* Initialize memory for signal alternate stack */
|
||||
if (!(map_addr = os_mmap(NULL, map_size,
|
||||
MMAP_PROT_READ | MMAP_PROT_WRITE,
|
||||
MMAP_MAP_NONE))) {
|
||||
os_printf("Failed to mmap memory for alternate stack\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize signal alternate stack */
|
||||
memset(map_addr, 0, map_size);
|
||||
sigalt_stack_info.ss_sp = map_addr;
|
||||
sigalt_stack_info.ss_size = map_size;
|
||||
sigalt_stack_info.ss_flags = 0;
|
||||
if ((ret = sigaltstack(&sigalt_stack_info, NULL)) != 0) {
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* Install signal hanlder */
|
||||
sig_act.sa_sigaction = signal_callback;
|
||||
sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
|
||||
sigemptyset(&sig_act.sa_mask);
|
||||
if ((ret = sigaction(SIGSEGV, &sig_act, NULL)) != 0
|
||||
|| (ret = sigaction(SIGBUS, &sig_act, NULL)) != 0) {
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
sigalt_stack_base_addr = map_addr;
|
||||
signal_handler = handler;
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
memset(&sigalt_stack_info, 0, sizeof(stack_t));
|
||||
sigalt_stack_info.ss_flags = SS_DISABLE;
|
||||
sigalt_stack_info.ss_size = map_size;
|
||||
sigaltstack(&sigalt_stack_info, NULL);
|
||||
fail1:
|
||||
os_munmap(map_addr, map_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
os_signal_destroy()
|
||||
{
|
||||
stack_t sigalt_stack_info;
|
||||
|
||||
/* Disable signal alternate stack */
|
||||
memset(&sigalt_stack_info, 0, sizeof(stack_t));
|
||||
sigalt_stack_info.ss_flags = SS_DISABLE;
|
||||
sigalt_stack_info.ss_size = SIG_ALT_STACK_SIZE;
|
||||
sigaltstack(&sigalt_stack_info, NULL);
|
||||
|
||||
os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE);
|
||||
}
|
||||
|
||||
void
|
||||
os_signal_unmask()
|
||||
{
|
||||
mask_signals(SIG_UNBLOCK);
|
||||
}
|
||||
|
||||
void
|
||||
os_sigreturn()
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
#define UC_RESET_ALT_STACK 0x80000000
|
||||
extern int __sigreturn(void *, int);
|
||||
|
||||
/* It's necessary to call __sigreturn to restore the sigaltstack state
|
||||
after exiting the signal handler. */
|
||||
__sigreturn(NULL, UC_RESET_ALT_STACK);
|
||||
#endif
|
||||
}
|
||||
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */
|
||||
|
||||
|
||||
@ -51,6 +51,38 @@ typedef pthread_t korp_thread;
|
||||
#define os_printf printf
|
||||
#define os_vprintf vprintf
|
||||
|
||||
#if WASM_DISABLE_HW_BOUND_CHECK == 0
|
||||
#if defined(BUILD_TARGET_X86_64) \
|
||||
|| defined(BUILD_TARGET_AMD_64) \
|
||||
|| defined(BUILD_TARGET_AARCH64)
|
||||
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#define OS_ENABLE_HW_BOUND_CHECK
|
||||
|
||||
#define os_thread_local_attribute __thread
|
||||
|
||||
typedef jmp_buf korp_jmpbuf;
|
||||
|
||||
#define os_setjmp setjmp
|
||||
#define os_longjmp longjmp
|
||||
#define os_alloca alloca
|
||||
|
||||
#define os_getpagesize getpagesize
|
||||
|
||||
typedef void (*os_signal_handler)(void *sig_addr);
|
||||
|
||||
int os_signal_init(os_signal_handler handler);
|
||||
|
||||
void os_signal_destroy();
|
||||
|
||||
void os_signal_unmask();
|
||||
|
||||
void os_sigreturn();
|
||||
#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */
|
||||
#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -110,9 +110,9 @@ enum {
|
||||
MMAP_MAP_FIXED = 2
|
||||
};
|
||||
|
||||
void *os_mmap(void *hint, unsigned int size, int prot, int flags);
|
||||
void os_munmap(void *addr, uint32 size);
|
||||
int os_mprotect(void *addr, uint32 size, int prot);
|
||||
void *os_mmap(void *hint, size_t size, int prot, int flags);
|
||||
void os_munmap(void *addr, size_t size);
|
||||
int os_mprotect(void *addr, size_t size, int prot);
|
||||
|
||||
/**
|
||||
* Flush cpu data cache, in some CPUs, after applying relocation to the
|
||||
|
||||
@ -82,7 +82,7 @@ int os_vprintf(const char * format, va_list arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* os_mmap(void *hint, uint32 size, int prot, int flags)
|
||||
void* os_mmap(void *hint, size_t size, int prot, int flags)
|
||||
{
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
int mprot = 0;
|
||||
@ -124,7 +124,7 @@ void* os_mmap(void *hint, uint32 size, int prot, int flags)
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_munmap(void *addr, uint32 size)
|
||||
void os_munmap(void *addr, size_t size)
|
||||
{
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
uint64 aligned_size, page_size;
|
||||
@ -135,11 +135,15 @@ void os_munmap(void *addr, uint32 size)
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_mprotect(void *addr, uint32 size, int prot)
|
||||
int os_mprotect(void *addr, size_t size, int prot)
|
||||
{
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
int mprot = 0;
|
||||
sgx_status_t st = 0;
|
||||
uint64 aligned_size, page_size;
|
||||
|
||||
page_size = getpagesize();
|
||||
aligned_size = (size + page_size - 1) & ~(page_size - 1);
|
||||
|
||||
if (prot & MMAP_PROT_READ)
|
||||
mprot |= SGX_PROT_READ;
|
||||
@ -147,7 +151,7 @@ int os_mprotect(void *addr, uint32 size, int prot)
|
||||
mprot |= SGX_PROT_WRITE;
|
||||
if (prot & MMAP_PROT_EXEC)
|
||||
mprot |= SGX_PROT_EXEC;
|
||||
st = sgx_tprotect_rsrv_mem(addr, size, mprot);
|
||||
st = sgx_tprotect_rsrv_mem(addr, aligned_size, mprot);
|
||||
if (st != SGX_SUCCESS)
|
||||
os_printf("os_mprotect(addr=0x%lx, size=%u, prot=0x%x) failed.",
|
||||
addr, size, prot);
|
||||
|
||||
@ -51,6 +51,38 @@ typedef pthread_t korp_thread;
|
||||
#define os_printf printf
|
||||
#define os_vprintf vprintf
|
||||
|
||||
#if WASM_DISABLE_HW_BOUND_CHECK == 0
|
||||
#if defined(BUILD_TARGET_X86_64) \
|
||||
|| defined(BUILD_TARGET_AMD_64) \
|
||||
|| defined(BUILD_TARGET_AARCH64)
|
||||
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#define OS_ENABLE_HW_BOUND_CHECK
|
||||
|
||||
#define os_thread_local_attribute __thread
|
||||
|
||||
typedef jmp_buf korp_jmpbuf;
|
||||
|
||||
#define os_setjmp setjmp
|
||||
#define os_longjmp longjmp
|
||||
#define os_alloca alloca
|
||||
|
||||
#define os_getpagesize getpagesize
|
||||
|
||||
typedef void (*os_signal_handler)(void *sig_addr);
|
||||
|
||||
int os_signal_init(os_signal_handler handler);
|
||||
|
||||
void os_signal_destroy();
|
||||
|
||||
void os_signal_unmask();
|
||||
|
||||
void os_sigreturn();
|
||||
#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */
|
||||
#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -50,6 +50,38 @@ typedef pthread_t korp_thread;
|
||||
#define os_printf printf
|
||||
#define os_vprintf vprintf
|
||||
|
||||
#if WASM_DISABLE_HW_BOUND_CHECK == 0
|
||||
#if defined(BUILD_TARGET_X86_64) \
|
||||
|| defined(BUILD_TARGET_AMD_64) \
|
||||
|| defined(BUILD_TARGET_AARCH64)
|
||||
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#define OS_ENABLE_HW_BOUND_CHECK
|
||||
|
||||
#define os_thread_local_attribute __thread
|
||||
|
||||
typedef jmp_buf korp_jmpbuf;
|
||||
|
||||
#define os_setjmp setjmp
|
||||
#define os_longjmp longjmp
|
||||
#define os_alloca alloca
|
||||
|
||||
#define os_getpagesize getpagesize
|
||||
|
||||
typedef void (*os_signal_handler)(void *sig_addr);
|
||||
|
||||
int os_signal_init(os_signal_handler handler);
|
||||
|
||||
void os_signal_destroy();
|
||||
|
||||
void os_signal_unmask();
|
||||
|
||||
void os_sigreturn();
|
||||
#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */
|
||||
#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -110,16 +110,18 @@ os_vprintf(const char *fmt, va_list ap)
|
||||
}
|
||||
|
||||
void *
|
||||
os_mmap(void *hint, unsigned int size, int prot, int flags)
|
||||
os_mmap(void *hint, size_t size, int prot, int flags)
|
||||
{
|
||||
if ((uint64)size >= UINT32_MAX)
|
||||
return NULL;
|
||||
if (exec_mem_alloc_func)
|
||||
return exec_mem_alloc_func(size);
|
||||
return exec_mem_alloc_func((uint32)size);
|
||||
else
|
||||
return BH_MALLOC(size);
|
||||
}
|
||||
|
||||
void
|
||||
os_munmap(void *addr, uint32 size)
|
||||
os_munmap(void *addr, size_t size)
|
||||
{
|
||||
if (exec_mem_free_func)
|
||||
exec_mem_free_func(addr);
|
||||
@ -128,7 +130,7 @@ os_munmap(void *addr, uint32 size)
|
||||
}
|
||||
|
||||
int
|
||||
os_mprotect(void *addr, uint32 size, int prot)
|
||||
os_mprotect(void *addr, size_t size, int prot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user