Add more security checks for libc wrapper API's (#105)

This commit is contained in:
wenyongh 2019-08-28 15:06:04 +08:00 committed by GitHub
parent 92cbecbec8
commit c808aa2ebb
3 changed files with 187 additions and 24 deletions

View File

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

View File

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

View File

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