2

Hi was going through solidity documentation. There was some code that I was not able to understand, even after researching a lot I was not able to find some satisfactory output. The code is as under:

contract Mutex {
  bool locked;
modifier noReentrancy() {
    require(!locked);
    locked = true;
    _;
    locked = false;
}

/// This function is protected by a mutex, which means that
/// reentrant calls from within `msg.sender.call` cannot call `f` again.
/// The `return 7` statement assigns 7 to the return value but still
/// executes the statement `locked = false` in the modifier.
  function f() public noReentrancy returns (uint) {
    require(msg.sender.call());
   return 7;
  }
}

What msg.sender.call() does? is it calling f() again? If yes then how?

2

It calls the anonymous fallback function on msg.sender.

In a typical reentrancy attack, it would be something like a withdraw function doing msg.sender.call.value(1 ether)(). The caller (a smart contract), would then call the function again, hence the "reentrancy" attack. In this snippet, the call doesn't seem to be doing anything useful, but it's just there to show that the locked variables guards against reentrancy.

  • Comments are not for extended discussion; this conversation has been moved to chat. – eth Mar 13 '18 at 5:32
0

msg.sender.call() calls the on msg.sender.

Here is an example that is extended with a canBeAttacked function.

contract Mutex {
  bool locked;
modifier noReentrancy() {
    require(!locked);
    locked = true;
    _;
    locked = false;
}

  function canBeAttacked() public returns (uint) {
    require(msg.sender.call.value(1 ether)());
   return 7;
  }

/// This function is protected by a mutex
  function f() public noReentrancy returns (uint) {
    require(msg.sender.call());
   return 7;
  }
}

2 things to be aware of from above code.

  1. An attacker can create a contract that has a fallback

of:

// attacker fallback
function() {
  Mutex(msg.sender).canBeAttacked();
}

The contract can have another function that calls canBeAttacked(), and this will keep reentering canBeAttacked() and send the attacker 1 ether each time. (The fallback needs more code to avoid an infinite loop and running out of gas.) This is an example of a reentrant attack.

Now imagine an attacker contract that has a fallback of:

// attacker fallback
function() {
  Mutex(msg.sender).f();
}
  1. When attacker calls f(), the attacker fallback will fail because locked is true, so require(!locked) will generate an exception and revert the entire transaction.

Also note that noReentrancy prevents an attacker calling f() and in the attacker's fallback, calling canBeAttacked. (But they can attack as #1 above.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.