-
Notifications
You must be signed in to change notification settings - Fork 294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EOF: limit validated container size to MAX_INITCODE_SIZE #930
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,9 @@ | |
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 | ||
|
@@ -592,6 +595,10 @@ | |
bytes_view bytes; | ||
ContainerKind kind; | ||
}; | ||
|
||
if (main_container.size() > MAX_INITCODE_SIZE) | ||
return EOFValidationError::container_size_above_limit; | ||
|
||
// Queue of containers left to process | ||
std::queue<ContainerValidation> container_queue; | ||
|
||
|
@@ -738,6 +745,12 @@ | |
if (rev < EVMC_PRAGUE) | ||
return EOFValidationError::eof_version_unknown; | ||
|
||
// `offset` variable handled below is known to not be greater than the container size, as | ||
// checked in `validate_section_headers`. Combined with the requirement for the container | ||
// size to not exceed MAX_INITCODE_SIZE (checked before `validate-header` is called), | ||
// this allows us to cast `offset` to narrower integers. | ||
assert(container.size() <= MAX_INITCODE_SIZE); | ||
|
||
const auto section_headers_or_error = validate_section_headers(container); | ||
if (const auto* error = std::get_if<EOFValidationError>(§ion_headers_or_error)) | ||
return *error; | ||
|
@@ -757,6 +770,7 @@ | |
std::vector<uint16_t> code_offsets; | ||
const auto type_section_size = section_headers[TYPE_SECTION][0]; | ||
auto offset = header_size + type_section_size; | ||
|
||
for (const auto code_size : code_sizes) | ||
{ | ||
assert(offset <= std::numeric_limits<uint16_t>::max()); | ||
|
@@ -768,10 +782,11 @@ | |
std::vector<uint16_t> container_offsets; | ||
for (const auto container_size : container_sizes) | ||
{ | ||
assert(offset <= std::numeric_limits<uint16_t>::max()); | ||
container_offsets.emplace_back(static_cast<uint16_t>(offset)); | ||
offset += container_size; | ||
} | ||
// NOTE: assertion always satisfied only as long as initcode limits apply (48K). | ||
|
||
assert(offset <= std::numeric_limits<uint16_t>::max()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should keep the assert. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks still removed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean I would still keep it even if it's checked in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah it moved up a bit and changed form, but the outcome is still the same (I think, please double check if in doubt) - the cast is safe. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Also currently it's incosistent, you removed this assertion, but kept another one at line 776. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
ouch, right, completely missed that. OK on keeping the assertion, but I guess just one assertion at the end (the removed one) will be enough? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. like 537d394 for example There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would keep the one in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay, then let's keep all, one for each cast to uint16 (one was missing originally) |
||
const auto data_offset = static_cast<uint16_t>(offset); | ||
|
||
|
@@ -971,6 +986,8 @@ | |
return "ambiguous_container_kind"; | ||
case EOFValidationError::incompatible_container_kind: | ||
return "incompatible_container_kind"; | ||
case EOFValidationError::container_size_above_limit: | ||
return "container_size_above_limit"; | ||
case EOFValidationError::impossible: | ||
return "impossible"; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An interesting case come up, concerning this piece: Should this check be done here (top-level
validate_eof
) or invalidate_header
.An expectation would be to have the logic of
validate_header
protected against oversized containers. It has been since creation txs moved to the public API of eof.hpp, so, in principle, it should also contain the check as one of the first.OTOH, this would be wasteful, as we'd be repeating the check for all subcontainers, which are always smaller than top-level. Also
validate_header
bare is only ever called inhost.cpp
during the process of validating a creation tx data (to be precise - to discover the split between container and calldata) - but there it is protected by the transaction-level MAX_INITCODE_SIZE check.Let me know if you have any thoughts on this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it mean the
validate_header
doesn't work correctly on its own?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only guaranteed for containers which have its size under the limit. In other words - checking size is outside of
validate_header
's responsibility.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is now the
validate_header()
precondition then add an assert in thevalidate_header()
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I reworked the comment and assertion in
validate_header
. I think this is good now, thx!