From 4bdb0ad132ba262d619d4cf56a686b8b6b006bb0 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Tue, 6 Jul 2021 11:54:36 +0430 Subject: [PATCH] LibWasm: Guard stack accesses with checks If the stack is empty, let's just trap. --- .../AbstractMachine/BytecodeInterpreter.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 868e1a7113..8d8d846533 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -87,6 +87,7 @@ void BytecodeInterpreter::load_and_push(Configuration& configuration, Instructio return; } auto& arg = instruction.arguments().get(); + TRAP_IF_NOT(!configuration.stack().is_empty()); auto& entry = configuration.stack().peek(); TRAP_IF_NOT(entry.has()); auto base = entry.get().to(); @@ -111,6 +112,7 @@ void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruct auto memory = configuration.store().get(address); TRAP_IF_NOT(memory); auto& arg = instruction.arguments().get(); + TRAP_IF_NOT(!configuration.stack().is_empty()); auto entry = configuration.stack().pop(); TRAP_IF_NOT(entry.has()); auto base = entry.get().to(); @@ -164,6 +166,7 @@ void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd #define BINARY_NUMERIC_OPERATION(type, operator, cast, ...) \ do { \ + TRAP_IF_NOT(!configuration.stack().is_empty()); \ auto rhs_entry = configuration.stack().pop(); \ auto& lhs_entry = configuration.stack().peek(); \ TRAP_IF_NOT(rhs_entry.has()); \ @@ -181,6 +184,7 @@ void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd #define OVF_CHECKED_BINARY_NUMERIC_OPERATION(type, operator, cast, ...) \ do { \ + TRAP_IF_NOT(!configuration.stack().is_empty()); \ auto rhs_entry = configuration.stack().pop(); \ auto& lhs_entry = configuration.stack().peek(); \ TRAP_IF_NOT(rhs_entry.has()); \ @@ -202,6 +206,7 @@ void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd #define BINARY_PREFIX_NUMERIC_OPERATION(type, operation, cast, ...) \ do { \ + TRAP_IF_NOT(!configuration.stack().is_empty()); \ auto rhs_entry = configuration.stack().pop(); \ auto& lhs_entry = configuration.stack().peek(); \ TRAP_IF_NOT(rhs_entry.has()); \ @@ -218,6 +223,7 @@ void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd #define UNARY_MAP(pop_type, operation, ...) \ do { \ + TRAP_IF_NOT(!configuration.stack().is_empty()); \ auto& entry = configuration.stack().peek(); \ TRAP_IF_NOT(entry.has()); \ auto value = entry.get().to(); \ @@ -238,6 +244,7 @@ void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd #define POP_AND_STORE(pop_type, store_type) \ do { \ + TRAP_IF_NOT(!configuration.stack().is_empty()); \ auto entry = configuration.stack().pop(); \ TRAP_IF_NOT(entry.has()); \ auto value = ConvertToRaw {}(*entry.get().to()); \ @@ -498,6 +505,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi configuration.stack().push(Value(configuration.frame().locals()[instruction.arguments().get().value()])); return; case Instructions::local_set.value(): { + TRAP_IF_NOT(!configuration.stack().is_empty()); auto entry = configuration.stack().pop(); TRAP_IF_NOT(entry.has()); configuration.frame().locals()[instruction.arguments().get().value()] = move(entry.get()); @@ -537,6 +545,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi if (args.block_type.kind() != BlockType::Empty) arity = 1; + TRAP_IF_NOT(!configuration.stack().is_empty()); auto entry = configuration.stack().pop(); TRAP_IF_NOT(entry.has()); auto value = entry.get().to(); @@ -594,6 +603,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi case Instructions::br.value(): return branch_to_label(configuration, instruction.arguments().get()); case Instructions::br_if.value(): { + TRAP_IF_NOT(!configuration.stack().is_empty()); auto entry = configuration.stack().pop(); TRAP_IF_NOT(entry.has()); if (entry.get().to().value_or(0) == 0) @@ -602,6 +612,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi } case Instructions::br_table.value(): { auto& arguments = instruction.arguments().get(); + TRAP_IF_NOT(!configuration.stack().is_empty()); auto entry = configuration.stack().pop(); TRAP_IF_NOT(entry.has()); auto maybe_i = entry.get().to(); @@ -625,6 +636,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi TRAP_IF_NOT(args.table.value() < configuration.frame().module().tables().size()); auto table_address = configuration.frame().module().tables()[args.table.value()]; auto table_instance = configuration.store().get(table_address); + TRAP_IF_NOT(!configuration.stack().is_empty()); auto entry = configuration.stack().pop(); TRAP_IF_NOT(entry.has()); auto index = entry.get().to(); @@ -686,6 +698,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi case Instructions::i64_store32.value(): POP_AND_STORE(i64, i32); case Instructions::local_tee.value(): { + TRAP_IF_NOT(!configuration.stack().is_empty()); auto& entry = configuration.stack().peek(); TRAP_IF_NOT(entry.has()); auto value = entry.get(); @@ -708,6 +721,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi auto global_index = instruction.arguments().get(); TRAP_IF_NOT(configuration.frame().module().globals().size() > global_index.value()); auto address = configuration.frame().module().globals()[global_index.value()]; + TRAP_IF_NOT(!configuration.stack().is_empty()); auto entry = configuration.stack().pop(); TRAP_IF_NOT(entry.has()); auto value = entry.get(); @@ -730,6 +744,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi auto address = configuration.frame().module().memories()[0]; auto instance = configuration.store().get(address); i32 old_pages = instance->size() / Constants::page_size; + TRAP_IF_NOT(!configuration.stack().is_empty()); auto& entry = configuration.stack().peek(); TRAP_IF_NOT(entry.has()); auto new_pages = entry.get().to(); @@ -759,6 +774,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi return; } case Instructions::ref_is_null.value(): { + TRAP_IF_NOT(!configuration.stack().is_empty()); auto top = configuration.stack().peek().get_pointer(); TRAP_IF_NOT(top); TRAP_IF_NOT(top->type().is_reference()); @@ -767,11 +783,13 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi return; } case Instructions::drop.value(): + TRAP_IF_NOT(!configuration.stack().is_empty()); configuration.stack().pop(); return; case Instructions::select.value(): case Instructions::select_typed.value(): { // Note: The type seems to only be used for validation. + TRAP_IF_NOT(!configuration.stack().is_empty()); auto entry = configuration.stack().pop(); TRAP_IF_NOT(entry.has()); auto value = entry.get().to();