Skip to content

Commit

Permalink
EOF: limit validated container size to MAX_INITCODE_SIZE
Browse files Browse the repository at this point in the history
  • Loading branch information
pdobacz committed Jun 17, 2024
1 parent 209aee1 commit 28f5f83
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 3 deletions.
24 changes: 22 additions & 2 deletions lib/evmone/eof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ constexpr auto REL_OFFSET_SIZE = sizeof(int16_t);
constexpr auto STACK_SIZE_LIMIT = 1024;
constexpr uint8_t NON_RETURNING_FUNCTION = 0x80;

constexpr size_t MAX_CODE_SIZE = 0x6000;
constexpr size_t MAX_INITCODE_SIZE = 2 * MAX_CODE_SIZE;

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

size_t eof_header_size(const EOFSectionHeaders& headers) noexcept
Expand Down Expand Up @@ -579,6 +582,10 @@ EOFValidationError validate_eof1(evmc_revision rev, bytes_view main_container) n
bytes_view bytes;
bool referenced_by_eofcreate = false;
};

if (main_container.size() > MAX_INITCODE_SIZE)
return EOFValidationError::container_size_above_limit;

Check warning on line 587 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L587

Added line #L587 was not covered by tests

// Queue of containers left to process
std::queue<ContainerValidation> container_queue;
container_queue.push({main_container, false});
Expand Down Expand Up @@ -726,11 +733,20 @@ std::variant<EOF1Header, EOFValidationError> validate_header(
std::vector<uint16_t> code_offsets;
const auto type_section_size = section_headers[TYPE_SECTION][0];
auto offset = header_size + type_section_size;

// `offset` is being checked to not overflow the container size. Combined with the
// requirement for the container size to not exceed MAX_INITCODE_SIZE, this allows
// us to cast to a narrower integer.
if (offset > container.size())
return EOFValidationError::invalid_section_bodies_size;

Check warning on line 741 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L741

Added line #L741 was not covered by tests

for (const auto code_size : code_sizes)
{
assert(offset <= std::numeric_limits<uint16_t>::max());
code_offsets.emplace_back(static_cast<uint16_t>(offset));
offset += code_size;
if (offset > container.size())
return EOFValidationError::invalid_section_bodies_size;

Check warning on line 749 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L749

Added line #L749 was not covered by tests
}

const auto& container_sizes = section_headers[CONTAINER_SECTION];
Expand All @@ -739,9 +755,11 @@ std::variant<EOF1Header, EOFValidationError> validate_header(
{
container_offsets.emplace_back(static_cast<uint16_t>(offset));
offset += container_size;

if (offset > container.size())
return EOFValidationError::invalid_section_bodies_size;

Check warning on line 760 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L760

Added line #L760 was not covered by tests
}
// NOTE: assertion always satisfied only as long as initcode limits apply (48K).
assert(offset <= std::numeric_limits<uint16_t>::max());

const auto data_offset = static_cast<uint16_t>(offset);

return EOF1Header{
Expand Down Expand Up @@ -935,6 +953,8 @@ std::string_view get_error_message(EOFValidationError err) noexcept
return "eofcreate_with_truncated_container";
case EOFValidationError::toplevel_container_truncated:
return "toplevel_container_truncated";
case EOFValidationError::container_size_above_limit:
return "container_size_above_limit";

Check warning on line 957 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L956-L957

Added lines #L956 - L957 were not covered by tests
case EOFValidationError::impossible:
return "impossible";
}
Expand Down
1 change: 1 addition & 0 deletions lib/evmone/eof.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ enum class EOFValidationError
invalid_container_section_index,
eofcreate_with_truncated_container,
toplevel_container_truncated,
container_size_above_limit,

impossible,
};
Expand Down
2 changes: 2 additions & 0 deletions test/unittests/eof_validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ std::string_view get_tests_error_message(EOFValidationError err) noexcept
return "EOF_EofCreateWithTruncatedContainer";
case EOFValidationError::toplevel_container_truncated:
return "EOF_ToplevelContainerTruncated";
case EOFValidationError::container_size_above_limit:
return "EOF_ContainerSizeAboveLimit";

Check warning on line 93 in test/unittests/eof_validation.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/eof_validation.cpp#L92-L93

Added lines #L92 - L93 were not covered by tests
case EOFValidationError::impossible:
return "impossible";
}
Expand Down
4 changes: 3 additions & 1 deletion test/unittests/eof_validation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1228,9 +1228,11 @@ TEST_F(eof_validation, EOF1_subcontainer_containing_unreachable_code_sections)

TEST_F(eof_validation, max_nested_containers)
{
constexpr size_t MAX_CODE_SIZE = 0x6000;
constexpr size_t MAX_INITCODE_SIZE = 2 * MAX_CODE_SIZE;
bytecode code{};
bytecode nextcode = eof_bytecode(OP_INVALID);
while (nextcode.size() <= std::numeric_limits<uint16_t>::max())
while (nextcode.size() <= MAX_INITCODE_SIZE)
{
code = nextcode;
nextcode = eof_bytecode(OP_INVALID).container(nextcode);
Expand Down

0 comments on commit 28f5f83

Please sign in to comment.