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

Add CEI pattern static analysis #3168

Merged
merged 25 commits into from
Nov 10, 2022

Conversation

anton-trunov
Copy link
Contributor

@anton-trunov anton-trunov commented Oct 27, 2022

CEI stands for "Checks, Effects, Interactions". We check no storage reads/writes (effects) occur after calling external contracts (interaction). See this blog post and this blogpost for more detail.

TODOs:

  • analyze libraries, scripts, and predicates (only contracts are analyzed at the moment)
  • process assembly blocks
  • what is the effects of the __revert intrinsic
  • Treat nested code blocks
  • more tests
    • Tests using storage.var = ...
    • Tests using asm blocks directly
    • Tests using complex control flow
    • Tests having multiple contract calls or multiple storage writes in various scenarios
    • Tests with nested code blocks (there is a very simple test, this needs more testing in a separate PR)
  • check for storage reads after interaction
    • Storage read intrinsics
    • StorageAccess expressions
    • asm blocks using srw or srwq
    • asm blocks using bal because bal actually reads from storage
  • CLI option or attribute to control the warnings (an internal discussion showed that we cannot do this at the moment, I guess this should be handled as a separate issue)
  • open an issue about unification of the currently existing storage annotation checks and effects inference in this PR

close #10

CEI stands for "Checks, Effects, Interactions".  We check no storage writes (effects)
occur after calling external contracts (interaction).
See this [blog post](https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html)
for more detail.
@anton-trunov anton-trunov self-assigned this Oct 27, 2022
@anton-trunov anton-trunov added the compiler: ui Mostly compiler messages label Oct 27, 2022
@anton-trunov anton-trunov requested a review from a team October 27, 2022 12:32
@anton-trunov
Copy link
Contributor Author

An example of a warning issued by the CEI analyzer:

warning
  --> /Users/anton/fuel.network/sway/reentrancy/src/main.sw:29:5
   |
27 |
28 |       // interaction
29 |       other_contract.deposit(gas, amount, color, unused);
   |  _____-
30 | |     // effect -- therefore violation of CEI where effect should go before interaction
31 | |     let storage_key = 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae;
32 | |     store(storage_key, ());
   | |__________________________- Storage modification after external contract interaction. Consider making all storage writes before calling another contract
33 |     }
34 |   }
   |
____

Copy link
Contributor

@mohammadfawaz mohammadfawaz left a comment

Choose a reason for hiding this comment

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

Some initial thoughts! But this looks excellent! Thank you so much 🚀

sway-core/src/semantic_analysis/cei_pattern_analysis.rs Outdated Show resolved Hide resolved
sway-core/src/semantic_analysis/cei_pattern_analysis.rs Outdated Show resolved Hide resolved
use sway_ast::Intrinsic::*;
match intr {
StateStoreWord | StateStoreQuad => HashSet::from([Effect::StorageWrite]),
// TODO: figure out the effect of __revert
Copy link
Contributor

Choose a reason for hiding this comment

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

I think a revert (or a return) between a contract call and a storage write should not result in a reentrancy warning. That being said, we should probably be warning on dead code in that case anyways?

sway-core/src/semantic_analysis/cei_pattern_analysis.rs Outdated Show resolved Hide resolved
sway-core/src/semantic_analysis/cei_pattern_analysis.rs Outdated Show resolved Hide resolved
@mohammadfawaz mohammadfawaz added enhancement New feature or request compiler: frontend Everything to do with type checking, control flow analysis, and everything between parsing and IRgen labels Oct 27, 2022
@anton-trunov anton-trunov marked this pull request as ready for review October 30, 2022 20:40
@anton-trunov anton-trunov requested a review from a team October 30, 2022 20:40
@mohammadfawaz
Copy link
Contributor

mohammadfawaz commented Oct 31, 2022

I'm very happy with the overall change, thanks!

My only nitpick is that the auction test is too large and complex to belong in the E2E test repo. Basically, the test is hard to understand and it is unclear where the violation is. I suggest we go with a much smaller example that showcases the same violation.

@anton-trunov
Copy link
Contributor Author

Just realized I need to treat nested code blocks. The fix is on the way

@anton-trunov anton-trunov marked this pull request as ready for review November 9, 2022 15:15
@anton-trunov
Copy link
Contributor Author

@mohammadfawaz Pushed an updated, deeper, version of the analysis, please have a look. It still needs a bit more testing, but it already reproduces all the existing tests and I added a very simple test with a nested code block which was not processed previously.

mohammadfawaz
mohammadfawaz previously approved these changes Nov 9, 2022
Copy link
Contributor

@mohammadfawaz mohammadfawaz left a comment

Choose a reason for hiding this comment

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

Generally this looks very reasonable. I'd certainly like to see more testing. At the very least, it would be nice to have full code coverage for cei_pattern_analysis.rs, but that can be done in a separate PR.

Comment on lines 370 to 371
// TODO: jumps are not processed at the moment, so the CEI analysis will work only
// for simple linear assembly blocks, which arguably is the most important use case so far
Copy link
Contributor

Choose a reason for hiding this comment

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

Jump are not and will porbably never be allowed in asm blocks, so you're good!

Suggested change
// TODO: jumps are not processed at the moment, so the CEI analysis will work only
// for simple linear assembly blocks, which arguably is the most important use case so far
No need to worry about jumps because they are not allowed in `asm` blocks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is really good to know! I applied the change in a separate commit (added //)

@anton-trunov anton-trunov requested a review from a team November 9, 2022 16:32
Copy link
Contributor

@otrho otrho left a comment

Choose a reason for hiding this comment

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

Would it be possible to add a test which uses effects (ref mut args?) to confirm the left-to-right evaluation of function args and struct initialisers?

Copy link
Contributor

@sezna sezna left a comment

Choose a reason for hiding this comment

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

Looks great! The only thing I wonder is if someday down the line we can merge this and other AST-traversing checks we do into one traversal. But the traversals themselves are slightly different so it may not be generalizable (thinking of purity checking mainly).

@sezna
Copy link
Contributor

sezna commented Nov 10, 2022

Would it be possible to add a test which uses effects (ref mut args?) to confirm the left-to-right evaluation of function args and struct initialisers?

I'd be okay with that as a follow-up PR since this one has the approvals needed. Your call @anton-trunov

@mohammadfawaz
Copy link
Contributor

mohammadfawaz commented Nov 10, 2022

Looks great! The only thing I wonder is if someday down the line we can merge this and other AST-traversing checks we do into one traversal. But the traversals themselves are slightly different so it may not be generalizable (thinking of purity checking mainly).

Actually @anton-trunov mentioned this to me recently when we were chatting. He thinks he has ideas on how to merge purity checking into this as he's already collecting storage access here anyways.

@mohammadfawaz
Copy link
Contributor

@anton-trunov I've opened #3342 and assigned it to you so we can follow up with additional testing.

@mohammadfawaz mohammadfawaz merged commit 57b6d08 into master Nov 10, 2022
@mohammadfawaz mohammadfawaz deleted the anton-trunov/cei-pattern-violation branch November 10, 2022 17:40
@anton-trunov
Copy link
Contributor Author

Awesome! Thanks everyone!

@anton-trunov
Copy link
Contributor Author

@otrho Great suggestion to test left-to-right evaluation on which the CEI analysis relies! In PR #3356, I added a compiler test for that: 332a240

anton-trunov added a commit that referenced this pull request Nov 16, 2022
## Test cases

- [x] `if` with interaction in the condition and storage in a branch
- [x] `match` with interaction in the condition and storage in branches
- [x] Pair or struct with interaction in one component and storage in a
subsequent component


### `while`-loops tests

- [x] `while` loop with effects in the condition or the body
- [x] `while` loop with interaction-then-storage
- [x] `while` loop with storage-then-interaction (this is a violation
too because on the next loop iteration it will be
interaction-then-storage) -- this requires a fix implemented in this PR

### Function application tests

- [x] Pure function + argument is a code block with CEI violation
- [x] Pure function + first argument does interaction + second argument
does storage effect
- [x] Storage reading/writing function + argument does interaction
- [x] Improved error reporting precision for function application
- [x] Left-to-right arguments evaluation

Closes #3342
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler: frontend Everything to do with type checking, control flow analysis, and everything between parsing and IRgen compiler: static-analysis compiler: ui Mostly compiler messages enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Detect and handle re-entrancy patterns
4 participants