Skip to content

Commit

Permalink
Check stack height for OP_CALLF
Browse files Browse the repository at this point in the history
  • Loading branch information
rodiazet authored and gumb0 committed Aug 3, 2023
1 parent 5b9c216 commit ff73384
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 6 deletions.
14 changes: 11 additions & 3 deletions lib/evmone/eof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ constexpr auto CODE_SECTION_NUMBER_LIMIT = 1024;
constexpr auto MAX_STACK_HEIGHT = 0x03FF;
constexpr auto OUTPUTS_INPUTS_NUMBER_LIMIT = 0x7F;
constexpr auto REL_OFFSET_SIZE = sizeof(int16_t);
constexpr auto STACK_SIZE_LIMIT = 1024;

using EOFSectionHeaders = std::array<std::vector<uint16_t>, MAX_SECTION + 1>;

Expand Down Expand Up @@ -343,18 +344,23 @@ std::variant<EOFValidationError, int32_t> validate_max_stack_height(
auto stack_height_required = instr::traits[opcode].stack_height_required;
auto stack_height_change = instr::traits[opcode].stack_height_change;

auto stack_height = stack_heights[i];
assert(stack_height != LOC_UNVISITED);

if (opcode == OP_CALLF)
{
const auto fid = read_uint16_be(&code[i + 1]);

stack_height_required = static_cast<int8_t>(code_types[fid].inputs);

if (stack_height + code_types[fid].max_stack_height - stack_height_required >
STACK_SIZE_LIMIT)
return EOFValidationError::stack_overflow;

stack_height_change =
static_cast<int8_t>(code_types[fid].outputs - stack_height_required);
}

auto stack_height = stack_heights[i];
assert(stack_height != LOC_UNVISITED);

if (stack_height < stack_height_required)
return EOFValidationError::stack_underflow;

Expand Down Expand Up @@ -628,6 +634,8 @@ std::string_view get_error_message(EOFValidationError err) noexcept
return "unreachable_instructions";
case EOFValidationError::stack_underflow:
return "stack_underflow";
case EOFValidationError::stack_overflow:
return "stack_overflow";
case EOFValidationError::invalid_code_section_index:
return "invalid_code_section_index";
case EOFValidationError::invalid_dataloadn_index:
Expand Down
1 change: 1 addition & 0 deletions lib/evmone/eof.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ enum class EOFValidationError
inputs_outputs_num_above_limit,
unreachable_instructions,
stack_underflow,
stack_overflow,
invalid_code_section_index,
invalid_dataloadn_index,

Expand Down
70 changes: 70 additions & 0 deletions test/unittests/eof_validation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ TEST(eof_validation, get_error_message)
{
EXPECT_EQ(evmone::get_error_message(EOFValidationError::success), "success");
EXPECT_EQ(evmone::get_error_message(EOFValidationError::invalid_prefix), "invalid_prefix");
EXPECT_EQ(evmone::get_error_message(EOFValidationError::stack_overflow), "stack_overflow");
EXPECT_EQ(evmone::get_error_message(EOFValidationError::impossible), "impossible");
EXPECT_EQ(evmone::get_error_message(static_cast<EOFValidationError>(-1)), "<unknown>");
}
Expand Down Expand Up @@ -740,6 +741,75 @@ TEST(eof_validation, callf_invalid_code_section_index)
EOFValidationError::invalid_code_section_index);
}

TEST(eof_validation, callf_stack_overflow)
{
{
auto code = eof1_bytecode(
512 * push(1) + OP_CALLF + bytecode{"0x0000"_hex} + 510 * OP_POP + OP_RETURN, 512);
EXPECT_EQ(validate_eof(code), EOFValidationError::success);
}

{
auto code = eof1_bytecode(
513 * push(1) + OP_CALLF + bytecode{"0x0000"_hex} + 511 * OP_POP + OP_RETURN, 513);
EXPECT_EQ(validate_eof(code), EOFValidationError::stack_overflow);
}

{
auto code = eof1_bytecode(
1023 * push(1) + OP_CALLF + bytecode{"0x0000"_hex} + 1021 * OP_POP + OP_RETURN, 1023);
EXPECT_EQ(validate_eof(code), EOFValidationError::stack_overflow);
}
}

TEST(eof_validation, callf_with_inputs_stack_overflow)
{
{
const auto code =
bytecode{"ef0001 010008 020002 0BFD 0003 040000 00 000003FF 02000002"_hex} +
1023 * push(1) + OP_CALLF + bytecode{"0x0001"_hex} + 1019 * OP_POP + OP_RETURN +
OP_POP + OP_POP + OP_RETF;

EXPECT_EQ(validate_eof(code), EOFValidationError::success);
}

{
const auto code =
bytecode{"ef0001 010008 020002 0BFF 0004 040000 00 000003FF 03030004"_hex} +
1023 * push(1) + OP_CALLF + bytecode{"0x0001"_hex} + 1021 * OP_POP + OP_RETURN +
push(1) + OP_POP + OP_RETF;

EXPECT_EQ(validate_eof(code), EOFValidationError::success);
}

{
const auto code =
bytecode{"ef0001 010008 020002 0BFF 0003 040000 00 000003FF 03050005"_hex} +
1023 * push(1) + OP_CALLF + bytecode{"0x0001"_hex} + 1021 * OP_POP + OP_RETURN +
OP_PUSH0 + OP_PUSH0 + OP_RETF;

EXPECT_EQ(validate_eof(code), EOFValidationError::stack_overflow);
}

{
const auto code =
bytecode{"ef0001 010008 020002 0BFF 0005 040000 00 000003FF 03030005"_hex} +
1023 * push(1) + OP_CALLF + bytecode{"0x0001"_hex} + 1021 * OP_POP + OP_RETURN +
OP_PUSH0 + OP_PUSH0 + OP_POP + OP_POP + OP_RETF;

EXPECT_EQ(validate_eof(code), EOFValidationError::stack_overflow);
}

{
const auto code =
bytecode{"ef0001 010008 020002 0C00 0005 040000 00 000003FF 02000003"_hex} +
1024 * push(1) + OP_CALLF + bytecode{"0x0001"_hex} + 1020 * OP_POP + OP_RETURN +
OP_PUSH0 + OP_POP + OP_POP + OP_POP + OP_RETF;

EXPECT_EQ(validate_eof(code), EOFValidationError::stack_overflow);
}
}

TEST(eof_validation, incomplete_section_size)
{
EXPECT_EQ(
Expand Down
6 changes: 3 additions & 3 deletions test/unittests/evm_eof_function_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ TEST_P(evm, callf_stack_overflow)

rev = EVMC_PRAGUE;
const auto code =
bytecode{"ef0001 010008 020002 0BFF 0007 040000 00 000003FF 00000002"_hex} + // EOF header
1023 * push(1) + OP_CALLF + bytecode{"0x0001"_hex} + 1021 * OP_POP + OP_RETURN +
2 * push(1) + 2 * OP_POP + OP_RETF;
bytecode{"ef0001 01000c 020003 0BFF 0007 0004 040000 00 000003FF 00000001 00000001"_hex} +
1023 * push(1) + OP_CALLF + bytecode{"0x0001"_hex} + 1021 * OP_POP + OP_RETURN + push(1) +
OP_CALLF + bytecode{"0x0002"_hex} + OP_POP + OP_RETF + push(1) + OP_POP + OP_RETF;

ASSERT_EQ(evmone::validate_eof(rev, code), evmone::EOFValidationError::success);
execute(bytecode{code});
Expand Down

0 comments on commit ff73384

Please sign in to comment.