Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Fixed potential modexp exp len overflow #6686

Merged
merged 1 commit into from
Oct 11, 2017
Merged

Fixed potential modexp exp len overflow #6686

merged 1 commit into from
Oct 11, 2017

Conversation

arkpar
Copy link
Collaborator

@arkpar arkpar commented Oct 10, 2017

No description provided.

@arkpar arkpar added A0-pleasereview 🤓 Pull request needs code review. M4-core ⛓ Core client code / Rust. labels Oct 10, 2017
@arkpar arkpar added F0-consensus 💣 Issue can lead to a consensus failure. B0-patch and removed F0-consensus 💣 Issue can lead to a consensus failure. labels Oct 10, 2017
@rphmeier
Copy link
Contributor

rphmeier commented Oct 10, 2017

wouldn't the right approach to simply use saturating_mul when calculating the cost using the adjusted_exp_len? the conditionals here using max_len seem tenuous and vulnerable to code shuffling breaking things easily.

Copy link
Collaborator

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wasm-tests submodule change is most likely not needed.

let mod_len = mod_len.low_u64();
let m = max(mod_len, base_len);
if m == 0 {
return U256::zero();
}
if exp_len > max_len {
Copy link
Collaborator

@tomusdrw tomusdrw Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditions look a bit messy now. What about this:

// max(mod_len, base_len) == 0
if mod_len.is_zero() && base_len.is_zero() {
  return U256::zero()
}

let max_len = U256::from(u32::max_value() / 2);
if base_len > max_len || mod_len > max_len || exp_len > max_len {
  return U256::max_value();
}

let (base_len, exp_len, mod_len) = (base_len.low_u64(), exp_len.low_u64(), mod_len.low_u64());
...

@arkpar
Copy link
Collaborator Author

arkpar commented Oct 10, 2017

@rphmeier u32::max_value() upper bound is used for other two params, so I'd use it for consistency and efficiency. I'll make pre-check more obvious as @tomusdrw suggests

@@ -133,8 +132,7 @@ impl ModexpPricer {
let bit_index = if exp_low.is_zero() { 0 } else { (255 - exp_low.leading_zeros()) as u64 };
if len <= 32 {
bit_index
}
else {
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Was hurting my eyes a bit :)

@5chdn 5chdn added this to the Patch milestone Oct 10, 2017
@5chdn 5chdn mentioned this pull request Oct 10, 2017
67 tasks
@rphmeier
Copy link
Contributor

rphmeier commented Oct 10, 2017

u32::max_value() upper bound is used for other two params

is that a hard bound specified by the EIP? otherwise, why introduce the arbitrary (and technically wrong) restriction, when really gas should be the only limiting factor? Doing computations on numbers a few gigabytes long is within reach of modern computers even if impractical

@arkpar
Copy link
Collaborator Author

arkpar commented Oct 10, 2017

This PR does not introduce any additional restrictions. Restriction for 32-bit addressable memory is already in the evm implementation. There are quite a few places where we choose more efficient gas calculation in plain integers. This is one of them. Changing that is out of scope of this PR

@@ -101,18 +101,17 @@ impl Pricer for ModexpPricer {
let exp_len = read_len();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't let me add comments on the actual line, but on line 92 above here: Why do we zero-extend the input and read_exact instead of just using read? The buffer's already filled with zeroes.

let m = max(mod_len, base_len);
if m == 0 {
return U256::zero();
}
// read fist 32-byte word of the exponent.
Copy link
Contributor

@eira-fransham eira-fransham Oct 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👊 fist 👊

@rphmeier rphmeier added A8-looksgood 🦄 Pull request is reviewed well. and removed A0-pleasereview 🤓 Pull request needs code review. labels Oct 11, 2017
@gavofyork gavofyork merged commit 7029dda into master Oct 11, 2017
@gavofyork gavofyork deleted the fix-overflow branch October 11, 2017 14:41
let max_len = U256::from(u32::max_value() / 2);
if base_len > max_len || mod_len > max_len {
if base_len > max_len || mod_len > max_len || exp_len > max_len {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this work properly with base = 1, mod = 1, exp = 2^256-1?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arkpar ^^^

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, according to the spec it should fail because gas calculation formula would return a huge value.

@5chdn 5chdn mentioned this pull request Oct 11, 2017
12 tasks
arkpar added a commit that referenced this pull request Oct 11, 2017
arkpar added a commit that referenced this pull request Oct 11, 2017
* v1.7.4

* Fixed potential exp len overflow (#6686)

* Fix warp sync blockers detection
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A8-looksgood 🦄 Pull request is reviewed well. F0-consensus 💣 Issue can lead to a consensus failure. M4-core ⛓ Core client code / Rust.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants