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.
This commit is contained in:
Wenyong Huang 2024-04-22 14:44:45 +08:00 committed by GitHub
parent a6e008bca7
commit 18d363029c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 94 additions and 36 deletions

View File

@ -4628,7 +4628,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end,
bool is_passive = false; bool is_passive = false;
uint32 mem_flag; uint32 mem_flag;
#endif #endif
uint8 mem_offset_type; uint8 mem_offset_type = VALUE_TYPE_I32;
read_leb_uint32(p, p_end, data_seg_count); read_leb_uint32(p, p_end, data_seg_count);
@ -11335,8 +11335,10 @@ re_scan:
BlockType block_type; BlockType block_type;
if (loader_ctx->csp_num < 2 if (loader_ctx->csp_num < 2
|| (loader_ctx->frame_csp - 1)->label_type /* the matched if isn't found */
!= LABEL_TYPE_IF) { || (loader_ctx->frame_csp - 1)->label_type != LABEL_TYPE_IF
/* duplicated else is found */
|| (loader_ctx->frame_csp - 1)->else_addr) {
set_error_buf( set_error_buf(
error_buf, error_buf_size, error_buf, error_buf_size,
"opcode else found without matched opcode if"); "opcode else found without matched opcode if");
@ -12408,22 +12410,45 @@ re_scan:
goto fail; goto fail;
} }
/* Refer to a forward-declared function */ /* Refer to a forward-declared function:
if (func_idx >= cur_func_idx + module->import_function_count) { 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; WASMTableSeg *table_seg = module->table_segments;
bool func_declared = false; bool func_declared = false;
uint32 j; uint32 j;
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, /* Check whether the function is declared in table segs,
note that it doesn't matter whether the table seg's mode note that it doesn't matter whether the table seg's
is passive, active or declarative. */ mode is passive, active or declarative. */
for (i = 0; i < module->table_seg_count; i++, table_seg++) { for (i = 0; i < module->table_seg_count;
i++, table_seg++) {
if (table_seg->elem_type == VALUE_TYPE_FUNCREF if (table_seg->elem_type == VALUE_TYPE_FUNCREF
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
|| (table_seg->elem_type == REF_TYPE_HT_NON_NULLABLE /* elem type is (ref null? func) or
&& table_seg->elem_ref_type->ref_ht_common (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
== HEAP_TYPE_FUNC) == HEAP_TYPE_FUNC
|| table_seg->elem_ref_type
->ref_ht_common.heap_type
> 0))
#endif #endif
) { ) {
for (j = 0; j < table_seg->value_count; j++) { for (j = 0; j < table_seg->value_count; j++) {
@ -12435,6 +12460,8 @@ re_scan:
} }
} }
} }
}
if (!func_declared) { if (!func_declared) {
/* Check whether the function is exported */ /* Check whether the function is exported */
for (i = 0; i < module->export_count; i++) { for (i = 0; i < module->export_count; i++) {

View File

@ -1776,7 +1776,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end,
bool is_passive = false; bool is_passive = false;
uint32 mem_flag; uint32 mem_flag;
#endif #endif
uint8 mem_offset_type; uint8 mem_offset_type = VALUE_TYPE_I32;
read_leb_uint32(p, p_end, data_seg_count); read_leb_uint32(p, p_end, data_seg_count);
@ -5179,10 +5179,21 @@ fail:
goto fail; \ goto fail; \
} while (0) } 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 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) \ #define POP_AND_PUSH(type_pop, type_push) \
do { \ do { \
@ -6203,8 +6214,11 @@ re_scan:
BranchBlock *block = NULL; BranchBlock *block = NULL;
BlockType block_type = (loader_ctx->frame_csp - 1)->block_type; BlockType block_type = (loader_ctx->frame_csp - 1)->block_type;
bh_assert(loader_ctx->csp_num >= 2 bh_assert(loader_ctx->csp_num >= 2
/* the matched if is found */
&& (loader_ctx->frame_csp - 1)->label_type && (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; block = loader_ctx->frame_csp - 1;
/* check whether if branch's stack matches its result type */ /* check whether if branch's stack matches its result type */
@ -6916,16 +6930,31 @@ re_scan:
goto fail; goto fail;
} }
/* Refer to a forward-declared function */ /* Refer to a forward-declared function:
if (func_idx >= cur_func_idx + module->import_function_count) { 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; WASMTableSeg *table_seg = module->table_segments;
bool func_declared = false; bool func_declared = false;
uint32 j; uint32 j;
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, /* Check whether the function is declared in table segs,
note that it doesn't matter whether the table seg's mode note that it doesn't matter whether the table seg's
is passive, active or declarative. */ mode is passive, active or declarative. */
for (i = 0; i < module->table_seg_count; i++, table_seg++) { for (i = 0; i < module->table_seg_count;
i++, table_seg++) {
if (table_seg->elem_type == VALUE_TYPE_FUNCREF) { if (table_seg->elem_type == VALUE_TYPE_FUNCREF) {
for (j = 0; j < table_seg->value_count; j++) { for (j = 0; j < table_seg->value_count; j++) {
if (table_seg->init_values[j].u.ref_index if (table_seg->init_values[j].u.ref_index
@ -6936,6 +6965,8 @@ re_scan:
} }
} }
} }
}
if (!func_declared) { if (!func_declared) {
/* Check whether the function is exported */ /* Check whether the function is exported */
for (i = 0; i < module->export_count; i++) { for (i = 0; i < module->export_count; i++) {