Skip to content

fix[codegen]: fix assertions for certain precompiles#4451

Merged
charles-cooper merged 18 commits intovyperlang:masterfrom
charles-cooper:fix/precompile-asserts
Jan 20, 2025
Merged

fix[codegen]: fix assertions for certain precompiles#4451
charles-cooper merged 18 commits intovyperlang:masterfrom
charles-cooper:fix/precompile-asserts

Conversation

@charles-cooper
Copy link
Copy Markdown
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).
@codecov
Copy link
Copy Markdown

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 75 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.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cyberthirst cyberthirst added the release - must release blocker label Jan 15, 2025
@cyberthirst
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
@charles-cooper charles-cooper deleted the fix/precompile-asserts branch January 20, 2025 16:51
lemenkov pushed a commit to fedora-ethereum/vyper that referenced this pull request Feb 27, 2025
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 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 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 93a9579, some calls to the
identity precompile did not check the success flag. cf. commit
cf03d27. the call to ecrecover was unchecked since
inception - db44cde).

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:
- GHSA-vgf2-gvx8-xwc3
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.

3 participants