Commit c5722641 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm] Improve error handling in global init decoder

This fixes a case where we hit a DCHECK in Debug mode, or silently
discarded bogus data in Release mode without rejecting the module.

Fixed: chromium:1108815
Change-Id: I928ff244a54b016cd8470be1ec4b5faf2c7e3994
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2349768
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarManos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69391}
parent 8876db49
...@@ -1619,10 +1619,6 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1619,10 +1619,6 @@ class ModuleDecoderImpl : public Decoder {
} }
WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected) { WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected) {
if (pc() >= end()) {
error(pc(), "Global initializer starting beyond code end");
return {};
}
constexpr Decoder::ValidateFlag validate = Decoder::kValidate; constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
WasmOpcode opcode = kExprNop; WasmOpcode opcode = kExprNop;
std::vector<WasmInitExpr> stack; std::vector<WasmInitExpr> stack;
...@@ -1635,14 +1631,14 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1635,14 +1631,14 @@ class ModuleDecoderImpl : public Decoder {
len = 1 + imm.length; len = 1 + imm.length;
if (V8_UNLIKELY(module->globals.size() <= imm.index)) { if (V8_UNLIKELY(module->globals.size() <= imm.index)) {
error(pc() + 1, "global index is out of bounds"); error(pc() + 1, "global index is out of bounds");
break; return {};
} }
WasmGlobal* global = &module->globals[imm.index]; WasmGlobal* global = &module->globals[imm.index];
if (V8_UNLIKELY(global->mutability || !global->imported)) { if (V8_UNLIKELY(global->mutability || !global->imported)) {
error(pc() + 1, error(pc() + 1,
"only immutable imported globals can be used in initializer " "only immutable imported globals can be used in initializer "
"expressions"); "expressions");
break; return {};
} }
stack.push_back(WasmInitExpr::GlobalGet(imm.index)); stack.push_back(WasmInitExpr::GlobalGet(imm.index));
break; break;
...@@ -1678,12 +1674,12 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1678,12 +1674,12 @@ class ModuleDecoderImpl : public Decoder {
"invalid opcode 0x%x in global initializer, enable with " "invalid opcode 0x%x in global initializer, enable with "
"--experimental-wasm-reftypes or --experimental-wasm-eh", "--experimental-wasm-reftypes or --experimental-wasm-eh",
kExprRefNull); kExprRefNull);
break; return {};
} }
HeapTypeImmediate<Decoder::kValidate> imm(enabled_features_, this, HeapTypeImmediate<Decoder::kValidate> imm(enabled_features_, this,
pc() + 1); pc() + 1);
len = 1 + imm.length; len = 1 + imm.length;
if (!Validate(pc() + 1, imm)) break; if (!Validate(pc() + 1, imm)) return {};
stack.push_back( stack.push_back(
WasmInitExpr::RefNullConst(imm.type.representation())); WasmInitExpr::RefNullConst(imm.type.representation()));
break; break;
...@@ -1694,14 +1690,14 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1694,14 +1690,14 @@ class ModuleDecoderImpl : public Decoder {
"invalid opcode 0x%x in global initializer, enable with " "invalid opcode 0x%x in global initializer, enable with "
"--experimental-wasm-reftypes", "--experimental-wasm-reftypes",
kExprRefFunc); kExprRefFunc);
break; return {};
} }
FunctionIndexImmediate<Decoder::kValidate> imm(this, pc() + 1); FunctionIndexImmediate<Decoder::kValidate> imm(this, pc() + 1);
len = 1 + imm.length; len = 1 + imm.length;
if (V8_UNLIKELY(module->functions.size() <= imm.index)) { if (V8_UNLIKELY(module->functions.size() <= imm.index)) {
errorf(pc(), "invalid function index: %u", imm.index); errorf(pc(), "invalid function index: %u", imm.index);
break; return {};
} }
stack.push_back(WasmInitExpr::RefFuncConst(imm.index)); stack.push_back(WasmInitExpr::RefFuncConst(imm.index));
// Functions referenced in the globals section count as "declared". // Functions referenced in the globals section count as "declared".
...@@ -1709,11 +1705,14 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1709,11 +1705,14 @@ class ModuleDecoderImpl : public Decoder {
break; break;
} }
case kSimdPrefix: { case kSimdPrefix: {
// No need to check for Simd in enabled_features_ here; we either
// failed to validate the global's type earlier, or will fail in
// the type check or stack height check at the end.
opcode = read_prefixed_opcode<validate>(pc(), &len); opcode = read_prefixed_opcode<validate>(pc(), &len);
if (V8_UNLIKELY(opcode != kExprS128Const)) { if (V8_UNLIKELY(opcode != kExprS128Const)) {
errorf(pc(), "invalid SIMD opcode 0x%x in global initializer", errorf(pc(), "invalid SIMD opcode 0x%x in global initializer",
opcode); opcode);
break; return {};
} }
Simd128Immediate<validate> imm(this, pc() + len + 1); Simd128Immediate<validate> imm(this, pc() + len + 1);
...@@ -1722,13 +1721,16 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1722,13 +1721,16 @@ class ModuleDecoderImpl : public Decoder {
break; break;
} }
case kGCPrefix: { case kGCPrefix: {
// No need to check for GC in enabled_features_ here; we either
// failed to validate the global's type earlier, or will fail in
// the type check or stack height check at the end.
opcode = read_prefixed_opcode<validate>(pc(), &len); opcode = read_prefixed_opcode<validate>(pc(), &len);
switch (opcode) { switch (opcode) {
case kExprRttCanon: { case kExprRttCanon: {
HeapTypeImmediate<validate> imm(enabled_features_, this, HeapTypeImmediate<validate> imm(enabled_features_, this,
pc() + 2); pc() + 2);
len += 1 + imm.length; len += 1 + imm.length;
if (!Validate(pc() + 2, imm)) break; if (!Validate(pc() + 2, imm)) return {};
stack.push_back( stack.push_back(
WasmInitExpr::RttCanon(imm.type.representation())); WasmInitExpr::RttCanon(imm.type.representation()));
break; break;
...@@ -1737,10 +1739,10 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1737,10 +1739,10 @@ class ModuleDecoderImpl : public Decoder {
HeapTypeImmediate<validate> imm(enabled_features_, this, HeapTypeImmediate<validate> imm(enabled_features_, this,
pc() + 2); pc() + 2);
len += 1 + imm.length; len += 1 + imm.length;
if (!Validate(pc() + 2, imm)) break; if (!Validate(pc() + 2, imm)) return {};
if (stack.empty()) { if (stack.empty()) {
error(pc(), "calling rtt.sub without arguments"); error(pc(), "calling rtt.sub without arguments");
break; return {};
} }
WasmInitExpr parent = std::move(stack.back()); WasmInitExpr parent = std::move(stack.back());
stack.pop_back(); stack.pop_back();
...@@ -1752,7 +1754,7 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1752,7 +1754,7 @@ class ModuleDecoderImpl : public Decoder {
ValueType::Ref(parent_type.heap_type(), kNonNullable), ValueType::Ref(parent_type.heap_type(), kNonNullable),
module_.get()))) { module_.get()))) {
error(pc(), "rtt.sub requires a supertype rtt on stack"); error(pc(), "rtt.sub requires a supertype rtt on stack");
break; return {};
} }
stack.push_back(WasmInitExpr::RttSub(imm.type.representation(), stack.push_back(WasmInitExpr::RttSub(imm.type.representation(),
std::move(parent))); std::move(parent)));
...@@ -1760,18 +1762,12 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1760,18 +1762,12 @@ class ModuleDecoderImpl : public Decoder {
} }
default: { default: {
errorf(pc(), "invalid opcode 0x%x in global initializer", opcode); errorf(pc(), "invalid opcode 0x%x in global initializer", opcode);
break; return {};
} }
} }
break; break; // case kGCPrefix
} }
case kExprEnd: case kExprEnd:
if (V8_UNLIKELY(stack.size() != 1)) {
errorf(pc(),
"Found 'end' in global initalizer, but %s expressions were "
"found on the stack",
stack.size() > 1 ? "more than one" : "no");
}
break; break;
default: { default: {
errorf(pc(), "invalid opcode 0x%x in global initializer", opcode); errorf(pc(), "invalid opcode 0x%x in global initializer", opcode);
...@@ -1785,9 +1781,17 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1785,9 +1781,17 @@ class ModuleDecoderImpl : public Decoder {
error(end(), "Global initializer extending beyond code end"); error(end(), "Global initializer extending beyond code end");
return {}; return {};
} }
if (V8_UNLIKELY(this->failed())) return {}; if (V8_UNLIKELY(opcode != kExprEnd)) {
error(pc(), "Global initializer is missing 'end'");
DCHECK_EQ(stack.size(), 1); return {};
}
if (V8_UNLIKELY(stack.size() != 1)) {
errorf(pc(),
"Found 'end' in global initalizer, but %s expressions were "
"found on the stack",
stack.size() > 1 ? "more than one" : "no");
return {};
}
WasmInitExpr expr = std::move(stack.back()); WasmInitExpr expr = std::move(stack.back());
if (expected != kWasmStmt && !IsSubtypeOf(TypeOf(expr), expected, module)) { if (expected != kWasmStmt && !IsSubtypeOf(TypeOf(expr), expected, module)) {
......
...@@ -491,6 +491,61 @@ TEST_F(WasmModuleVerifyTest, Global_invalid_type2) { ...@@ -491,6 +491,61 @@ TEST_F(WasmModuleVerifyTest, Global_invalid_type2) {
EXPECT_FAILURE(data); EXPECT_FAILURE(data);
} }
TEST_F(WasmModuleVerifyTest, Global_invalid_init) {
static const byte no_initializer_no_end[] = {
SECTION(Global, //--
ENTRY_COUNT(1), //--
kLocalI32, // type
1) // mutable
};
EXPECT_FAILURE_WITH_MSG(no_initializer_no_end,
"Global initializer is missing 'end'");
static const byte no_initializer[] = {
SECTION(Global, //--
ENTRY_COUNT(1), //--
kLocalI32, // type
1, // mutable
kExprEnd) // --
};
EXPECT_FAILURE_WITH_MSG(no_initializer,
"Found 'end' in global initalizer, but no "
"expressions were found on the stack");
static const byte too_many_initializers_no_end[] = {
SECTION(Global, // --
ENTRY_COUNT(1), // --
kLocalI32, // type
1, // mutable
WASM_I32V_1(42), // one value is good
WASM_I32V_1(43)) // another value is too much
};
EXPECT_FAILURE_WITH_MSG(too_many_initializers_no_end,
"Global initializer is missing 'end'");
static const byte too_many_initializers[] = {
SECTION(Global, // --
ENTRY_COUNT(1), // --
kLocalI32, // type
1, // mutable
WASM_I32V_1(42), // one value is good
WASM_I32V_1(43), // another value is too much
kExprEnd)};
EXPECT_FAILURE_WITH_MSG(too_many_initializers,
"Found 'end' in global initalizer, but more than one "
"expressions were found on the stack");
static const byte missing_end_opcode[] = {
SECTION(Global, // --
ENTRY_COUNT(1), // --
kLocalI32, // type
1, // mutable
WASM_I32V_1(42)) // init value
};
EXPECT_FAILURE_WITH_MSG(missing_end_opcode,
"Global initializer is missing 'end'");
}
TEST_F(WasmModuleVerifyTest, ZeroGlobals) { TEST_F(WasmModuleVerifyTest, ZeroGlobals) {
static const byte data[] = {SECTION(Global, ENTRY_COUNT(0))}; static const byte data[] = {SECTION(Global, ENTRY_COUNT(0))};
ModuleResult result = DecodeModule(data, data + sizeof(data)); ModuleResult result = DecodeModule(data, data + sizeof(data));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment