From 2bde8bfbb6ae48218318573ccb98436918ee16d9 Mon Sep 17 00:00:00 2001 From: bt3gl <1130416+bt3gl@users.noreply.github.com> Date: Sat, 17 Sep 2022 17:55:39 -0700 Subject: [PATCH] Add a simple example for reentrancy and solutions with mutex or CEI --- Smart-Contract-Security/reentrancy-notes.md | 73 ++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/Smart-Contract-Security/reentrancy-notes.md b/Smart-Contract-Security/reentrancy-notes.md index 3f356e4..3200419 100644 --- a/Smart-Contract-Security/reentrancy-notes.md +++ b/Smart-Contract-Security/reentrancy-notes.md @@ -3,12 +3,83 @@
+### TL; DR + * When a contract calls an external function, that external function may itself call the calling function. +* A reentrancy attack may occur when a function makes an external call to another untrusted contract. Then, the unstrusted contract makes a recursive callback to the vulnerable contract function to steal funds. * To prevent this attack, a contract can implement a lock in storage that prevents re-entrant calls. +
-### References to learn about reentrancy +--- + +### Example of re-entrancy attack + +
+ +For example, suppose this method: + +``` +function withdrawBalance() public { + uint amountToWithdraw = userBalances[msg.sender]; + (bool success, ) = msg.sender.call.value(amountToWithdraw)(""); + requires(success); + userBalances[msg.sender] = 0; +} +``` + +and this exploit: + +``` +function() public payable { + if(msg.sender == address(vulnContract)) { + vulnContract.withdrawBalance(); + } +} +``` + +How to fix? + +#### Option 1: Adding a mutex locking: + +``` +modifier noReentrant() { + require(!locked, "nooooope"); + locked = true; + _; + locked = false; +} +``` + +so + +``` +function withdrawBalance() public noReentrant { + ... +} +``` + +
+ +#### Option 2: CEI (checks effects interaction) pattern + +``` +function withdrawBalance() public { + uint amountToWithdraw = userBalances[msg.sender]; + userBalances[msg.sender] = 0; // update state first + (bool success, ) = msg.sender.call.value(amountToWithdraw)(""); + requires(success); +} +``` + + +
+ +---- + + +### Resources