From 18d363029c3570b34e340ac480906e89c4c73ae1 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 22 Apr 2024 14:44:45 +0800 Subject: [PATCH] wasm loader: Fix checks for opcode ref.func and opcode else (#3340) Fix wasm loader integrity checks for opcode ref.func and opcode else: for opcode ref.func, the function must be an import, exported, or present in a table elem segment or global initializer to be used as the operand to ref.func, for opcode else, there must not be an else opcode previously. Reported in #3336 and #3337. And fix mini loader PUSH_MEM_OFFSET/POP_MEM_OFFSET macro definitions due to the introducing of memory64 feature. --- core/iwasm/interpreter/wasm_loader.c | 67 ++++++++++++++++------- core/iwasm/interpreter/wasm_mini_loader.c | 63 +++++++++++++++------ 2 files changed, 94 insertions(+), 36 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 6bde9cceb..9aab9febd 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -4628,7 +4628,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, bool is_passive = false; uint32 mem_flag; #endif - uint8 mem_offset_type; + uint8 mem_offset_type = VALUE_TYPE_I32; read_leb_uint32(p, p_end, data_seg_count); @@ -11335,8 +11335,10 @@ re_scan: BlockType block_type; if (loader_ctx->csp_num < 2 - || (loader_ctx->frame_csp - 1)->label_type - != LABEL_TYPE_IF) { + /* the matched if isn't found */ + || (loader_ctx->frame_csp - 1)->label_type != LABEL_TYPE_IF + /* duplicated else is found */ + || (loader_ctx->frame_csp - 1)->else_addr) { set_error_buf( error_buf, error_buf_size, "opcode else found without matched opcode if"); @@ -12408,33 +12410,58 @@ re_scan: goto fail; } - /* Refer to a forward-declared function */ - if (func_idx >= cur_func_idx + module->import_function_count) { + /* Refer to a forward-declared function: + the function must be an import, exported, or present in + a table elem segment or global initializer to be used as + the operand to ref.func */ + if (func_idx >= module->import_function_count) { WASMTableSeg *table_seg = module->table_segments; bool func_declared = false; uint32 j; - /* Check whether the function is declared in table segs, - note that it doesn't matter whether the table seg's mode - is passive, active or declarative. */ - for (i = 0; i < module->table_seg_count; i++, table_seg++) { - if (table_seg->elem_type == VALUE_TYPE_FUNCREF + for (i = 0; i < module->global_count; i++) { + if (module->globals[i].type == VALUE_TYPE_FUNCREF + && module->globals[i].init_expr.init_expr_type + == INIT_EXPR_TYPE_FUNCREF_CONST + && module->globals[i].init_expr.u.u32 == func_idx) { + func_declared = true; + break; + } + } + + if (!func_declared) { + /* Check whether the function is declared in table segs, + note that it doesn't matter whether the table seg's + mode is passive, active or declarative. */ + for (i = 0; i < module->table_seg_count; + i++, table_seg++) { + if (table_seg->elem_type == VALUE_TYPE_FUNCREF #if WASM_ENABLE_GC != 0 - || (table_seg->elem_type == REF_TYPE_HT_NON_NULLABLE - && table_seg->elem_ref_type->ref_ht_common - .heap_type - == HEAP_TYPE_FUNC) + /* elem type is (ref null? func) or + (ref null? $t) */ + || ((table_seg->elem_type + == REF_TYPE_HT_NON_NULLABLE + || table_seg->elem_type + == REF_TYPE_HT_NULLABLE) + && (table_seg->elem_ref_type->ref_ht_common + .heap_type + == HEAP_TYPE_FUNC + || table_seg->elem_ref_type + ->ref_ht_common.heap_type + > 0)) #endif - ) { - for (j = 0; j < table_seg->value_count; j++) { - if (table_seg->init_values[j].u.ref_index - == func_idx) { - func_declared = true; - break; + ) { + for (j = 0; j < table_seg->value_count; j++) { + if (table_seg->init_values[j].u.ref_index + == func_idx) { + func_declared = true; + break; + } } } } } + if (!func_declared) { /* Check whether the function is exported */ for (i = 0; i < module->export_count; i++) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index e82c85278..d5282c675 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1776,7 +1776,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, bool is_passive = false; uint32 mem_flag; #endif - uint8 mem_offset_type; + uint8 mem_offset_type = VALUE_TYPE_I32; read_leb_uint32(p, p_end, data_seg_count); @@ -5179,10 +5179,21 @@ fail: goto fail; \ } while (0) -#define PUSH_MEM_OFFSET() PUSH_OFFSET_TYPE(mem_offset_type) +#define PUSH_MEM_OFFSET() \ + do { \ + if (!wasm_loader_push_frame_ref_offset(loader_ctx, mem_offset_type, \ + disable_emit, operand_offset, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() -#define POP_MEM_OFFSET() POP_OFFSET_TYPE(mem_offset_type) +#define POP_MEM_OFFSET() \ + do { \ + if (!wasm_loader_pop_frame_ref_offset(loader_ctx, mem_offset_type, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) #define POP_AND_PUSH(type_pop, type_push) \ do { \ @@ -6203,8 +6214,11 @@ re_scan: BranchBlock *block = NULL; BlockType block_type = (loader_ctx->frame_csp - 1)->block_type; bh_assert(loader_ctx->csp_num >= 2 + /* the matched if is found */ && (loader_ctx->frame_csp - 1)->label_type - == LABEL_TYPE_IF); + == LABEL_TYPE_IF + /* duplicated else isn't found */ + && !(loader_ctx->frame_csp - 1)->else_addr); block = loader_ctx->frame_csp - 1; /* check whether if branch's stack matches its result type */ @@ -6916,26 +6930,43 @@ re_scan: goto fail; } - /* Refer to a forward-declared function */ - if (func_idx >= cur_func_idx + module->import_function_count) { + /* Refer to a forward-declared function: + the function must be an import, exported, or present in + a table elem segment or global initializer to be used as + the operand to ref.func */ + if (func_idx >= module->import_function_count) { WASMTableSeg *table_seg = module->table_segments; bool func_declared = false; uint32 j; - /* Check whether the function is declared in table segs, - note that it doesn't matter whether the table seg's mode - is passive, active or declarative. */ - for (i = 0; i < module->table_seg_count; i++, table_seg++) { - if (table_seg->elem_type == VALUE_TYPE_FUNCREF) { - for (j = 0; j < table_seg->value_count; j++) { - if (table_seg->init_values[j].u.ref_index - == func_idx) { - func_declared = true; - break; + for (i = 0; i < module->global_count; i++) { + if (module->globals[i].type == VALUE_TYPE_FUNCREF + && module->globals[i].init_expr.init_expr_type + == INIT_EXPR_TYPE_FUNCREF_CONST + && module->globals[i].init_expr.u.u32 == func_idx) { + func_declared = true; + break; + } + } + + if (!func_declared) { + /* Check whether the function is declared in table segs, + note that it doesn't matter whether the table seg's + mode is passive, active or declarative. */ + for (i = 0; i < module->table_seg_count; + i++, table_seg++) { + if (table_seg->elem_type == VALUE_TYPE_FUNCREF) { + for (j = 0; j < table_seg->value_count; j++) { + if (table_seg->init_values[j].u.ref_index + == func_idx) { + func_declared = true; + break; + } } } } } + if (!func_declared) { /* Check whether the function is exported */ for (i = 0; i < module->export_count; i++) {