Skip to content
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[codegen]: fix assertions for certain precompiles #4451

Merged
merged 18 commits into from
Jan 20, 2025

Conversation

charles-cooper
Copy link
Member

@charles-cooper charles-cooper commented Jan 14, 2025

What I did

fix for GHSA-vgf2-gvx8-xwc3

How I did it

How to verify it

Commit message

this commit fixes a flaw in code generation for certain
precompiles. specifically, some calls to the ecrecover (0x01) and
identity (0x04) precompiles were not checked for success.

in 93a957947af1088addc, the assert for memory copying calls to the
identity precompile was optimized out; the reasoning being that if the
identity precompile fails due to OOG, the contract would also likely
fail with OOG. however, due to the 63/64ths rule, there are cases where
just enough gas was supplied to the current call context so that the
subcall to the precompile could fail with OOG, but the contract has
enough gas to continue execution after it shouldn't (which is undefined
behavior) and then successfully return out of the call context.

(note that even prior to 93a957947af1088addc, some calls to the
identity precompile did not check the success flag. cf. commit
cf03d27be6a74c0c33de. the call to ecrecover was unchecked since
inception - db44cde626919ed8bebf).

note also that since cancun, memory copies are implemented using
the `mcopy` instruction, so the bug as it pertains to the identity
precompile only affects pre-cancun compilation targets.

this commit fixes the flaw by converting the relevant unchecked calls
to checked calls.

it also adds tests that trigger the behavior by running the call, and
then performing the exact same call again but providing `gas_used` back
to the contract, which is the minimum amount of gas for the call to the
contract to finish execution. the specific amount of gas left at the
point of the subcall is small enough to cause the subcall to fail (and
the check around the subcall success to revert, which is what is tested
for in the new tests). in these tests, it also adds a static check
that the IR is well-formed (that all relevant calls to precompiles are
appropriately checked).

references:
- https://github.com/vyperlang/vyper/security/advisories/GHSA-vgf2-gvx8-xwc3

Description for the changelog

Cute Animal Picture

image

in 93a9579, the assert for memory copying calls to the
identity precompile was optimized out; the reasoning being that if the
identity precompile fails due to OOG, the caller contract would also
likely fail with OOG. however, due to the 63/64ths rule, there are cases
where the identity precompile could fail with OOG, but the caller
contract has enough gas to successfully return out of the call context.

(note that even prior to 93a9579, some calls to the identity
precompile did not check the success flag. cf. commit cf03d27).

this only affects pre-cancun compilation targets, since post-cancun the
`mcopy` instruction is chosen. this commit fixes the identity precompile
call for pre-cancun targets.

a similar optimization was also applied in the past to omit the check
when calling the ecrecover precompile. a check for the ecrecover call is
applied in this commit.

while this is a performance regression, ecrecover is generally not a
hotspot; as for the identity precompile, it is only used by the compiler
for memory copies pre-cancun, so the performance regression there is not
too relevant (as of nov 2024).
Copy link

codecov bot commented Jan 14, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.01%. Comparing base (d7f50df) to head (9355192).
Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4451   +/-   ##
=======================================
  Coverage   92.01%   92.01%           
=======================================
  Files         119      119           
  Lines       16692    16692           
  Branches     2805     2805           
=======================================
  Hits        15359    15359           
  Misses        915      915           
  Partials      418      418           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@cyberthirst cyberthirst added the release - must release blocker label Jan 15, 2025
@cyberthirst
Copy link
Collaborator

aren't the tests using cancun?

gas_used - 1 will always revert. we want to supply enough gas that the
inner call will return 0 but the outer call will not oog.
@charles-cooper charles-cooper marked this pull request as ready for review January 16, 2025 15:29
# check deploy IR (which contains runtime IR)
ir_node = CompilerData(source_code).ir_nodes

def _check(ir_node, parent=None):
Copy link
Collaborator

Choose a reason for hiding this comment

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

i think it would be better to assert that one of the nodes is staticcall and assert that it calls a precompile address

Copy link
Collaborator

Choose a reason for hiding this comment

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

and once we establish this is true, assert that the parent is assert

Copy link
Collaborator

Choose a reason for hiding this comment

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

hmm i guess this was motivated by making this general even for cancun. but still i'd change the code and handle this on callsite

@charles-cooper charles-cooper merged commit 7136eab into vyperlang:master Jan 20, 2025
165 checks passed
@charles-cooper charles-cooper deleted the fix/precompile-asserts branch January 20, 2025 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release - must release blocker
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants