Please note, this content is no longer actively maintained.
The content of the SWC registry has not been thoroughly updated since 2020. It is known to be incomplete and may contain errors as well as crucial omissions.
For currently maintained guidance on known Smart Contract vulnerabilities written primarily as guidance for security reviewers, please see the EEA EthTrust Security Levels specification. As well as the latest release version, an Editor's draft is available, that represents the latest work of the group developing the specification.
General guidance for developers on what to consider to ensure security, that is currently maintained, is also available through the Smart Contract Security Verification Standard (SCSVS).
Title
Arbitrary Jump with Function Type Variable
Relationships
- CWE-695: Use of Low-Level Functionality
- EEA EthTrust Security Levels:
- [S] No
assembly {}
- [M] Avoid Common
assembly {}
Attack Vectors
Description
Solidity supports function types. That is, a variable of function type can be assigned with a reference to a function with a matching signature. The function saved to such variable can be called just like a regular function.
The problem arises when a user has the ability to arbitrarily change the function type variable and thus execute random code instructions. As Solidity doesn't support pointer arithmetics, it's impossible to change such variable to an arbitrary value. However, if the developer uses assembly instructions, such as mstore
or assign operator, in the worst case scenario an attacker is able to point a function type variable to any code instruction, violating required validations and required state changes.
Remediation
The use of assembly should be minimal. A developer should not allow a user to assign arbitrary values to function type variables.
References
Samples
FunctionTypes.sol
/*
* @source: https://gist.github.com/wadeAlexC/7a18de852693b3f890560ab6a211a2b8
* @author: Alexander Wade
*/
pragma solidity ^0.4.25;
contract FunctionTypes {
constructor() public payable { require(msg.value != 0); }
function withdraw() private {
require(msg.value == 0, 'dont send funds!');
address(msg.sender).transfer(address(this).balance);
}
function frwd() internal
{ withdraw(); }
struct Func { function () internal f; }
function breakIt() public payable {
require(msg.value != 0, 'send funds!');
Func memory func;
func.f = frwd;
assembly { mstore(func, add(mload(func), callvalue)) }
func.f();
}
}