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:
wenyongh
2020-06-28 15:41:25 +08:00
committed by GitHub
parent 548926ab1a
commit ee315e4049
33 changed files with 1143 additions and 438 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;
}