Secure Pattern: Contract wide re-entry protection with a mutex modifier.

o0ragman0oo0ragman0o Member, Moderator Posts: 1,291 mod
edited June 2016 in Solidity
Thanks to Philip Daian, et al, the analysis that followed the DAO hack turned up some pretty nasty anti-patterns classed as 're-entries'.

In short, a reentry is an external calling of a public function followed by a subsequent calling of a function in the same contract before the first function had finished execution. A recursive reentry is when ContractA.a() calls ContractB() which then calls ContractA.a() again and so on. If that's not bad enough, another anti-pattern that can trash a contract's state is when ContractA.a() calls ContractB.a() which then calls ContractA.b() and changes state without ContractA.a() being aware of the change.

To protect against this behaviour I offer the following mutual exclusion (mutex) pattern on the contracts as a whole.
contract MutexProtected
{
// Mutex contract on all state mutating external/public functions for protecting against
// Re-entry and `Solar Storm` attacks
modifier isMutexed() {
if(mutex) throw; // Exclusion already set so bail.
else mutex = true; // Set exclusion and continue with function code
_
delete mutex; // release contract from exclusion
return; // functions require single exit and return parameters
}
bool mutex; // the exclusion state variable
}
In the above, the MutexProtected contract has a bool mutex which is set upon entry into a modified function (see bellow). Any further attempts to enter that or any other public function will be thrown simply by having a contract inherit MutexProtected and applying the isMutexed() modifyier to public functions.

The only drawback is that an author must manage that mutex themselves if they want a public function to call another public function within their contract. However it is probably a more secure practice to simply limit the public API as best one can and rely on internals to do the bulk of the work.

Following is an example of a mutex protected contract:
contract Guff is MutexProtected
{
uint someGuff; // a state variable
function sendSomeGuff(uint guff)
isMutexed // the function modifier
returns (uint ret) // Requires return parameters
{
// This code cannot run if the mutex is true
someGuff += guff; // Mutate the state variable
msg.sender.send(guff); // Send some eth
ret = someGuff; // set the return parament
//note the missing return. It is in the modifier.
}
}
Other restrictions are that a function must have only a single exit and return parameters are to be used instead of single values.
Post edited by o0ragman0o on

Comments

  • HippoClipHippoClip Member Posts: 16
    I am surprised I have not seen this kind of construction in Ethereum sooner. After all, using a mutex to protect against these kinds of problems in distributed systems is a new idea.
Sign In or Register to comment.