From f0dc6a301502a6926629a7a4becc6d81096776cc Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 4 Apr 2022 07:55:37 +0800 Subject: [PATCH] Fix fast interpreter constant space overflow issue (#1071) Fix the potential integer overflow of const index in const space of fast interpreter, emit i32/i64.const opcode when the const index is larger than INT32_MAX. And add check for the function local cell num. --- core/iwasm/interpreter/wasm_interp_fast.c | 31 +++++- core/iwasm/interpreter/wasm_loader.c | 126 +++++++++++++++++++--- core/iwasm/interpreter/wasm_mini_loader.c | 123 ++++++++++++++++++--- 3 files changed, 247 insertions(+), 33 deletions(-) diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 6638e4543..24ae38dfe 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1773,6 +1773,33 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END(); } + /* constant instructions */ + HANDLE_OP(WASM_OP_F64_CONST) + HANDLE_OP(WASM_OP_I64_CONST) + { + uint8 *orig_ip = frame_ip; + + frame_ip += sizeof(uint64); + addr_ret = GET_OFFSET(); + + bh_memcpy_s(frame_lp + addr_ret, sizeof(uint64), orig_ip, + sizeof(uint64)); + HANDLE_OP_END(); + } + + HANDLE_OP(WASM_OP_F32_CONST) + HANDLE_OP(WASM_OP_I32_CONST) + { + uint8 *orig_ip = frame_ip; + + frame_ip += sizeof(uint32); + addr_ret = GET_OFFSET(); + + bh_memcpy_s(frame_lp + addr_ret, sizeof(uint32), orig_ip, + sizeof(uint32)); + HANDLE_OP_END(); + } + /* comparison instructions of i32 */ HANDLE_OP(WASM_OP_I32_EQZ) { @@ -3496,10 +3523,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_F64_LOAD) HANDLE_OP(EXT_OP_GET_LOCAL_FAST) HANDLE_OP(WASM_OP_GET_LOCAL) - HANDLE_OP(WASM_OP_F64_CONST) - HANDLE_OP(WASM_OP_I64_CONST) - HANDLE_OP(WASM_OP_F32_CONST) - HANDLE_OP(WASM_OP_I32_CONST) HANDLE_OP(WASM_OP_DROP) HANDLE_OP(WASM_OP_DROP_64) HANDLE_OP(WASM_OP_BLOCK) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index fb411abfb..40228179c 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1824,7 +1824,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, uint32 func_count; uint64 total_size; uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index; - uint32 local_count, local_set_count, sub_local_count; + uint32 local_count, local_set_count, sub_local_count, local_cell_num; uint8 type; WASMFunction *func; @@ -1950,9 +1950,17 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, func->param_cell_num = func->func_type->param_cell_num; func->ret_cell_num = func->func_type->ret_cell_num; - func->local_cell_num = + local_cell_num = wasm_get_cell_num(func->local_types, func->local_count); + if (local_cell_num > UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "local count too large"); + return false; + } + + func->local_cell_num = (uint16)local_cell_num; + if (!init_function_local_offsets(func, error_buf, error_buf_size)) return false; @@ -4380,8 +4388,8 @@ typedef struct WASMLoaderContext { /* const buffer */ uint8 *const_buf; uint16 num_const; - uint16 const_buf_size; uint16 const_cell_num; + uint32 const_buf_size; /* processed code */ uint8 *p_code_compiled; @@ -4591,38 +4599,45 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx) } static WASMLoaderContext * -wasm_loader_ctx_init(WASMFunction *func) +wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size) { WASMLoaderContext *loader_ctx = - loader_malloc(sizeof(WASMLoaderContext), NULL, 0); + loader_malloc(sizeof(WASMLoaderContext), error_buf, error_buf_size); if (!loader_ctx) return NULL; loader_ctx->frame_ref_size = 32; - if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = - loader_malloc(loader_ctx->frame_ref_size, NULL, 0))) + if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = loader_malloc( + loader_ctx->frame_ref_size, error_buf, error_buf_size))) goto fail; loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + 32; loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8; - if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = - loader_malloc(loader_ctx->frame_csp_size, NULL, 0))) + if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = loader_malloc( + loader_ctx->frame_csp_size, error_buf, error_buf_size))) goto fail; loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8; #if WASM_ENABLE_FAST_INTERP != 0 loader_ctx->frame_offset_size = sizeof(int16) * 32; if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset = - loader_malloc(loader_ctx->frame_offset_size, NULL, 0))) + loader_malloc(loader_ctx->frame_offset_size, error_buf, + error_buf_size))) goto fail; loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32; loader_ctx->num_const = 0; loader_ctx->const_buf_size = sizeof(Const) * 8; - if (!(loader_ctx->const_buf = - loader_malloc(loader_ctx->const_buf_size, NULL, 0))) + if (!(loader_ctx->const_buf = loader_malloc(loader_ctx->const_buf_size, + error_buf, error_buf_size))) goto fail; + if (func->param_cell_num >= (int32)INT16_MAX - func->local_cell_num) { + set_error_buf(error_buf, error_buf_size, + "fast interpreter offset overflow"); + goto fail; + } + loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset = loader_ctx->max_dynamic_offset = func->param_cell_num + func->local_cell_num; @@ -4902,6 +4917,24 @@ fail: LOG_OP("%d\t", value); \ } while (0) +#define emit_uint64(ctx, value) \ + do { \ + wasm_loader_emit_const(ctx, &value, false); \ + LOG_OP("%lld\t", value); \ + } while (0) + +#define emit_float32(ctx, value) \ + do { \ + wasm_loader_emit_const(ctx, &value, true); \ + LOG_OP("%f\t", value); \ + } while (0) + +#define emit_float64(ctx, value) \ + do { \ + wasm_loader_emit_const(ctx, &value, false); \ + LOG_OP("%f\t", value); \ + } while (0) + static bool wasm_loader_ctx_reinit(WASMLoaderContext *ctx) { @@ -4933,6 +4966,28 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx) return true; } +static void +wasm_loader_emit_const(WASMLoaderContext *ctx, void *value, bool is_32_bit) +{ + uint32 size = is_32_bit ? sizeof(uint32) : sizeof(uint64); + + if (ctx->p_code_compiled) { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif + bh_memcpy_s(ctx->p_code_compiled, + ctx->p_code_compiled_end - ctx->p_code_compiled, value, + size); + ctx->p_code_compiled += size; + } + else { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif + ctx->code_compiled_size += size; + } +} + static void wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value) { @@ -5401,8 +5456,11 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value, int16 *offset, char *error_buf, uint32 error_buf_size) { + int8 bytes_to_increase; int16 operand_offset = 0; Const *c; + + /* Search existing constant */ for (c = (Const *)ctx->const_buf; (uint8 *)c < ctx->const_buf + ctx->num_const * sizeof(Const); c++) { /* TODO: handle v128 type? */ @@ -5428,7 +5486,24 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value, else operand_offset += 2; } + if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) { + /* New constant, append to the const buffer */ + if ((type == VALUE_TYPE_F64) || (type == VALUE_TYPE_I64)) { + bytes_to_increase = 2; + } + else { + bytes_to_increase = 1; + } + + /* The max cell num of const buffer is 32768 since the valid index range + * is -32768 ~ -1. Return an invalid index 0 to indicate the buffer is + * full */ + if (ctx->const_cell_num > INT16_MAX - bytes_to_increase + 1) { + *offset = 0; + return true; + } + if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) { MEM_REALLOC(ctx->const_buf, ctx->const_buf_size, ctx->const_buf_size + 4 * sizeof(Const)); @@ -6358,8 +6433,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, local_types = func->local_types; local_offsets = func->local_offsets; - if (!(loader_ctx = wasm_loader_ctx_init(func))) { - set_error_buf(error_buf, error_buf_size, "allocate memory failed"); + if (!(loader_ctx = wasm_loader_ctx_init(func, error_buf, error_buf_size))) { goto fail; } @@ -7698,6 +7772,12 @@ re_scan: skip_label(); disable_emit = true; GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const); + + if (operand_offset == 0) { + disable_emit = false; + emit_label(WASM_OP_I32_CONST); + emit_uint32(loader_ctx, i32_const); + } #else (void)i32_const; #endif @@ -7710,6 +7790,12 @@ re_scan: skip_label(); disable_emit = true; GET_CONST_OFFSET(VALUE_TYPE_I64, i64_const); + + if (operand_offset == 0) { + disable_emit = false; + emit_label(WASM_OP_I64_CONST); + emit_uint64(loader_ctx, i64_const); + } #endif PUSH_I64(); break; @@ -7722,6 +7808,12 @@ re_scan: bh_memcpy_s((uint8 *)&f32_const, sizeof(float32), p_org, sizeof(float32)); GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32_const); + + if (operand_offset == 0) { + disable_emit = false; + emit_label(WASM_OP_F32_CONST); + emit_float32(loader_ctx, f32_const); + } #endif PUSH_F32(); break; @@ -7735,6 +7827,12 @@ re_scan: bh_memcpy_s((uint8 *)&f64_const, sizeof(float64), p_org, sizeof(float64)); GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64_const); + + if (operand_offset == 0) { + disable_emit = false; + emit_label(WASM_OP_F64_CONST); + emit_float64(loader_ctx, f64_const); + } #endif PUSH_F64(); break; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index f2b8728c0..8f36e7ae8 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -910,7 +910,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, uint32 func_count; uint64 total_size; uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index; - uint32 local_count, local_set_count, sub_local_count; + uint32 local_count, local_set_count, sub_local_count, local_cell_num; uint8 type; WASMFunction *func; @@ -1001,8 +1001,11 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, func->param_cell_num = func->func_type->param_cell_num; func->ret_cell_num = func->func_type->ret_cell_num; - func->local_cell_num = + local_cell_num = wasm_get_cell_num(func->local_types, func->local_count); + bh_assert(local_cell_num <= UINT16_MAX); + + func->local_cell_num = (uint16)local_cell_num; if (!init_function_local_offsets(func, error_buf, error_buf_size)) return false; @@ -2962,8 +2965,8 @@ typedef struct WASMLoaderContext { /* const buffer */ uint8 *const_buf; uint16 num_const; - uint16 const_buf_size; uint16 const_cell_num; + uint32 const_buf_size; /* processed code */ uint8 *p_code_compiled; @@ -3148,38 +3151,45 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx) } static WASMLoaderContext * -wasm_loader_ctx_init(WASMFunction *func) +wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size) { WASMLoaderContext *loader_ctx = - loader_malloc(sizeof(WASMLoaderContext), NULL, 0); + loader_malloc(sizeof(WASMLoaderContext), error_buf, error_buf_size); if (!loader_ctx) - return false; + return NULL; loader_ctx->frame_ref_size = 32; - if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = - loader_malloc(loader_ctx->frame_ref_size, NULL, 0))) + if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = loader_malloc( + loader_ctx->frame_ref_size, error_buf, error_buf_size))) goto fail; loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + 32; loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8; - if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = - loader_malloc(loader_ctx->frame_csp_size, NULL, 0))) + if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = loader_malloc( + loader_ctx->frame_csp_size, error_buf, error_buf_size))) goto fail; loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8; #if WASM_ENABLE_FAST_INTERP != 0 loader_ctx->frame_offset_size = sizeof(int16) * 32; if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset = - loader_malloc(loader_ctx->frame_offset_size, NULL, 0))) + loader_malloc(loader_ctx->frame_offset_size, error_buf, + error_buf_size))) goto fail; loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32; loader_ctx->num_const = 0; loader_ctx->const_buf_size = sizeof(Const) * 8; - if (!(loader_ctx->const_buf = - loader_malloc(loader_ctx->const_buf_size, NULL, 0))) + if (!(loader_ctx->const_buf = loader_malloc(loader_ctx->const_buf_size, + error_buf, error_buf_size))) goto fail; + if (func->param_cell_num >= (int32)INT16_MAX - func->local_cell_num) { + set_error_buf(error_buf, error_buf_size, + "fast interpreter offset overflow"); + goto fail; + } + loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset = loader_ctx->max_dynamic_offset = func->param_cell_num + func->local_cell_num; @@ -3432,6 +3442,24 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf, LOG_OP("%d\t", value); \ } while (0) +#define emit_uint64(ctx, value) \ + do { \ + wasm_loader_emit_const(ctx, &value, false); \ + LOG_OP("%lld\t", value); \ + } while (0) + +#define emit_float32(ctx, value) \ + do { \ + wasm_loader_emit_const(ctx, &value, true); \ + LOG_OP("%f\t", value); \ + } while (0) + +#define emit_float64(ctx, value) \ + do { \ + wasm_loader_emit_const(ctx, &value, false); \ + LOG_OP("%f\t", value); \ + } while (0) + static bool wasm_loader_ctx_reinit(WASMLoaderContext *ctx) { @@ -3463,6 +3491,28 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx) return true; } +static void +wasm_loader_emit_const(WASMLoaderContext *ctx, void *value, bool is_32_bit) +{ + uint32 size = is_32_bit ? sizeof(uint32) : sizeof(uint64); + + if (ctx->p_code_compiled) { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif + bh_memcpy_s(ctx->p_code_compiled, + ctx->p_code_compiled_end - ctx->p_code_compiled, value, + size); + ctx->p_code_compiled += size; + } + else { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif + ctx->code_compiled_size += size; + } +} + static void wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value) { @@ -3931,8 +3981,11 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value, int16 *offset, char *error_buf, uint32 error_buf_size) { + int8 bytes_to_increase; int16 operand_offset = 0; Const *c; + + /* Search existing constant */ for (c = (Const *)ctx->const_buf; (uint8 *)c < ctx->const_buf + ctx->num_const * sizeof(Const); c++) { if ((type == c->value_type) @@ -3957,7 +4010,24 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value, else operand_offset += 1; } + if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) { + /* New constant, append to the const buffer */ + if ((type == VALUE_TYPE_F64) || (type == VALUE_TYPE_I64)) { + bytes_to_increase = 2; + } + else { + bytes_to_increase = 1; + } + + /* The max cell num of const buffer is 32768 since the valid index range + * is -32768 ~ -1. Return an invalid index 0 to indicate the buffer is + * full */ + if (ctx->const_cell_num > INT16_MAX - bytes_to_increase + 1) { + *offset = 0; + return true; + } + if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) { MEM_REALLOC(ctx->const_buf, ctx->const_buf_size, ctx->const_buf_size + 4 * sizeof(Const)); @@ -4757,8 +4827,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, local_types = func->local_types; local_offsets = func->local_offsets; - if (!(loader_ctx = wasm_loader_ctx_init(func))) { - set_error_buf(error_buf, error_buf_size, "allocate memory failed"); + if (!(loader_ctx = wasm_loader_ctx_init(func, error_buf, error_buf_size))) { goto fail; } @@ -5943,6 +6012,12 @@ re_scan: skip_label(); disable_emit = true; GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const); + + if (operand_offset == 0) { + disable_emit = false; + emit_label(WASM_OP_I32_CONST); + emit_uint32(loader_ctx, i32_const); + } #else (void)i32_const; #endif @@ -5955,6 +6030,12 @@ re_scan: skip_label(); disable_emit = true; GET_CONST_OFFSET(VALUE_TYPE_I64, i64_const); + + if (operand_offset == 0) { + disable_emit = false; + emit_label(WASM_OP_I64_CONST); + emit_uint64(loader_ctx, i64_const); + } #endif PUSH_I64(); break; @@ -5967,6 +6048,12 @@ re_scan: bh_memcpy_s((uint8 *)&f32_const, sizeof(float32), p_org, sizeof(float32)); GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32_const); + + if (operand_offset == 0) { + disable_emit = false; + emit_label(WASM_OP_F32_CONST); + emit_float32(loader_ctx, f32_const); + } #endif PUSH_F32(); break; @@ -5980,6 +6067,12 @@ re_scan: bh_memcpy_s((uint8 *)&f64_const, sizeof(float64), p_org, sizeof(float64)); GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64_const); + + if (operand_offset == 0) { + disable_emit = false; + emit_label(WASM_OP_F64_CONST); + emit_float64(loader_ctx, f64_const); + } #endif PUSH_F64(); break;