|
16 | 16 | #include <numeric>
|
17 | 17 | #include <queue>
|
18 | 18 | #include <unordered_set>
|
| 19 | +#include <variant> |
19 | 20 | #include <vector>
|
20 | 21 |
|
21 | 22 | namespace evmone
|
@@ -225,14 +226,84 @@ std::variant<EOFSectionHeaders, EOFValidationError> validate_section_headers(byt
|
225 | 226 | std::accumulate(section_headers.container_sizes.begin(),
|
226 | 227 | section_headers.container_sizes.end(), uint64_t{0});
|
227 | 228 | const auto remaining_container_size = static_cast<uint64_t>(container_end - it);
|
228 |
| - // Only data section may be truncated, so remaining_container size must be at least |
229 |
| - // declared_size_without_data |
| 229 | + // Only data section may be truncated, so remaining_container size must be in |
| 230 | + // [declared_size_without_data, declared_size_without_data + declared_data_size] |
230 | 231 | if (remaining_container_size < section_bodies_without_data)
|
231 | 232 | return EOFValidationError::invalid_section_bodies_size;
|
| 233 | + if (remaining_container_size > section_bodies_without_data + section_headers.data_size) |
| 234 | + return EOFValidationError::invalid_section_bodies_size; |
232 | 235 |
|
233 | 236 | return section_headers;
|
234 | 237 | }
|
235 | 238 |
|
| 239 | +std::variant<EOF1Header, EOFValidationError> validate_header( |
| 240 | + evmc_revision rev, bytes_view container) noexcept |
| 241 | +{ |
| 242 | + if (!is_eof_container(container)) |
| 243 | + return EOFValidationError::invalid_prefix; |
| 244 | + |
| 245 | + const auto version = get_eof_version(container); |
| 246 | + if (version != 1) |
| 247 | + return EOFValidationError::eof_version_unknown; |
| 248 | + |
| 249 | + if (rev < EVMC_OSAKA) |
| 250 | + return EOFValidationError::eof_version_unknown; |
| 251 | + |
| 252 | + // `offset` variable handled below is known to not be greater than the container size, as |
| 253 | + // checked in `validate_section_headers`. Combined with the requirement for the container |
| 254 | + // size to not exceed MAX_INITCODE_SIZE (checked before `validate-header` is called), |
| 255 | + // this allows us to cast `offset` to narrower integers. |
| 256 | + assert(container.size() <= MAX_INITCODE_SIZE); |
| 257 | + |
| 258 | + auto section_headers_or_error = validate_section_headers(container); |
| 259 | + if (const auto* error = std::get_if<EOFValidationError>(§ion_headers_or_error)) |
| 260 | + return *error; |
| 261 | + |
| 262 | + auto& section_headers = std::get<EOFSectionHeaders>(section_headers_or_error); |
| 263 | + |
| 264 | + const auto header_size = eof_header_size(section_headers); |
| 265 | + |
| 266 | + const auto type_section_offset = header_size; |
| 267 | + |
| 268 | + if (section_headers.type_size != |
| 269 | + section_headers.code_sizes.size() * EOF1Header::TYPE_ENTRY_SIZE) |
| 270 | + return EOFValidationError::invalid_type_section_size; |
| 271 | + |
| 272 | + auto offset = header_size + section_headers.type_size; |
| 273 | + |
| 274 | + std::vector<uint16_t> code_offsets; |
| 275 | + code_offsets.reserve(section_headers.code_sizes.size()); |
| 276 | + for (const auto code_size : section_headers.code_sizes) |
| 277 | + { |
| 278 | + assert(offset <= std::numeric_limits<uint16_t>::max()); |
| 279 | + code_offsets.emplace_back(static_cast<uint16_t>(offset)); |
| 280 | + offset += code_size; |
| 281 | + } |
| 282 | + |
| 283 | + std::vector<uint32_t> container_offsets; |
| 284 | + container_offsets.reserve(section_headers.container_sizes.size()); |
| 285 | + for (const auto container_size : section_headers.container_sizes) |
| 286 | + { |
| 287 | + assert(offset <= std::numeric_limits<uint32_t>::max()); |
| 288 | + container_offsets.emplace_back(static_cast<uint32_t>(offset)); |
| 289 | + offset += container_size; |
| 290 | + } |
| 291 | + |
| 292 | + assert(offset <= std::numeric_limits<uint32_t>::max()); |
| 293 | + const auto data_offset = static_cast<uint32_t>(offset); |
| 294 | + |
| 295 | + return EOF1Header{ |
| 296 | + .version = container[2], |
| 297 | + .type_section_offset = type_section_offset, |
| 298 | + .code_sizes = std::move(section_headers.code_sizes), |
| 299 | + .code_offsets = std::move(code_offsets), |
| 300 | + .data_size = section_headers.data_size, |
| 301 | + .data_offset = data_offset, |
| 302 | + .container_sizes = std::move(section_headers.container_sizes), |
| 303 | + .container_offsets = std::move(container_offsets), |
| 304 | + }; |
| 305 | +} |
| 306 | + |
236 | 307 | EOFValidationError validate_types(bytes_view container, const EOF1Header& header) noexcept
|
237 | 308 | {
|
238 | 309 | for (size_t i = 0; i < header.get_type_count(); ++i)
|
@@ -634,9 +705,6 @@ EOFValidationError validate_eof1(
|
634 | 705 |
|
635 | 706 | auto& header = std::get<EOF1Header>(error_or_header);
|
636 | 707 |
|
637 |
| - if (container.size() > static_cast<size_t>(header.data_offset) + header.data_size) |
638 |
| - return EOFValidationError::invalid_section_bodies_size; |
639 |
| - |
640 | 708 | if (const auto err = validate_types(container, header); err != EOFValidationError::success)
|
641 | 709 | return err;
|
642 | 710 |
|
@@ -756,74 +824,6 @@ bool is_eof_container(bytes_view container) noexcept
|
756 | 824 | return container.starts_with(EOF_MAGIC);
|
757 | 825 | }
|
758 | 826 |
|
759 |
| -std::variant<EOF1Header, EOFValidationError> validate_header( |
760 |
| - evmc_revision rev, bytes_view container) noexcept |
761 |
| -{ |
762 |
| - if (!is_eof_container(container)) |
763 |
| - return EOFValidationError::invalid_prefix; |
764 |
| - |
765 |
| - const auto version = get_eof_version(container); |
766 |
| - if (version != 1) |
767 |
| - return EOFValidationError::eof_version_unknown; |
768 |
| - |
769 |
| - if (rev < EVMC_OSAKA) |
770 |
| - return EOFValidationError::eof_version_unknown; |
771 |
| - |
772 |
| - // `offset` variable handled below is known to not be greater than the container size, as |
773 |
| - // checked in `validate_section_headers`. Combined with the requirement for the container |
774 |
| - // size to not exceed MAX_INITCODE_SIZE (checked before `validate-header` is called), |
775 |
| - // this allows us to cast `offset` to narrower integers. |
776 |
| - assert(container.size() <= MAX_INITCODE_SIZE); |
777 |
| - |
778 |
| - auto section_headers_or_error = validate_section_headers(container); |
779 |
| - if (const auto* error = std::get_if<EOFValidationError>(§ion_headers_or_error)) |
780 |
| - return *error; |
781 |
| - |
782 |
| - auto& section_headers = std::get<EOFSectionHeaders>(section_headers_or_error); |
783 |
| - |
784 |
| - const auto header_size = eof_header_size(section_headers); |
785 |
| - |
786 |
| - const auto type_section_offset = header_size; |
787 |
| - |
788 |
| - if (section_headers.type_size != |
789 |
| - section_headers.code_sizes.size() * EOF1Header::TYPE_ENTRY_SIZE) |
790 |
| - return EOFValidationError::invalid_type_section_size; |
791 |
| - |
792 |
| - auto offset = header_size + section_headers.type_size; |
793 |
| - |
794 |
| - std::vector<uint16_t> code_offsets; |
795 |
| - code_offsets.reserve(section_headers.code_sizes.size()); |
796 |
| - for (const auto code_size : section_headers.code_sizes) |
797 |
| - { |
798 |
| - assert(offset <= std::numeric_limits<uint16_t>::max()); |
799 |
| - code_offsets.emplace_back(static_cast<uint16_t>(offset)); |
800 |
| - offset += code_size; |
801 |
| - } |
802 |
| - |
803 |
| - std::vector<uint32_t> container_offsets; |
804 |
| - container_offsets.reserve(section_headers.container_sizes.size()); |
805 |
| - for (const auto container_size : section_headers.container_sizes) |
806 |
| - { |
807 |
| - assert(offset <= std::numeric_limits<uint32_t>::max()); |
808 |
| - container_offsets.emplace_back(static_cast<uint32_t>(offset)); |
809 |
| - offset += container_size; |
810 |
| - } |
811 |
| - |
812 |
| - assert(offset <= std::numeric_limits<uint32_t>::max()); |
813 |
| - const auto data_offset = static_cast<uint32_t>(offset); |
814 |
| - |
815 |
| - return EOF1Header{ |
816 |
| - .version = container[2], |
817 |
| - .type_section_offset = type_section_offset, |
818 |
| - .code_sizes = std::move(section_headers.code_sizes), |
819 |
| - .code_offsets = std::move(code_offsets), |
820 |
| - .data_size = section_headers.data_size, |
821 |
| - .data_offset = data_offset, |
822 |
| - .container_sizes = std::move(section_headers.container_sizes), |
823 |
| - .container_offsets = std::move(container_offsets), |
824 |
| - }; |
825 |
| -} |
826 |
| - |
827 | 827 | /// This function expects the prefix and version to be valid, as it ignores it.
|
828 | 828 | EOF1Header read_valid_eof1_header(bytes_view container)
|
829 | 829 | {
|
|
0 commit comments