mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-11 09:25:20 +00:00
Add more security checks for libc wrapper API's (#105)
This commit is contained in:
parent
92cbecbec8
commit
c808aa2ebb
|
@ -52,6 +52,29 @@ wasm_runtime_set_llvm_stack(wasm_module_inst_t module, uint32 llvm_stack);
|
|||
#define module_free(offset) \
|
||||
wasm_runtime_module_free(module_inst, offset)
|
||||
|
||||
static bool
|
||||
validate_str_addr(wasm_module_inst_t module_inst, int32 str_offset)
|
||||
{
|
||||
int32 app_end_offset;
|
||||
char *str, *str_end;
|
||||
|
||||
if (!wasm_runtime_get_app_addr_range(module_inst, str_offset,
|
||||
NULL, &app_end_offset))
|
||||
goto fail;
|
||||
|
||||
str = addr_app_to_native(str_offset);
|
||||
str_end = str + (app_end_offset - str_offset);
|
||||
while (str < str_end && *str != '\0')
|
||||
str++;
|
||||
if (str == str_end)
|
||||
goto fail;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef int (*out_func_t)(int c, void *ctx);
|
||||
|
||||
enum pad_type {
|
||||
|
@ -64,9 +87,14 @@ enum pad_type {
|
|||
typedef char *_va_list;
|
||||
#define _INTSIZEOF(n) \
|
||||
((sizeof(n) + 3) & ~3)
|
||||
#define _va_arg(ap,t) \
|
||||
#define _va_arg(ap, t) \
|
||||
(*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
|
||||
|
||||
#define CHECK_VA_ARG(ap, t) do { \
|
||||
if ((uint8*)ap + _INTSIZEOF(t) > native_end_addr) \
|
||||
goto fail; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Output an unsigned int in hex format
|
||||
*
|
||||
|
@ -172,14 +200,19 @@ print_err(out_func_t out, void *ctx)
|
|||
out('R', ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
_vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
||||
wasm_module_inst_t module_inst)
|
||||
static bool
|
||||
_vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
||||
wasm_module_inst_t module_inst)
|
||||
{
|
||||
int might_format = 0; /* 1 if encountered a '%' */
|
||||
enum pad_type padding = PAD_NONE;
|
||||
int min_width = -1;
|
||||
int long_ctr = 0;
|
||||
uint8 *native_end_addr;
|
||||
|
||||
if (!wasm_runtime_get_native_addr_range(module_inst, (uint8*)ap,
|
||||
NULL, &native_end_addr))
|
||||
goto fail;
|
||||
|
||||
/* fmt has already been adjusted if needed */
|
||||
|
||||
|
@ -232,10 +265,13 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
int32 d;
|
||||
|
||||
if (long_ctr < 2) {
|
||||
CHECK_VA_ARG(ap, int32);
|
||||
d = _va_arg(ap, int32);
|
||||
}
|
||||
else {
|
||||
int64 lld = _va_arg(ap, int64);
|
||||
int64 lld;
|
||||
CHECK_VA_ARG(ap, int64);
|
||||
lld = _va_arg(ap, int64);
|
||||
if (lld > INT32_MAX || lld < INT32_MIN) {
|
||||
print_err(out, ctx);
|
||||
break;
|
||||
|
@ -255,10 +291,13 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
uint32 u;
|
||||
|
||||
if (long_ctr < 2) {
|
||||
CHECK_VA_ARG(ap, uint32);
|
||||
u = _va_arg(ap, uint32);
|
||||
}
|
||||
else {
|
||||
uint64 llu = _va_arg(ap, uint64);
|
||||
uint64 llu;
|
||||
CHECK_VA_ARG(ap, uint64);
|
||||
llu = _va_arg(ap, uint64);
|
||||
if (llu > INT32_MAX) {
|
||||
print_err(out, ctx);
|
||||
break;
|
||||
|
@ -281,8 +320,10 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
bool is_ptr = (*fmt == 'p') ? true : false;
|
||||
|
||||
if (long_ctr < 2) {
|
||||
CHECK_VA_ARG(ap, uint32);
|
||||
x = _va_arg(ap, uint32);
|
||||
} else {
|
||||
CHECK_VA_ARG(ap, uint64);
|
||||
x = _va_arg(ap, uint64);
|
||||
}
|
||||
_printf_hex_uint(out, ctx, x, !is_ptr, padding, min_width);
|
||||
|
@ -292,11 +333,13 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
case 's': {
|
||||
char *s;
|
||||
char *start;
|
||||
int32 s_offset = _va_arg(ap, uint32);
|
||||
int32 s_offset;
|
||||
|
||||
if (!validate_app_addr(s_offset, 1)) {
|
||||
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
|
||||
return;
|
||||
CHECK_VA_ARG(ap, uint32);
|
||||
s_offset = _va_arg(ap, uint32);
|
||||
|
||||
if (!validate_str_addr(module_inst, s_offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s = start = addr_app_to_native(s_offset);
|
||||
|
@ -314,7 +357,9 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
}
|
||||
|
||||
case 'c': {
|
||||
int c = _va_arg(ap, int);
|
||||
int c;
|
||||
CHECK_VA_ARG(ap, int);
|
||||
c = _va_arg(ap, int);
|
||||
out(c, ctx);
|
||||
break;
|
||||
}
|
||||
|
@ -336,6 +381,11 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
still_might_format:
|
||||
++fmt;
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct str_context {
|
||||
|
@ -391,7 +441,7 @@ parse_printf_args(wasm_module_inst_t module_inst, int32 fmt_offset,
|
|||
_va_list v;
|
||||
} u;
|
||||
|
||||
if (!validate_app_addr(fmt_offset, 1)
|
||||
if (!validate_str_addr(module_inst, fmt_offset)
|
||||
|| !validate_app_addr(va_list_offset, sizeof(int32)))
|
||||
return false;
|
||||
|
||||
|
@ -414,7 +464,8 @@ _printf_wrapper(int32 fmt_offset, int32 va_list_offset)
|
|||
if (!parse_printf_args(module_inst, fmt_offset, va_list_offset, &fmt, &va_args))
|
||||
return 0;
|
||||
|
||||
_vprintf((out_func_t) printf_out, &ctx, fmt, va_args, module_inst);
|
||||
if (!_vprintf_wa((out_func_t)printf_out, &ctx, fmt, va_args, module_inst))
|
||||
return 0;
|
||||
return ctx.count;
|
||||
}
|
||||
|
||||
|
@ -427,7 +478,7 @@ _sprintf_wrapper(int32 str_offset, int32 fmt_offset, int32 va_list_offset)
|
|||
const char *fmt;
|
||||
_va_list va_args;
|
||||
|
||||
if (!validate_app_addr(str_offset, 1))
|
||||
if (!validate_str_addr(module_inst, str_offset))
|
||||
return 0;
|
||||
|
||||
str = addr_app_to_native(str_offset);
|
||||
|
@ -439,7 +490,8 @@ _sprintf_wrapper(int32 str_offset, int32 fmt_offset, int32 va_list_offset)
|
|||
ctx.max = INT_MAX;
|
||||
ctx.count = 0;
|
||||
|
||||
_vprintf((out_func_t) sprintf_out, &ctx, fmt, va_args, module_inst);
|
||||
if (!_vprintf_wa((out_func_t)sprintf_out, &ctx, fmt, va_args, module_inst))
|
||||
return 0;
|
||||
|
||||
if (ctx.count < ctx.max) {
|
||||
str[ctx.count] = '\0';
|
||||
|
@ -470,7 +522,8 @@ _snprintf_wrapper(int32 str_offset, int32 size, int32 fmt_offset,
|
|||
ctx.max = size;
|
||||
ctx.count = 0;
|
||||
|
||||
_vprintf((out_func_t) sprintf_out, &ctx, fmt, va_args, module_inst);
|
||||
if (!_vprintf_wa((out_func_t)sprintf_out, &ctx, fmt, va_args, module_inst))
|
||||
return 0;
|
||||
|
||||
if (ctx.count < ctx.max) {
|
||||
str[ctx.count] = '\0';
|
||||
|
@ -485,7 +538,7 @@ _puts_wrapper(int32 str_offset)
|
|||
wasm_module_inst_t module_inst = get_module_inst();
|
||||
const char *str;
|
||||
|
||||
if (!validate_app_addr(str_offset, 1))
|
||||
if (!validate_str_addr(module_inst, str_offset))
|
||||
return 0;
|
||||
|
||||
str = addr_app_to_native(str_offset);
|
||||
|
@ -507,7 +560,7 @@ _strdup_wrapper(int32 str_offset)
|
|||
uint32 len;
|
||||
int32 str_ret_offset = 0;
|
||||
|
||||
if (!validate_app_addr(str_offset, 1))
|
||||
if (!validate_str_addr(module_inst, str_offset))
|
||||
return 0;
|
||||
|
||||
str = addr_app_to_native(str_offset);
|
||||
|
@ -596,7 +649,7 @@ _strchr_wrapper(int32 s_offset, int32 c)
|
|||
const char *s;
|
||||
char *ret;
|
||||
|
||||
if (!validate_app_addr(s_offset, 1))
|
||||
if (!validate_str_addr(module_inst, s_offset))
|
||||
return s_offset;
|
||||
|
||||
s = addr_app_to_native(s_offset);
|
||||
|
@ -610,8 +663,8 @@ _strcmp_wrapper(int32 s1_offset, int32 s2_offset)
|
|||
wasm_module_inst_t module_inst = get_module_inst();
|
||||
void *s1, *s2;
|
||||
|
||||
if (!validate_app_addr(s1_offset, 1)
|
||||
|| !validate_app_addr(s2_offset, 1))
|
||||
if (!validate_str_addr(module_inst, s1_offset)
|
||||
|| !validate_str_addr(module_inst, s2_offset))
|
||||
return 0;
|
||||
|
||||
s1 = addr_app_to_native(s1_offset);
|
||||
|
@ -640,8 +693,8 @@ _strcpy_wrapper(int32 dst_offset, int32 src_offset)
|
|||
wasm_module_inst_t module_inst = get_module_inst();
|
||||
char *dst, *src;
|
||||
|
||||
if (!validate_app_addr(dst_offset, 1)
|
||||
|| !validate_app_addr(src_offset, 1))
|
||||
if (!validate_str_addr(module_inst, dst_offset)
|
||||
|| !validate_str_addr(module_inst, src_offset))
|
||||
return 0;
|
||||
|
||||
dst = addr_app_to_native(dst_offset);
|
||||
|
@ -672,7 +725,7 @@ _strlen_wrapper(int32 s_offset)
|
|||
wasm_module_inst_t module_inst = get_module_inst();
|
||||
char *s;
|
||||
|
||||
if (!validate_app_addr(s_offset, 1))
|
||||
if (!validate_str_addr(module_inst, s_offset))
|
||||
return 0;
|
||||
|
||||
s = addr_app_to_native(s_offset);
|
||||
|
|
|
@ -391,6 +391,38 @@ int32_t
|
|||
wasm_runtime_addr_native_to_app(wasm_module_inst_t module_inst,
|
||||
void *native_ptr);
|
||||
|
||||
/**
|
||||
* Get the app address range (relative address) that a app address belongs to
|
||||
*
|
||||
* @param module_inst the WASM module instance
|
||||
* @param app_offset the app address to retrieve
|
||||
* @param p_app_start_offset buffer to output the app start offset if not NULL
|
||||
* @param p_app_end_offset buffer to output the app end offset if not NULL
|
||||
*
|
||||
* @return true if success, false otherwise.
|
||||
*/
|
||||
bool
|
||||
wasm_runtime_get_app_addr_range(wasm_module_inst_t module_inst,
|
||||
int32_t app_offset,
|
||||
int32_t *p_app_start_offset,
|
||||
int32_t *p_app_end_offset);
|
||||
|
||||
/**
|
||||
* Get the native address range (absolute address) that a native address belongs to
|
||||
*
|
||||
* @param module_inst the WASM module instance
|
||||
* @param native_ptr the native address to retrieve
|
||||
* @param p_native_start_addr buffer to output the native start address if not NULL
|
||||
* @param p_native_end_addr buffer to output the native end address if not NULL
|
||||
*
|
||||
* @return true if success, false otherwise.
|
||||
*/
|
||||
bool
|
||||
wasm_runtime_get_native_addr_range(wasm_module_inst_t module_inst,
|
||||
uint8_t *native_ptr,
|
||||
uint8_t **p_native_start_addr,
|
||||
uint8_t **p_native_end_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1302,6 +1302,84 @@ wasm_runtime_addr_native_to_app(WASMModuleInstance *module_inst,
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_get_app_addr_range(WASMModuleInstance *module_inst,
|
||||
int32 app_offset,
|
||||
int32 *p_app_start_offset,
|
||||
int32 *p_app_end_offset)
|
||||
{
|
||||
int32 app_start_offset, app_end_offset;
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
|
||||
if (0 <= app_offset && app_offset < memory->heap_base_offset) {
|
||||
app_start_offset = 0;
|
||||
app_end_offset = NumBytesPerPage * memory->cur_page_count;
|
||||
}
|
||||
else if (memory->heap_base_offset < app_offset
|
||||
&& app_offset < memory->heap_base_offset
|
||||
+ (memory->heap_data_end - memory->heap_data)) {
|
||||
app_start_offset = memory->heap_base_offset;
|
||||
app_end_offset = memory->heap_base_offset
|
||||
+ (memory->heap_data_end - memory->heap_data);
|
||||
}
|
||||
#if WASM_ENABLE_EXT_MEMORY_SPACE != 0
|
||||
else if (module_inst->ext_mem_data
|
||||
&& module_inst->ext_mem_base_offset <= app_offset
|
||||
&& app_offset < module_inst->ext_mem_base_offset
|
||||
+ module_inst->ext_mem_size) {
|
||||
app_start_offset = module_inst->ext_mem_base_offset;
|
||||
app_end_offset = app_start_offset + module_inst->ext_mem_size;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return false;
|
||||
|
||||
if (p_app_start_offset)
|
||||
*p_app_start_offset = app_start_offset;
|
||||
if (p_app_end_offset)
|
||||
*p_app_end_offset = app_end_offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_get_native_addr_range(WASMModuleInstance *module_inst,
|
||||
uint8 *native_ptr,
|
||||
uint8 **p_native_start_addr,
|
||||
uint8 **p_native_end_addr)
|
||||
{
|
||||
uint8 *native_start_addr, *native_end_addr;
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
|
||||
if (memory->base_addr <= (uint8*)native_ptr
|
||||
&& (uint8*)native_ptr < memory->end_addr) {
|
||||
native_start_addr = memory->memory_data;
|
||||
native_end_addr = memory->memory_data
|
||||
+ NumBytesPerPage * memory->cur_page_count;
|
||||
}
|
||||
else if (memory->heap_data <= (uint8*)native_ptr
|
||||
&& (uint8*)native_ptr < memory->heap_data_end) {
|
||||
native_start_addr = memory->heap_data;
|
||||
native_end_addr = memory->heap_data_end;
|
||||
}
|
||||
#if WASM_ENABLE_EXT_MEMORY_SPACE != 0
|
||||
else if (module_inst->ext_mem_data
|
||||
&& module_inst->ext_mem_data <= (uint8*)native_ptr
|
||||
&& (uint8*)native_ptr < module_inst->ext_mem_data_end) {
|
||||
native_start_addr = module_inst->ext_mem_data;
|
||||
native_end_addr = module_inst->ext_mem_data_end;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return false;
|
||||
|
||||
if (p_native_start_addr)
|
||||
*p_native_start_addr = native_start_addr;
|
||||
if (p_native_end_addr)
|
||||
*p_native_end_addr = native_end_addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
wasm_runtime_get_temp_ret(WASMModuleInstance *module_inst)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user