mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2024-11-26 15:32:05 +00:00
Make memory access boundary check behavior configurable (#2289)
Allow to use `cmake -DWAMR_CONFIGURABLE_BOUNDS_CHECKS=1` to build iwasm, and then run `iwasm --disable-bounds-checks` to disable the memory access boundary checks. And add two APIs: `wasm_runtime_set_bounds_checks` and `wasm_runtime_is_bounds_checks_enabled`
This commit is contained in:
parent
44f4b4f062
commit
18092f86cc
|
@ -396,3 +396,7 @@ if (WAMR_DISABLE_WRITE_GS_BASE EQUAL 1)
|
|||
add_definitions (-DWASM_DISABLE_WRITE_GS_BASE=1)
|
||||
message (" Write linear memory base addr to x86 GS register disabled")
|
||||
endif ()
|
||||
if (WAMR_CONFIGUABLE_BOUNDS_CHECKS EQUAL 1)
|
||||
add_definitions (-DWASM_CONFIGURABLE_BOUNDS_CHECKS=1)
|
||||
message (" Configurable bounds checks enabled")
|
||||
endif ()
|
||||
|
|
|
@ -456,4 +456,9 @@
|
|||
#define WASM_DISABLE_WRITE_GS_BASE 0
|
||||
#endif
|
||||
|
||||
/* Configurable bounds checks */
|
||||
#ifndef WASM_CONFIGURABLE_BOUNDS_CHECKS
|
||||
#define WASM_CONFIGURABLE_BOUNDS_CHECKS 0
|
||||
#endif
|
||||
|
||||
#endif /* end of _CONFIG_H_ */
|
||||
|
|
|
@ -90,6 +90,10 @@ typedef struct AOTFunctionInstance {
|
|||
typedef struct AOTModuleInstanceExtra {
|
||||
DefPointer(const uint32 *, stack_sizes);
|
||||
CApiFuncImport *c_api_func_imports;
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
/* Disable bounds checks or not */
|
||||
bool disable_bounds_checks;
|
||||
#endif
|
||||
} AOTModuleInstanceExtra;
|
||||
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "wasm_runtime_common.h"
|
||||
#include "../interpreter/wasm_runtime.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
#include "bh_platform.h"
|
||||
#include "mem_alloc.h"
|
||||
|
||||
|
@ -87,6 +88,16 @@ wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func,
|
|||
}
|
||||
#endif
|
||||
|
||||
static inline bool
|
||||
is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
|
||||
{
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
return wasm_runtime_is_bounds_checks_enabled(module_inst);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
|
||||
const MemAllocOption *alloc_option)
|
||||
|
@ -269,6 +280,10 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm,
|
|||
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|
||||
|| module_inst_comm->module_type == Wasm_Module_AoT);
|
||||
|
||||
if (!is_bounds_checks_enabled(module_inst_comm)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
memory_inst = wasm_get_default_memory(module_inst);
|
||||
if (!memory_inst) {
|
||||
goto fail;
|
||||
|
@ -299,6 +314,10 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
|
|||
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|
||||
|| module_inst_comm->module_type == Wasm_Module_AoT);
|
||||
|
||||
if (!is_bounds_checks_enabled(module_inst_comm)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, NULL,
|
||||
&app_end_offset))
|
||||
goto fail;
|
||||
|
@ -327,6 +346,10 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm,
|
|||
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|
||||
|| module_inst_comm->module_type == Wasm_Module_AoT);
|
||||
|
||||
if (!is_bounds_checks_enabled(module_inst_comm)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
memory_inst = wasm_get_default_memory(module_inst);
|
||||
if (!memory_inst) {
|
||||
goto fail;
|
||||
|
@ -354,10 +377,13 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm,
|
|||
WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
|
||||
WASMMemoryInstance *memory_inst;
|
||||
uint8 *addr;
|
||||
bool bounds_checks;
|
||||
|
||||
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|
||||
|| module_inst_comm->module_type == Wasm_Module_AoT);
|
||||
|
||||
bounds_checks = is_bounds_checks_enabled(module_inst_comm);
|
||||
|
||||
memory_inst = wasm_get_default_memory(module_inst);
|
||||
if (!memory_inst) {
|
||||
return NULL;
|
||||
|
@ -365,8 +391,17 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm,
|
|||
|
||||
addr = memory_inst->memory_data + app_offset;
|
||||
|
||||
if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end)
|
||||
if (bounds_checks) {
|
||||
if (memory_inst->memory_data <= addr
|
||||
&& addr < memory_inst->memory_data_end) {
|
||||
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
/* If bounds checks is disabled, return the address directly */
|
||||
else if (app_offset != 0) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -378,17 +413,27 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm,
|
|||
WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
|
||||
WASMMemoryInstance *memory_inst;
|
||||
uint8 *addr = (uint8 *)native_ptr;
|
||||
bool bounds_checks;
|
||||
|
||||
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|
||||
|| module_inst_comm->module_type == Wasm_Module_AoT);
|
||||
|
||||
bounds_checks = is_bounds_checks_enabled(module_inst_comm);
|
||||
|
||||
memory_inst = wasm_get_default_memory(module_inst);
|
||||
if (!memory_inst) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end)
|
||||
if (bounds_checks) {
|
||||
if (memory_inst->memory_data <= addr
|
||||
&& addr < memory_inst->memory_data_end)
|
||||
return (uint32)(addr - memory_inst->memory_data);
|
||||
}
|
||||
/* If bounds checks is disabled, return the offset directly */
|
||||
else if (addr != NULL) {
|
||||
return (uint32)(addr - memory_inst->memory_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -460,6 +505,7 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
|
|||
{
|
||||
WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst);
|
||||
uint8 *native_addr;
|
||||
bool bounds_checks;
|
||||
|
||||
if (!memory_inst) {
|
||||
goto fail;
|
||||
|
@ -467,6 +513,15 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
|
|||
|
||||
native_addr = memory_inst->memory_data + app_buf_addr;
|
||||
|
||||
bounds_checks = is_bounds_checks_enabled((wasm_module_inst_t)module_inst);
|
||||
|
||||
if (!bounds_checks) {
|
||||
if (app_buf_addr == 0) {
|
||||
native_addr = NULL;
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* No need to check the app_offset and buf_size if memory access
|
||||
boundary check with hardware trap is enabled */
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
|
@ -492,6 +547,7 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
|
|||
}
|
||||
#endif
|
||||
|
||||
success:
|
||||
*p_native_addr = (void *)native_addr;
|
||||
return true;
|
||||
fail:
|
||||
|
|
|
@ -2482,6 +2482,54 @@ wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst_comm)
|
|||
return module_inst->custom_data;
|
||||
}
|
||||
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
void
|
||||
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
|
||||
bool enable)
|
||||
{
|
||||
/* Alwary disable bounds checks if hw bounds checks enabled */
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
enable = false;
|
||||
#endif
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
((WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e)
|
||||
->disable_bounds_checks = enable ? false : true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
((AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e)
|
||||
->disable_bounds_checks = enable ? false : true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
|
||||
{
|
||||
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
return !((WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)
|
||||
->e)
|
||||
->disable_bounds_checks;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
return !((AOTModuleInstanceExtra *)((WASMModuleInstance *)module_inst)
|
||||
->e)
|
||||
->disable_bounds_checks;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32
|
||||
wasm_runtime_module_malloc_internal(WASMModuleInstanceCommon *module_inst,
|
||||
WASMExecEnv *exec_env, uint32 size,
|
||||
|
|
|
@ -593,6 +593,17 @@ wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data);
|
|||
WASM_RUNTIME_API_EXTERN void *
|
||||
wasm_runtime_get_user_data(WASMExecEnv *exec_env);
|
||||
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
|
||||
bool enable);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst);
|
||||
#endif
|
||||
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
/* Access exception check guard page to trigger the signal handler */
|
||||
void
|
||||
|
|
|
@ -914,6 +914,25 @@ wasm_runtime_set_custom_data(wasm_module_inst_t module_inst,
|
|||
WASM_RUNTIME_API_EXTERN void *
|
||||
wasm_runtime_get_custom_data(wasm_module_inst_t module_inst);
|
||||
|
||||
/**
|
||||
* Set the memory bounds checks flag of a WASM module instance.
|
||||
*
|
||||
* @param module_inst the WASM module instance
|
||||
* @param enable the flag to enable/disable the memory bounds checks
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_runtime_set_bounds_checks(wasm_module_inst_t module_inst,
|
||||
bool enable);
|
||||
/**
|
||||
* Check if the memory bounds checks flag is enabled for a WASM module instance.
|
||||
*
|
||||
* @param module_inst the WASM module instance
|
||||
*
|
||||
* @return true if the memory bounds checks flag is enabled, false otherwise
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_is_bounds_checks_enabled(
|
||||
wasm_module_inst_t module_inst);
|
||||
/**
|
||||
* Allocate memory from the heap of WASM module instance
|
||||
*
|
||||
|
|
|
@ -44,7 +44,8 @@ typedef float64 CellType_F64;
|
|||
#define CHECK_MEMORY_OVERFLOW(bytes) \
|
||||
do { \
|
||||
uint64 offset1 = (uint64)offset + (uint64)addr; \
|
||||
if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
|
||||
if (disable_bounds_checks \
|
||||
|| offset1 + bytes <= (uint64)get_linear_mem_size()) \
|
||||
/* If offset1 is in valid range, maddr must also \
|
||||
be in valid range, no need to check it again. */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
|
@ -55,7 +56,8 @@ typedef float64 CellType_F64;
|
|||
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
|
||||
do { \
|
||||
uint64 offset1 = (uint32)(start); \
|
||||
if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
|
||||
if (disable_bounds_checks \
|
||||
|| offset1 + bytes <= (uint64)get_linear_mem_size()) \
|
||||
/* App heap space is not valid space for \
|
||||
bulk memory operation */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
|
@ -1174,6 +1176,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
uint8 local_type, *global_addr;
|
||||
uint32 cache_index, type_index, param_cell_num, cell_num;
|
||||
uint8 value_type;
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
bool disable_bounds_checks = !wasm_runtime_is_bounds_checks_enabled(
|
||||
(WASMModuleInstanceCommon *)module);
|
||||
#else
|
||||
bool disable_bounds_checks = false;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
uint8 *frame_ip_orig = NULL;
|
||||
|
|
|
@ -35,7 +35,8 @@ typedef float64 CellType_F64;
|
|||
#define CHECK_MEMORY_OVERFLOW(bytes) \
|
||||
do { \
|
||||
uint64 offset1 = (uint64)offset + (uint64)addr; \
|
||||
if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
|
||||
if (disable_bounds_checks \
|
||||
|| offset1 + bytes <= (uint64)get_linear_mem_size()) \
|
||||
/* If offset1 is in valid range, maddr must also \
|
||||
be in valid range, no need to check it again. */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
|
@ -46,7 +47,7 @@ typedef float64 CellType_F64;
|
|||
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
|
||||
do { \
|
||||
uint64 offset1 = (uint32)(start); \
|
||||
if (offset1 + bytes <= get_linear_mem_size()) \
|
||||
if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
|
||||
/* App heap space is not valid space for \
|
||||
bulk memory operation */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
|
@ -1199,6 +1200,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
uint8 *maddr = NULL;
|
||||
uint32 local_idx, local_offset, global_idx;
|
||||
uint8 opcode, local_type, *global_addr;
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
bool disable_bounds_checks = !wasm_runtime_is_bounds_checks_enabled(
|
||||
(WASMModuleInstanceCommon *)module);
|
||||
#else
|
||||
bool disable_bounds_checks = false;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LABELS_AS_VALUES != 0
|
||||
#define HANDLE_OPCODE(op) &&HANDLE_##op
|
||||
|
|
|
@ -241,6 +241,10 @@ typedef struct WASMModuleInstanceExtra {
|
|||
&& WASM_ENABLE_LAZY_JIT != 0)
|
||||
WASMModuleInstance *next;
|
||||
#endif
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
/* Disable bounds checks or not */
|
||||
bool disable_bounds_checks;
|
||||
#endif
|
||||
} WASMModuleInstanceExtra;
|
||||
|
||||
struct AOTFuncPerfProfInfo;
|
||||
|
|
|
@ -72,3 +72,18 @@ wasm_runtime_dump_pgo_prof_data_to_buf(wasm_module_inst_t module_inst, char *buf
|
|||
6. Run the optimized aot_file: `iwasm <aot_file>`.
|
||||
|
||||
Developer can refer to the `test_pgo.sh` files under each benchmark folder for more details, e.g. [test_pgo.sh](../tests/benchmarks/coremark/test_pgo.sh) of CoreMark benchmark.
|
||||
|
||||
## 6. Disable the memory boundary check
|
||||
|
||||
Please notice that this method is not a general solution since it may lead to security issues. And only boost the performance for some platforms in AOT mode and don't support hardware trap for memory boundary check.
|
||||
|
||||
1. Build WAMR with `-DWAMR_CONFIGUABLE_BOUNDS_CHECKS=1` option.
|
||||
|
||||
2. Compile AOT module by wamrc with `--bounds-check=0` option.
|
||||
|
||||
3. Run the AOT module by iwasm with `--disable-bounds-checks` option.
|
||||
|
||||
> Note: The size of AOT file will be much smaller than the default, and some tricks are possible such as let the wasm application access the memory of host os directly.
|
||||
Please notice that if this option is enabled, the wasm spec test will fail since it requires the memory boundary check. For example, the runtime will crash when accessing the memory out of the boundary in some cases instead of throwing an exception as the spec requires.
|
||||
|
||||
You should only use this method for well tested wasm applications and make sure the memory access is safe.
|
||||
|
|
|
@ -230,6 +230,12 @@ else
|
|||
CFLAGS += -DWASM_ENABLE_LIBC_BUILTIN=0
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INTERPRETERS_WAMR_CONFIGUABLE_BOUNDS_CHECKS),y)
|
||||
CFLAGS += -DWASM_CONFIGUABLE_BOUNDS_CHECKS=1
|
||||
else
|
||||
CFLAGS += -DWASM_CONFIGUABLE_BOUNDS_CHECKS=0
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INTERPRETERS_WAMR_LIBC_WASI),y)
|
||||
CFLAGS += -DWASM_ENABLE_LIBC_WASI=1
|
||||
CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/src
|
||||
|
|
|
@ -65,6 +65,9 @@ print_help()
|
|||
#endif
|
||||
printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
|
||||
" that runs commands in the form of \"FUNC ARG...\"\n");
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
printf(" --disable-bounds-checks Disable bounds checks for memory accesses\n");
|
||||
#endif
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n");
|
||||
printf(" to the program, for example:\n");
|
||||
|
@ -481,6 +484,9 @@ main(int argc, char *argv[])
|
|||
#endif
|
||||
bool is_repl_mode = false;
|
||||
bool is_xip_file = false;
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
bool disable_bounds_checks = false;
|
||||
#endif
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
const char *dir_list[8] = { NULL };
|
||||
uint32 dir_list_size = 0;
|
||||
|
@ -545,6 +551,11 @@ main(int argc, char *argv[])
|
|||
else if (!strcmp(argv[0], "--repl")) {
|
||||
is_repl_mode = true;
|
||||
}
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
else if (!strcmp(argv[0], "--disable-bounds-checks")) {
|
||||
disable_bounds_checks = true;
|
||||
}
|
||||
#endif
|
||||
else if (!strncmp(argv[0], "--stack-size=", 13)) {
|
||||
if (argv[0][13] == '\0')
|
||||
return print_help();
|
||||
|
@ -832,6 +843,12 @@ main(int argc, char *argv[])
|
|||
goto fail3;
|
||||
}
|
||||
|
||||
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
|
||||
if (disable_bounds_checks) {
|
||||
wasm_runtime_set_bounds_checks(wasm_module_inst, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
if (ip_addr != NULL) {
|
||||
wasm_exec_env_t exec_env =
|
||||
|
|
Loading…
Reference in New Issue
Block a user