Skip to content

Commit

Permalink
Make boundary check behavior configurable
Browse files Browse the repository at this point in the history
Change-Id: Id06b5f9f8b9ef4e29ed0bf70d9b48c5a70ea2853
  • Loading branch information
no1wudi committed Jul 4, 2023
1 parent c39eb46 commit cd3b528
Show file tree
Hide file tree
Showing 13 changed files with 218 additions and 30 deletions.
4 changes: 4 additions & 0 deletions build-scripts/config_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()
5 changes: 5 additions & 0 deletions core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
4 changes: 4 additions & 0 deletions core/iwasm/aot/aot_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
51 changes: 49 additions & 2 deletions core/iwasm/common/wasm_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -269,6 +270,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 (!wasm_runtime_is_bounds_checks_enabled(module_inst_comm)) {
return true;
}

memory_inst = wasm_get_default_memory(module_inst);
if (!memory_inst) {
goto fail;
Expand Down Expand Up @@ -299,6 +304,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 (!wasm_runtime_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;
Expand Down Expand Up @@ -327,6 +336,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 (!wasm_runtime_is_bounds_checks_enabled(module_inst_comm)) {
return true;
}

memory_inst = wasm_get_default_memory(module_inst);
if (!memory_inst) {
goto fail;
Expand Down Expand Up @@ -354,19 +367,31 @@ 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 = wasm_runtime_is_bounds_checks_enabled(module_inst_comm);

memory_inst = wasm_get_default_memory(module_inst);
if (!memory_inst) {
return NULL;
}

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;
}
Expand All @@ -378,17 +403,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 = wasm_runtime_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;
}
Expand Down Expand Up @@ -460,13 +495,24 @@ 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;
}

native_addr = memory_inst->memory_data + app_buf_addr;

bounds_checks =
wasm_runtime_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
Expand All @@ -492,6 +538,7 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
}
#endif

success:
*p_native_addr = (void *)native_addr;
return true;
fail:
Expand Down
50 changes: 50 additions & 0 deletions core/iwasm/common/wasm_runtime_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -2482,6 +2482,56 @@ 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
}
#endif

bool
wasm_runtime_is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
{

#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
#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
#endif

return true;
}

uint32
wasm_runtime_module_malloc_internal(WASMModuleInstanceCommon *module_inst,
WASMExecEnv *exec_env, uint32 size,
Expand Down
10 changes: 10 additions & 0 deletions core/iwasm/common/wasm_runtime_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,16 @@ 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);
#endif
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN bool
wasm_runtime_is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst);

#ifdef OS_ENABLE_HW_BOUND_CHECK
/* Access exception check guard page to trigger the signal handler */
void
Expand Down
19 changes: 19 additions & 0 deletions core/iwasm/include/wasm_export.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
40 changes: 22 additions & 18 deletions core/iwasm/interpreter/wasm_interp_classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,28 @@ typedef float64 CellType_F64;

#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
#define CHECK_MEMORY_OVERFLOW(bytes) \
do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \
if (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; \
else \
goto out_of_bounds; \
#define CHECK_MEMORY_OVERFLOW(bytes) \
do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \
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; \
else \
goto out_of_bounds; \
} while (0)

#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \
uint64 offset1 = (uint32)(start); \
if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
/* App heap space is not valid space for \
bulk memory operation */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \
uint64 offset1 = (uint32)(start); \
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; \
else \
goto out_of_bounds; \
} while (0)
#else
#define CHECK_MEMORY_OVERFLOW(bytes) \
Expand Down Expand Up @@ -1174,6 +1176,8 @@ 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;
bool disable_bounds_checks = !wasm_runtime_is_bounds_checks_enabled(
(WASMModuleInstanceCommon *)module);

#if WASM_ENABLE_DEBUG_INTERP != 0
uint8 *frame_ip_orig = NULL;
Expand Down
23 changes: 13 additions & 10 deletions core/iwasm/interpreter/wasm_interp_fast.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,24 @@ 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; \
else \
goto out_of_bounds; \
} while (0)

#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \
uint64 offset1 = (uint32)(start); \
if (offset1 + bytes <= get_linear_mem_size()) \
/* App heap space is not valid space for \
bulk memory operation */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \
uint64 offset1 = (uint32)(start); \
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; \
else \
goto out_of_bounds; \
} while (0)
#else
#define CHECK_MEMORY_OVERFLOW(bytes) \
Expand Down Expand Up @@ -1199,6 +1200,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint8 *maddr = NULL;
uint32 local_idx, local_offset, global_idx;
uint8 opcode, local_type, *global_addr;
bool disable_bounds_checks = !wasm_runtime_is_bounds_checks_enabled(
(WASMModuleInstanceCommon *)module);

#if WASM_ENABLE_LABELS_AS_VALUES != 0
#define HANDLE_OPCODE(op) &&HANDLE_##op
Expand Down
4 changes: 4 additions & 0 deletions core/iwasm/interpreter/wasm_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 15 additions & 0 deletions doc/perf_tune.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Loading

0 comments on commit cd3b528

Please sign in to comment.