What is the purpose in asserting 'msg.data.length == 64 + 4'?
up vote
4
down vote
favorite
In a contract used for testing Gnosis MultiSigWallet, I found this piece of code:
/*
* This modifier is present in some real world token contracts, and due to a solidity
* bug it was not compatible with multisig wallets
*/
modifier onlyPayloadSize(uint size) {
require(msg.data.length == size + 4);
_;
}
/// @dev Transfers sender's tokens to a given address. Returns success.
/// @param _to Address of token receiver.
/// @param _value Number of tokens to transfer.
/// @return Returns success of function call.
function transfer(address _to, uint256 _value) onlyPayloadSize(2 * 32)
public
returns (bool success)
{
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
}
The documentation of the onlyPayloadSize
modifier is extremely unclear to me.
Can somebody please explain the following:
- What exactly is the purpose of this modifier?
- Why is it used only in the
trasnsfer
function? - Why is it used with a specific size of 64 (
2 * 32
)? - Why is this modifier present only in a test contract, and not in the actual
MultiSigWallet
contract? Does this by any chance imply that I should add this modifier in every contract in my system, designated for access only via an instance of theMultiSigWallet
contract? If I don't have any such contract with a standardtransfer
method (i.e., an ERC20 contract), can I rest assure that I don't need this modifier anywhere else in my system?
Thank you!
solidity
add a comment |
up vote
4
down vote
favorite
In a contract used for testing Gnosis MultiSigWallet, I found this piece of code:
/*
* This modifier is present in some real world token contracts, and due to a solidity
* bug it was not compatible with multisig wallets
*/
modifier onlyPayloadSize(uint size) {
require(msg.data.length == size + 4);
_;
}
/// @dev Transfers sender's tokens to a given address. Returns success.
/// @param _to Address of token receiver.
/// @param _value Number of tokens to transfer.
/// @return Returns success of function call.
function transfer(address _to, uint256 _value) onlyPayloadSize(2 * 32)
public
returns (bool success)
{
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
}
The documentation of the onlyPayloadSize
modifier is extremely unclear to me.
Can somebody please explain the following:
- What exactly is the purpose of this modifier?
- Why is it used only in the
trasnsfer
function? - Why is it used with a specific size of 64 (
2 * 32
)? - Why is this modifier present only in a test contract, and not in the actual
MultiSigWallet
contract? Does this by any chance imply that I should add this modifier in every contract in my system, designated for access only via an instance of theMultiSigWallet
contract? If I don't have any such contract with a standardtransfer
method (i.e., an ERC20 contract), can I rest assure that I don't need this modifier anywhere else in my system?
Thank you!
solidity
add a comment |
up vote
4
down vote
favorite
up vote
4
down vote
favorite
In a contract used for testing Gnosis MultiSigWallet, I found this piece of code:
/*
* This modifier is present in some real world token contracts, and due to a solidity
* bug it was not compatible with multisig wallets
*/
modifier onlyPayloadSize(uint size) {
require(msg.data.length == size + 4);
_;
}
/// @dev Transfers sender's tokens to a given address. Returns success.
/// @param _to Address of token receiver.
/// @param _value Number of tokens to transfer.
/// @return Returns success of function call.
function transfer(address _to, uint256 _value) onlyPayloadSize(2 * 32)
public
returns (bool success)
{
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
}
The documentation of the onlyPayloadSize
modifier is extremely unclear to me.
Can somebody please explain the following:
- What exactly is the purpose of this modifier?
- Why is it used only in the
trasnsfer
function? - Why is it used with a specific size of 64 (
2 * 32
)? - Why is this modifier present only in a test contract, and not in the actual
MultiSigWallet
contract? Does this by any chance imply that I should add this modifier in every contract in my system, designated for access only via an instance of theMultiSigWallet
contract? If I don't have any such contract with a standardtransfer
method (i.e., an ERC20 contract), can I rest assure that I don't need this modifier anywhere else in my system?
Thank you!
solidity
In a contract used for testing Gnosis MultiSigWallet, I found this piece of code:
/*
* This modifier is present in some real world token contracts, and due to a solidity
* bug it was not compatible with multisig wallets
*/
modifier onlyPayloadSize(uint size) {
require(msg.data.length == size + 4);
_;
}
/// @dev Transfers sender's tokens to a given address. Returns success.
/// @param _to Address of token receiver.
/// @param _value Number of tokens to transfer.
/// @return Returns success of function call.
function transfer(address _to, uint256 _value) onlyPayloadSize(2 * 32)
public
returns (bool success)
{
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
}
The documentation of the onlyPayloadSize
modifier is extremely unclear to me.
Can somebody please explain the following:
- What exactly is the purpose of this modifier?
- Why is it used only in the
trasnsfer
function? - Why is it used with a specific size of 64 (
2 * 32
)? - Why is this modifier present only in a test contract, and not in the actual
MultiSigWallet
contract? Does this by any chance imply that I should add this modifier in every contract in my system, designated for access only via an instance of theMultiSigWallet
contract? If I don't have any such contract with a standardtransfer
method (i.e., an ERC20 contract), can I rest assure that I don't need this modifier anywhere else in my system?
Thank you!
solidity
solidity
edited Nov 29 at 12:16
asked Nov 29 at 12:04
goodvibration
2,412721
2,412721
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
4
down vote
accepted
Questions 1 is answered in this question. There is also much more details at Golem's blog here.
The only reason it was only used in the transfer function is because the contract is for testing. In the wild, this contract would have the safeguard in the
transferFrom
andapprove
functions as well.The 2 * 32 is because that's how large the payload should be for that function. ABI encoding for function parameters has address and uint256 using 1 256 bit slot each, hence why they're calling the modifier with 2 * 32.
This vulnerability is a protection for the person calling the contract against someone that gives them the data. If the person calling the function validates the data is the correct size before submitting it to the network, then they wont have any issues. The large libraries (Web3.js, Ethers.js, etc.) do all this for you when you encode data, e.g. if you use
web3.eth.abi.encodeParameters(["address"], ["0x72abde8f"])
, it'll throw an error because the address is too short.
Edit: As Smarx has pointed out in the comments, there is a lot of discussion about specifically avoiding this type of fix, as it makes some things even more difficulty as outlined here. Gnosis specifically points this out in the code quoted by OP as well. In the end, my opinion is that protections such as onlyPayloadSize
are much better suited to be done off-chain.
1
Note that as one of the answers on that question points out, the current guidance is to not use this type of check.
– smarx
Nov 29 at 14:46
And it is done off-chain so long as I use web3, right? Can someone attack my contract (the one protected with aMultiSigWallet
instance), by passing corrupted data to it without using web3? I mean, the fact that I interact with the contract via web3 makes theonlyPayloadSize
redundant. But can someone use the fact that I have omitted this modifier, and attack my contract by interracting with it directly (i.e., not via web3)?
– goodvibration
Nov 29 at 15:01
It's very hard to say without specific examples. You really have to think about what would happen if someone sent a short parameter to one of the functions.
– flygoing
Nov 29 at 15:04
So you're saying that theMultiSigWallet
contract is not really secure by itself, and I would need to check payload size at the beginning of every function intended to be invoked viaMultiSigWallet
?
– goodvibration
Nov 29 at 15:07
It's not theMultiSigWallet
's responsibility to validate the data being passed to your contract. It can't be insecure at something it has no knowledge, context, or responsibility about. Its responsibility is to only act on transactions that have been given proper authorization by whatever its x-of-x scheme, and it's likely pretty safe at doing that. You need to analyze your own contracts (or pay someone else to) outside the scope of the multisig to be sure they're safe. Note in the edit that many contracts (including Gnosis safe) can't call contracts with theonlyPayloadSize
check anyway
– flygoing
Nov 29 at 15:13
|
show 2 more comments
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
Questions 1 is answered in this question. There is also much more details at Golem's blog here.
The only reason it was only used in the transfer function is because the contract is for testing. In the wild, this contract would have the safeguard in the
transferFrom
andapprove
functions as well.The 2 * 32 is because that's how large the payload should be for that function. ABI encoding for function parameters has address and uint256 using 1 256 bit slot each, hence why they're calling the modifier with 2 * 32.
This vulnerability is a protection for the person calling the contract against someone that gives them the data. If the person calling the function validates the data is the correct size before submitting it to the network, then they wont have any issues. The large libraries (Web3.js, Ethers.js, etc.) do all this for you when you encode data, e.g. if you use
web3.eth.abi.encodeParameters(["address"], ["0x72abde8f"])
, it'll throw an error because the address is too short.
Edit: As Smarx has pointed out in the comments, there is a lot of discussion about specifically avoiding this type of fix, as it makes some things even more difficulty as outlined here. Gnosis specifically points this out in the code quoted by OP as well. In the end, my opinion is that protections such as onlyPayloadSize
are much better suited to be done off-chain.
1
Note that as one of the answers on that question points out, the current guidance is to not use this type of check.
– smarx
Nov 29 at 14:46
And it is done off-chain so long as I use web3, right? Can someone attack my contract (the one protected with aMultiSigWallet
instance), by passing corrupted data to it without using web3? I mean, the fact that I interact with the contract via web3 makes theonlyPayloadSize
redundant. But can someone use the fact that I have omitted this modifier, and attack my contract by interracting with it directly (i.e., not via web3)?
– goodvibration
Nov 29 at 15:01
It's very hard to say without specific examples. You really have to think about what would happen if someone sent a short parameter to one of the functions.
– flygoing
Nov 29 at 15:04
So you're saying that theMultiSigWallet
contract is not really secure by itself, and I would need to check payload size at the beginning of every function intended to be invoked viaMultiSigWallet
?
– goodvibration
Nov 29 at 15:07
It's not theMultiSigWallet
's responsibility to validate the data being passed to your contract. It can't be insecure at something it has no knowledge, context, or responsibility about. Its responsibility is to only act on transactions that have been given proper authorization by whatever its x-of-x scheme, and it's likely pretty safe at doing that. You need to analyze your own contracts (or pay someone else to) outside the scope of the multisig to be sure they're safe. Note in the edit that many contracts (including Gnosis safe) can't call contracts with theonlyPayloadSize
check anyway
– flygoing
Nov 29 at 15:13
|
show 2 more comments
up vote
4
down vote
accepted
Questions 1 is answered in this question. There is also much more details at Golem's blog here.
The only reason it was only used in the transfer function is because the contract is for testing. In the wild, this contract would have the safeguard in the
transferFrom
andapprove
functions as well.The 2 * 32 is because that's how large the payload should be for that function. ABI encoding for function parameters has address and uint256 using 1 256 bit slot each, hence why they're calling the modifier with 2 * 32.
This vulnerability is a protection for the person calling the contract against someone that gives them the data. If the person calling the function validates the data is the correct size before submitting it to the network, then they wont have any issues. The large libraries (Web3.js, Ethers.js, etc.) do all this for you when you encode data, e.g. if you use
web3.eth.abi.encodeParameters(["address"], ["0x72abde8f"])
, it'll throw an error because the address is too short.
Edit: As Smarx has pointed out in the comments, there is a lot of discussion about specifically avoiding this type of fix, as it makes some things even more difficulty as outlined here. Gnosis specifically points this out in the code quoted by OP as well. In the end, my opinion is that protections such as onlyPayloadSize
are much better suited to be done off-chain.
1
Note that as one of the answers on that question points out, the current guidance is to not use this type of check.
– smarx
Nov 29 at 14:46
And it is done off-chain so long as I use web3, right? Can someone attack my contract (the one protected with aMultiSigWallet
instance), by passing corrupted data to it without using web3? I mean, the fact that I interact with the contract via web3 makes theonlyPayloadSize
redundant. But can someone use the fact that I have omitted this modifier, and attack my contract by interracting with it directly (i.e., not via web3)?
– goodvibration
Nov 29 at 15:01
It's very hard to say without specific examples. You really have to think about what would happen if someone sent a short parameter to one of the functions.
– flygoing
Nov 29 at 15:04
So you're saying that theMultiSigWallet
contract is not really secure by itself, and I would need to check payload size at the beginning of every function intended to be invoked viaMultiSigWallet
?
– goodvibration
Nov 29 at 15:07
It's not theMultiSigWallet
's responsibility to validate the data being passed to your contract. It can't be insecure at something it has no knowledge, context, or responsibility about. Its responsibility is to only act on transactions that have been given proper authorization by whatever its x-of-x scheme, and it's likely pretty safe at doing that. You need to analyze your own contracts (or pay someone else to) outside the scope of the multisig to be sure they're safe. Note in the edit that many contracts (including Gnosis safe) can't call contracts with theonlyPayloadSize
check anyway
– flygoing
Nov 29 at 15:13
|
show 2 more comments
up vote
4
down vote
accepted
up vote
4
down vote
accepted
Questions 1 is answered in this question. There is also much more details at Golem's blog here.
The only reason it was only used in the transfer function is because the contract is for testing. In the wild, this contract would have the safeguard in the
transferFrom
andapprove
functions as well.The 2 * 32 is because that's how large the payload should be for that function. ABI encoding for function parameters has address and uint256 using 1 256 bit slot each, hence why they're calling the modifier with 2 * 32.
This vulnerability is a protection for the person calling the contract against someone that gives them the data. If the person calling the function validates the data is the correct size before submitting it to the network, then they wont have any issues. The large libraries (Web3.js, Ethers.js, etc.) do all this for you when you encode data, e.g. if you use
web3.eth.abi.encodeParameters(["address"], ["0x72abde8f"])
, it'll throw an error because the address is too short.
Edit: As Smarx has pointed out in the comments, there is a lot of discussion about specifically avoiding this type of fix, as it makes some things even more difficulty as outlined here. Gnosis specifically points this out in the code quoted by OP as well. In the end, my opinion is that protections such as onlyPayloadSize
are much better suited to be done off-chain.
Questions 1 is answered in this question. There is also much more details at Golem's blog here.
The only reason it was only used in the transfer function is because the contract is for testing. In the wild, this contract would have the safeguard in the
transferFrom
andapprove
functions as well.The 2 * 32 is because that's how large the payload should be for that function. ABI encoding for function parameters has address and uint256 using 1 256 bit slot each, hence why they're calling the modifier with 2 * 32.
This vulnerability is a protection for the person calling the contract against someone that gives them the data. If the person calling the function validates the data is the correct size before submitting it to the network, then they wont have any issues. The large libraries (Web3.js, Ethers.js, etc.) do all this for you when you encode data, e.g. if you use
web3.eth.abi.encodeParameters(["address"], ["0x72abde8f"])
, it'll throw an error because the address is too short.
Edit: As Smarx has pointed out in the comments, there is a lot of discussion about specifically avoiding this type of fix, as it makes some things even more difficulty as outlined here. Gnosis specifically points this out in the code quoted by OP as well. In the end, my opinion is that protections such as onlyPayloadSize
are much better suited to be done off-chain.
edited Nov 29 at 14:56
answered Nov 29 at 13:52
flygoing
6,248830
6,248830
1
Note that as one of the answers on that question points out, the current guidance is to not use this type of check.
– smarx
Nov 29 at 14:46
And it is done off-chain so long as I use web3, right? Can someone attack my contract (the one protected with aMultiSigWallet
instance), by passing corrupted data to it without using web3? I mean, the fact that I interact with the contract via web3 makes theonlyPayloadSize
redundant. But can someone use the fact that I have omitted this modifier, and attack my contract by interracting with it directly (i.e., not via web3)?
– goodvibration
Nov 29 at 15:01
It's very hard to say without specific examples. You really have to think about what would happen if someone sent a short parameter to one of the functions.
– flygoing
Nov 29 at 15:04
So you're saying that theMultiSigWallet
contract is not really secure by itself, and I would need to check payload size at the beginning of every function intended to be invoked viaMultiSigWallet
?
– goodvibration
Nov 29 at 15:07
It's not theMultiSigWallet
's responsibility to validate the data being passed to your contract. It can't be insecure at something it has no knowledge, context, or responsibility about. Its responsibility is to only act on transactions that have been given proper authorization by whatever its x-of-x scheme, and it's likely pretty safe at doing that. You need to analyze your own contracts (or pay someone else to) outside the scope of the multisig to be sure they're safe. Note in the edit that many contracts (including Gnosis safe) can't call contracts with theonlyPayloadSize
check anyway
– flygoing
Nov 29 at 15:13
|
show 2 more comments
1
Note that as one of the answers on that question points out, the current guidance is to not use this type of check.
– smarx
Nov 29 at 14:46
And it is done off-chain so long as I use web3, right? Can someone attack my contract (the one protected with aMultiSigWallet
instance), by passing corrupted data to it without using web3? I mean, the fact that I interact with the contract via web3 makes theonlyPayloadSize
redundant. But can someone use the fact that I have omitted this modifier, and attack my contract by interracting with it directly (i.e., not via web3)?
– goodvibration
Nov 29 at 15:01
It's very hard to say without specific examples. You really have to think about what would happen if someone sent a short parameter to one of the functions.
– flygoing
Nov 29 at 15:04
So you're saying that theMultiSigWallet
contract is not really secure by itself, and I would need to check payload size at the beginning of every function intended to be invoked viaMultiSigWallet
?
– goodvibration
Nov 29 at 15:07
It's not theMultiSigWallet
's responsibility to validate the data being passed to your contract. It can't be insecure at something it has no knowledge, context, or responsibility about. Its responsibility is to only act on transactions that have been given proper authorization by whatever its x-of-x scheme, and it's likely pretty safe at doing that. You need to analyze your own contracts (or pay someone else to) outside the scope of the multisig to be sure they're safe. Note in the edit that many contracts (including Gnosis safe) can't call contracts with theonlyPayloadSize
check anyway
– flygoing
Nov 29 at 15:13
1
1
Note that as one of the answers on that question points out, the current guidance is to not use this type of check.
– smarx
Nov 29 at 14:46
Note that as one of the answers on that question points out, the current guidance is to not use this type of check.
– smarx
Nov 29 at 14:46
And it is done off-chain so long as I use web3, right? Can someone attack my contract (the one protected with a
MultiSigWallet
instance), by passing corrupted data to it without using web3? I mean, the fact that I interact with the contract via web3 makes the onlyPayloadSize
redundant. But can someone use the fact that I have omitted this modifier, and attack my contract by interracting with it directly (i.e., not via web3)?– goodvibration
Nov 29 at 15:01
And it is done off-chain so long as I use web3, right? Can someone attack my contract (the one protected with a
MultiSigWallet
instance), by passing corrupted data to it without using web3? I mean, the fact that I interact with the contract via web3 makes the onlyPayloadSize
redundant. But can someone use the fact that I have omitted this modifier, and attack my contract by interracting with it directly (i.e., not via web3)?– goodvibration
Nov 29 at 15:01
It's very hard to say without specific examples. You really have to think about what would happen if someone sent a short parameter to one of the functions.
– flygoing
Nov 29 at 15:04
It's very hard to say without specific examples. You really have to think about what would happen if someone sent a short parameter to one of the functions.
– flygoing
Nov 29 at 15:04
So you're saying that the
MultiSigWallet
contract is not really secure by itself, and I would need to check payload size at the beginning of every function intended to be invoked via MultiSigWallet
?– goodvibration
Nov 29 at 15:07
So you're saying that the
MultiSigWallet
contract is not really secure by itself, and I would need to check payload size at the beginning of every function intended to be invoked via MultiSigWallet
?– goodvibration
Nov 29 at 15:07
It's not the
MultiSigWallet
's responsibility to validate the data being passed to your contract. It can't be insecure at something it has no knowledge, context, or responsibility about. Its responsibility is to only act on transactions that have been given proper authorization by whatever its x-of-x scheme, and it's likely pretty safe at doing that. You need to analyze your own contracts (or pay someone else to) outside the scope of the multisig to be sure they're safe. Note in the edit that many contracts (including Gnosis safe) can't call contracts with the onlyPayloadSize
check anyway– flygoing
Nov 29 at 15:13
It's not the
MultiSigWallet
's responsibility to validate the data being passed to your contract. It can't be insecure at something it has no knowledge, context, or responsibility about. Its responsibility is to only act on transactions that have been given proper authorization by whatever its x-of-x scheme, and it's likely pretty safe at doing that. You need to analyze your own contracts (or pay someone else to) outside the scope of the multisig to be sure they're safe. Note in the edit that many contracts (including Gnosis safe) can't call contracts with the onlyPayloadSize
check anyway– flygoing
Nov 29 at 15:13
|
show 2 more comments
Thanks for contributing an answer to Ethereum Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fethereum.stackexchange.com%2fquestions%2f63278%2fwhat-is-the-purpose-in-asserting-msg-data-length-64-4%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown