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

[Certora] Reentrancy specification. #325

Merged
merged 3 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/certora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ jobs:
- verifyBlue.sh
- verifyBlueRatioMathSummary.sh
- verifyBlueExitLiquidity.sh
- verifyReentrancy.sh
12 changes: 12 additions & 0 deletions certora/scripts/verifyReentrancy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

set -euxo pipefail

certoraRun \
certora/harness/MorphoHarness.sol \
--verify MorphoHarness:certora/specs/Reentrancy.spec \
--prover_args '-enableStorageSplitting false' \
--loop_iter 3 \
--optimistic_loop \
--msg "Check Reentrancy" \
"$@"
65 changes: 65 additions & 0 deletions certora/specs/Reentrancy.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
methods {
function _.borrowRate(MorphoHarness.Market market) external => summaryBorrowRate(market) expect uint256;
}

ghost bool hasAccessedStorage;
ghost bool hasCallAfterAccessingStorage;
ghost bool hasReentrancyUnsafeCall;
ghost bool delegate_call;
ghost bool static_call;
ghost bool callIsBorrowRate;

function summaryBorrowRate(MorphoHarness.Market market) returns uint256 {
uint256 result;
callIsBorrowRate = true;
return result;
}

hook ALL_SSTORE(uint loc, uint v) {
hasAccessedStorage = true;
hasReentrancyUnsafeCall = hasCallAfterAccessingStorage;
}

hook ALL_SLOAD(uint loc) uint v {
hasAccessedStorage = true;
hasReentrancyUnsafeCall = hasCallAfterAccessingStorage;
}

hook CALL(uint g, address addr, uint value, uint argsOffset, uint argsLength, uint retOffset, uint retLength) uint rc {
if (callIsBorrowRate) {
/* The calls to borrow rate are trusted and don't count */
callIsBorrowRate = false;
hasCallAfterAccessingStorage = hasCallAfterAccessingStorage;
} else {
hasCallAfterAccessingStorage = hasAccessedStorage;
}
}

hook DELEGATECALL(uint g, address addr, uint argsOffset, uint argsLength, uint retOffset, uint retLength) uint rc {
delegate_call = true;
}

hook STATICCALL(uint g, address addr, uint argsOffset, uint argsLength, uint retOffset, uint retLength) uint rc {
static_call = true;
}

rule reentrancySafe(method f, calldataarg data, env e) {
require !callIsBorrowRate;
require !hasAccessedStorage && !hasCallAfterAccessingStorage && !hasReentrancyUnsafeCall;
f(e,data);
assert !hasReentrancyUnsafeCall, "Method is not safe for reentrancy.";
}

rule noDelegateCalls(method f, calldataarg data, env e) {
require !delegate_call;
f(e,data);
assert !delegate_call;
}

/* This rule can be used to check which methods have static calls
rule hasStaticCalls(method f, calldataarg data, env e) {
require !static_call;
f(e,data);
satisfy static_call;
}
*/