From 58bfc9ba94e9a66b61f54a48d523bab5ae5593c5 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Mon, 4 Apr 2022 12:46:38 +0200 Subject: [PATCH] Validation of RJUMP* instructions --- lib/evmone/eof.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ lib/evmone/eof.hpp | 2 ++ 2 files changed, 46 insertions(+) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 5beeb05c3d..d52325901b 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace evmone { @@ -119,6 +120,41 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe return EOFValidationError::success; } +bool validate_rjump_destinations( + const EOF1Header& header, bytes_view::const_iterator container) noexcept +{ + // Collect relative jump destinations and immediate locations + std::vector rjumpdests; + std::vector immediate_map(header.code_end()); + for (auto i = header.code_begin(); i < header.code_end(); ++i) + { + const auto op = container[i]; + + if (op == OP_RJUMP || op == OP_RJUMPI) + { + const auto offset_hi = container[i + 1]; + const auto offset_lo = container[i + 2]; + const auto offset = static_cast((offset_hi << 8) + offset_lo); + const auto jumpdest = static_cast(i) + 3 + offset; + if (jumpdest < static_cast(header.code_begin()) || + jumpdest >= static_cast(header.code_end())) + return false; + rjumpdests.push_back(static_cast(jumpdest)); + } + + const auto imm_size = instr::traits[op].immediate_size; + std::fill_n(immediate_map.begin() + static_cast(i) + 1, imm_size, true); + i += imm_size; + } + + // Check relative jump destinations against immediate locations. + for (const auto rjumpdest : rjumpdests) + if (immediate_map[rjumpdest]) + return false; + + return true; +} + std::pair validate_eof1( evmc_revision rev, bytes_view container) noexcept { @@ -133,6 +169,9 @@ std::pair validate_eof1( if (error_instr != EOFValidationError::success) return {{}, error_instr}; + if (!validate_rjump_destinations(header, container.begin())) + return {{}, EOFValidationError::invalid_rjump_destination}; + return {header, EOFValidationError::success}; } @@ -148,6 +187,11 @@ size_t EOF1Header::code_begin() const noexcept return 10; // MAGIC + VERSION + SECTION_ID + SIZE + SECTION_ID + SIZE + TERMINATOR } +size_t EOF1Header::code_end() const noexcept +{ + return code_begin() + code_size; +} + bool is_eof_code(bytes_view code) noexcept { return code.size() > 1 && code[0] == MAGIC[0] && code[1] == MAGIC[1]; diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index ed9faef28c..58e9f4109e 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -20,6 +20,7 @@ struct EOF1Header /// Returns offset of code section start. [[nodiscard]] EVMC_EXPORT size_t code_begin() const noexcept; + [[nodiscard]] EVMC_EXPORT size_t code_end() const noexcept; }; /// Checks if code starts with EOF FORMAT + MAGIC, doesn't validate the format. @@ -48,6 +49,7 @@ enum class EOFValidationError invalid_section_bodies_size, undefined_instruction, missing_terminating_instruction, + invalid_rjump_destination, impossible, };