-
Notifications
You must be signed in to change notification settings - Fork 21
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
fix(levm): prevent unsafe arithmetic #1095
base: levm_fixes
Are you sure you want to change the base?
Conversation
.checked_add(WORD_SIZE) | ||
.ok_or(VMError::VeryLargeNumber)? | ||
.saturating_sub(1)) | ||
/ WORD_SIZE; |
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.
Shouldn't we use checked_div
here?
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.
checked_div
only checks if denominator is zero, and WORD_SIZE is a non-zero constant
let memory_byte_size = (args_offset | ||
.checked_add(args_size) | ||
.ok_or(VMError::VeryLargeNumber)?) | ||
.max( | ||
ret_offset | ||
.checked_add(ret_size) | ||
.ok_or(VMError::VeryLargeNumber)?, | ||
); |
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.
Nit. The parenthesis is not needed (do not commit this, it needs to be formatted).
let memory_byte_size = (args_offset | |
.checked_add(args_size) | |
.ok_or(VMError::VeryLargeNumber)?) | |
.max( | |
ret_offset | |
.checked_add(ret_size) | |
.ok_or(VMError::VeryLargeNumber)?, | |
); | |
let memory_byte_size = args_offset | |
.checked_add(args_size) | |
.ok_or(VMError::VeryLargeNumber)? | |
.max( | |
ret_offset | |
.checked_add(ret_size) | |
.ok_or(VMError::VeryLargeNumber)?, | |
); |
call_opcode::NON_ZERO_VALUE_COST + call_opcode::BASIC_FALLBACK_FUNCTION_STIPEND | ||
call_opcode::NON_ZERO_VALUE_COST | ||
.checked_add(call_opcode::BASIC_FALLBACK_FUNCTION_STIPEND) | ||
.ok_or(VMError::OverflowInArithmeticOp)? |
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.
What are the criteria for returning a VMError::OverflowInArithmeticOp
and VMError::InternalError
?
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.
The Internal's are those that should not happen in any case of execution, and the OverflowInArithmeticOp's are those that should not happen normally.
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.
Now I understand, should be an Internal because should not happen in any case
crates/vm/levm/src/vm.rs
Outdated
current_call_frame.gas_used = match current_call_frame | ||
.gas_used | ||
.checked_add(tx_report.gas_used.into()) | ||
{ | ||
Some(gas) => gas, | ||
None => { | ||
return Err(VMError::ConsumedGasOverflow); | ||
} | ||
}; |
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.
Nit. We could use .ok_or
here (it is manually implemented).
crates/vm/levm/src/vm.rs
Outdated
@@ -737,11 +813,23 @@ impl VM { | |||
current_call_frame: &mut CallFrame, | |||
gas: U256, | |||
) -> Result<(), VMError> { | |||
if current_call_frame.gas_used + gas > current_call_frame.gas_limit { | |||
let potential_consumed_gas = match current_call_frame.gas_used.checked_add(gas) { |
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.
Ditto.
crates/vm/levm/src/vm.rs
Outdated
self.env.consumed_gas += gas; | ||
|
||
current_call_frame.gas_used = potential_consumed_gas; | ||
self.env.consumed_gas = match self.env.consumed_gas.checked_add(gas) { |
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.
Ditto.
Motivation
The idea is to prevent arithmetic overflows and underflows in the levm code.
Description
Design desitions:
checked_add
and added aConsumedGasOverflow
error.checked_add
and theStackOverflow
errorVM::execute
method I decided to do not raise an error, because the previous behavior was to do not raise errors, so used the saturating functionsVMError::Internal
because the value was restricted on input an is never going to cause problemsGasCostOverflow
InvalidOpcode
errorCloses #1075