Implement Windows boundary check with hardware trap (#623)
This commit is contained in:
@ -1042,7 +1042,8 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end,
|
||||
read_uint32(buf, buf_end, data_sections[i].size);
|
||||
|
||||
/* Allocate memory for data */
|
||||
if (!(data_sections[i].data =
|
||||
if (data_sections[i].size > 0
|
||||
&& !(data_sections[i].data =
|
||||
os_mmap(NULL, data_sections[i].size, map_prot, map_flags))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"allocate memory failed");
|
||||
@ -1179,6 +1180,27 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
||||
const uint8 *p = buf, *p_end = buf_end;
|
||||
uint32 i;
|
||||
uint64 size, text_offset;
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
RUNTIME_FUNCTION *rtl_func_table;
|
||||
AOTUnwindInfo *unwind_info;
|
||||
uint32 unwind_info_offset = module->code_size - sizeof(AOTUnwindInfo);
|
||||
uint32 unwind_code_offset = unwind_info_offset - PLT_ITEM_SIZE;
|
||||
#endif
|
||||
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
unwind_info= (AOTUnwindInfo *)((uint8*)module->code + module->code_size
|
||||
- sizeof(AOTUnwindInfo));
|
||||
unwind_info->Version = 1;
|
||||
unwind_info->Flags = UNW_FLAG_EHANDLER;
|
||||
*(uint32*)&unwind_info->UnwindCode[0] = unwind_code_offset;
|
||||
|
||||
size = sizeof(RUNTIME_FUNCTION) * (uint64)module->func_count;
|
||||
if (size > 0
|
||||
&& !(rtl_func_table = module->rtl_func_table =
|
||||
loader_malloc(size, error_buf, error_buf_size))) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
size = sizeof(void*) * (uint64)module->func_count;
|
||||
if (size > 0
|
||||
@ -1205,9 +1227,31 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
||||
#if defined(BUILD_TARGET_THUMB) || defined(BUILD_TARGET_THUMB_VFP)
|
||||
/* bits[0] of thumb function address must be 1 */
|
||||
module->func_ptrs[i] = (void*)((uintptr_t)module->func_ptrs[i] | 1);
|
||||
#endif
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
rtl_func_table[i].BeginAddress = (DWORD)text_offset;
|
||||
if (i > 0) {
|
||||
rtl_func_table[i].EndAddress = rtl_func_table[i - 1].BeginAddress;
|
||||
}
|
||||
rtl_func_table[i].UnwindInfoAddress = (DWORD)unwind_info_offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
if (module->func_count > 0) {
|
||||
rtl_func_table[module->func_count - 1].EndAddress =
|
||||
(DWORD)(module->code_size - get_plt_table_size());
|
||||
|
||||
if (!RtlAddFunctionTable(rtl_func_table, module->func_count,
|
||||
(DWORD64)(uintptr_t)module->code)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"add dynamic function table failed");
|
||||
return false;
|
||||
}
|
||||
module->rtl_func_table_registered = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set start function when function pointers are resolved */
|
||||
if (module->start_func_index != (uint32)-1) {
|
||||
if (module->start_func_index >= module->import_func_count)
|
||||
@ -2621,6 +2665,14 @@ aot_unload(AOTModule *module)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
if (module->rtl_func_table) {
|
||||
if (module->rtl_func_table_registered)
|
||||
RtlDeleteFunctionTable(module->rtl_func_table);
|
||||
wasm_runtime_free(module->rtl_func_table);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (module->data_sections)
|
||||
destroy_object_data_sections(module->data_sections,
|
||||
module->data_section_count);
|
||||
|
||||
@ -339,6 +339,11 @@ memories_deinstantiate(AOTModuleInstance *module_inst)
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
wasm_runtime_free(memory_inst->memory_data.ptr);
|
||||
#else
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
os_mem_decommit(memory_inst->memory_data.ptr,
|
||||
memory_inst->num_bytes_per_page
|
||||
* memory_inst->cur_page_count);
|
||||
#endif
|
||||
os_munmap((uint8*)memory_inst->memory_data.ptr,
|
||||
8 * (uint64)BH_GB);
|
||||
#endif
|
||||
@ -499,8 +504,19 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
if (!os_mem_commit(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE)) {
|
||||
set_error_buf(error_buf, error_buf_size, "commit memory failed");
|
||||
os_munmap(mapped_mem, map_size);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (os_mprotect(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) {
|
||||
set_error_buf(error_buf, error_buf_size, "mprotec memory failed");
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
os_mem_decommit(p, total_size);
|
||||
#endif
|
||||
os_munmap(mapped_mem, map_size);
|
||||
return NULL;
|
||||
}
|
||||
@ -583,6 +599,10 @@ fail1:
|
||||
if (memory_inst->memory_data.ptr)
|
||||
wasm_runtime_free(memory_inst->memory_data.ptr);
|
||||
#else
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
if (memory_inst->memory_data.ptr)
|
||||
os_mem_decommit(p, total_size);
|
||||
#endif
|
||||
os_munmap(mapped_mem, map_size);
|
||||
#endif
|
||||
memory_inst->memory_data.ptr = NULL;
|
||||
@ -1129,8 +1149,16 @@ aot_lookup_function(const AOTModuleInstance *module_inst,
|
||||
|
||||
static os_thread_local_attribute WASMExecEnv *aot_exec_env = NULL;
|
||||
|
||||
#ifndef BH_PLATFORM_WINDOWS
|
||||
static void
|
||||
aot_signal_handler(void *sig_addr)
|
||||
#else
|
||||
EXCEPTION_DISPOSITION
|
||||
aot_exception_handler(PEXCEPTION_RECORD ExceptionRecord,
|
||||
ULONG64 EstablisherFrame,
|
||||
PCONTEXT ContextRecord,
|
||||
PDISPATCHER_CONTEXT DispatcherContext)
|
||||
#endif
|
||||
{
|
||||
AOTModuleInstance *module_inst;
|
||||
AOTMemoryInstance *memory_inst;
|
||||
@ -1140,11 +1168,18 @@ aot_signal_handler(void *sig_addr)
|
||||
uint8 *stack_min_addr;
|
||||
uint32 page_size;
|
||||
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
uint8 *sig_addr = (uint8*)ExceptionRecord->ExceptionInformation[1];
|
||||
#endif
|
||||
|
||||
/* Check whether current thread is running aot function */
|
||||
if (aot_exec_env
|
||||
&& aot_exec_env->handle == os_self_thread()
|
||||
&& (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) {
|
||||
&& (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
&& ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
|
||||
#endif
|
||||
) {
|
||||
/* Get mapped mem info of current instance */
|
||||
module_inst = (AOTModuleInstance *)aot_exec_env->module_inst;
|
||||
/* Get the default memory instance */
|
||||
@ -1176,18 +1211,60 @@ aot_signal_handler(void *sig_addr)
|
||||
os_longjmp(jmpbuf_node->jmpbuf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
ContextRecord->Rip += 3;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
(void)EstablisherFrame;
|
||||
(void)ContextRecord;
|
||||
(void)DispatcherContext;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
static LONG
|
||||
stack_overflow_handler(EXCEPTION_POINTERS *exce_info)
|
||||
{
|
||||
AOTModuleInstance* module_inst;
|
||||
WASMJmpBuf* jmpbuf_node;
|
||||
|
||||
/* Check whether it is stack overflow exception and
|
||||
current thread is running aot function */
|
||||
if (exce_info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW
|
||||
&& aot_exec_env
|
||||
&& aot_exec_env->handle == os_self_thread()
|
||||
&& (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) {
|
||||
/* Set stack overflow exception and let the aot func continue
|
||||
to run, when the aot func returns, the caller will check
|
||||
whether the exception is thrown and return to runtime, and
|
||||
the damaged stack will be recovered by _resetstkoflw(). */
|
||||
module_inst = (AOTModuleInstance*)aot_exec_env->module_inst;
|
||||
aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_signal_init()
|
||||
{
|
||||
#ifndef BH_PLATFORM_WINDOWS
|
||||
return os_signal_init(aot_signal_handler) == 0 ? true : false;
|
||||
#else
|
||||
return AddVectoredExceptionHandler(1, stack_overflow_handler)
|
||||
? true : false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
aot_signal_destroy()
|
||||
{
|
||||
#ifndef BH_PLATFORM_WINDOWS
|
||||
os_signal_destroy();
|
||||
#else
|
||||
RemoveVectoredExceptionHandler(stack_overflow_handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1201,6 +1278,10 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
|
||||
WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop;
|
||||
uint32 page_size = os_getpagesize();
|
||||
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
|
||||
#if BH_PLATFORM_WINDOWS
|
||||
const char *exce;
|
||||
int result;
|
||||
#endif
|
||||
bool ret;
|
||||
|
||||
/* Check native stack overflow firstly to ensure we have enough
|
||||
@ -1226,6 +1307,15 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
|
||||
ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type,
|
||||
signature, attachment,
|
||||
argv, argc, argv_ret);
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
if ((exce = aot_get_exception(module_inst))
|
||||
&& strstr(exce, "native stack overflow")) {
|
||||
/* After a stack overflow, the stack was left
|
||||
in a damaged state, let the CRT repair it */
|
||||
result = _resetstkoflw();
|
||||
bh_assert(result != 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* Exception has been set in signal handler before calling longjmp */
|
||||
@ -1992,9 +2082,21 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
if (!os_mem_commit(memory_inst->memory_data_end.ptr,
|
||||
num_bytes_per_page * inc_page_count,
|
||||
MMAP_PROT_READ | MMAP_PROT_WRITE)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (os_mprotect(memory_inst->memory_data_end.ptr,
|
||||
num_bytes_per_page * inc_page_count,
|
||||
MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) {
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
os_mem_decommit(memory_inst->memory_data_end.ptr,
|
||||
num_bytes_per_page * inc_page_count);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -88,6 +88,28 @@ typedef struct AOTFunctionInstance {
|
||||
} u;
|
||||
} AOTFunctionInstance;
|
||||
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
typedef struct AOTUnwindInfo {
|
||||
uint8 Version : 3;
|
||||
uint8 Flags : 5;
|
||||
uint8 SizeOfProlog;
|
||||
uint8 CountOfCodes;
|
||||
uint8 FrameRegister : 4;
|
||||
uint8 FrameOffset : 4;
|
||||
struct {
|
||||
struct {
|
||||
uint8 CodeOffset;
|
||||
uint8 UnwindOp : 4;
|
||||
uint8 OpInfo : 4;
|
||||
};
|
||||
uint16 FrameOffset;
|
||||
} UnwindCode[1];
|
||||
} AOTUnwindInfo;
|
||||
|
||||
/* size of mov instruction and jmp instruction */
|
||||
#define PLT_ITEM_SIZE 12
|
||||
#endif
|
||||
|
||||
typedef struct AOTModule {
|
||||
uint32 module_type;
|
||||
|
||||
@ -173,6 +195,14 @@ typedef struct AOTModule {
|
||||
uint32 float_plt_count;
|
||||
#endif
|
||||
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
/* dynamic function table to be added by RtlAddFunctionTable(),
|
||||
used to unwind the call stack and register exception handler
|
||||
for AOT functions */
|
||||
RUNTIME_FUNCTION *rtl_func_table;
|
||||
bool rtl_func_table_registered;
|
||||
#endif
|
||||
|
||||
/* data sections in AOT object file, including .data, .rodata
|
||||
* and .rodata.cstN. NULL for JIT mode. */
|
||||
AOTObjectDataSection *data_sections;
|
||||
@ -629,6 +659,14 @@ aot_signal_init();
|
||||
|
||||
void
|
||||
aot_signal_destroy();
|
||||
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
EXCEPTION_DISPOSITION
|
||||
aot_exception_handler(PEXCEPTION_RECORD ExceptionRecord,
|
||||
ULONG64 EstablisherFrame,
|
||||
PCONTEXT ContextRecord,
|
||||
PDISPATCHER_CONTEXT DispatcherContext);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void
|
||||
|
||||
@ -61,15 +61,22 @@ get_plt_item_size()
|
||||
uint32
|
||||
get_plt_table_size()
|
||||
{
|
||||
return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
|
||||
uint32 size = get_plt_item_size()
|
||||
* (sizeof(target_sym_map) / sizeof(SymbolMap));
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
size += get_plt_item_size() + sizeof(AOTUnwindInfo);
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
init_plt_table(uint8 *plt)
|
||||
{
|
||||
uint32 i, num = sizeof(target_sym_map) / sizeof(SymbolMap);
|
||||
uint8 *p;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
uint8 *p = plt;
|
||||
p = plt;
|
||||
/* mov symbol_addr, rax */
|
||||
*p++ = 0x48;
|
||||
*p++ = 0xB8;
|
||||
@ -80,6 +87,18 @@ init_plt_table(uint8 *plt)
|
||||
*p++ = 0xE0;
|
||||
plt += get_plt_item_size();
|
||||
}
|
||||
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
p = plt;
|
||||
/* mov exception_handler, rax */
|
||||
*p++ = 0x48;
|
||||
*p++ = 0xB8;
|
||||
*(uint64*)p = (uint64)(uintptr_t)aot_exception_handler;
|
||||
p += sizeof(uint64);
|
||||
/* jmp rax */
|
||||
*p++ = 0xFF;
|
||||
*p++ = 0xE0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
|
||||
@ -2707,7 +2707,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
{
|
||||
if (strncasecmp(argv[i], "null", 4) == 0) {
|
||||
if (strncmp(argv[i], "null", 4) == 0
|
||||
|| strncmp(argv[i], "NULL", 4) == 0) {
|
||||
argv1[p++] = NULL_REF;
|
||||
}
|
||||
else {
|
||||
@ -2717,7 +2718,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
|
||||
}
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
{
|
||||
if (strncasecmp(argv[i], "null", 4) == 0) {
|
||||
if (strncmp(argv[i], "null", 4) == 0
|
||||
|| strncmp(argv[i], "NULL", 4) == 0) {
|
||||
argv1[p++] = NULL_REF;
|
||||
}
|
||||
else {
|
||||
|
||||
@ -657,7 +657,11 @@ strcpy_wrapper(wasm_exec_env_t exec_env, char *dst, const char *src)
|
||||
if (!validate_native_addr(dst, len))
|
||||
return 0;
|
||||
|
||||
#ifndef BH_PLATFORM_WINDOWS
|
||||
strncpy(dst, src, len);
|
||||
#else
|
||||
strncpy_s(dst, len, src, len);
|
||||
#endif
|
||||
return addr_native_to_app(dst);
|
||||
}
|
||||
|
||||
@ -671,7 +675,11 @@ strncpy_wrapper(wasm_exec_env_t exec_env,
|
||||
if (!validate_native_addr(dst, size))
|
||||
return 0;
|
||||
|
||||
#ifndef BH_PLATFORM_WINDOWS
|
||||
strncpy(dst, src, size);
|
||||
#else
|
||||
strncpy_s(dst, size, src, size);
|
||||
#endif
|
||||
return addr_native_to_app(dst);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user