You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on May 26, 2023. It is now read-only.
github-actionsbot opened this issue
Feb 20, 2023
· 1 comment
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelHighA valid High severity issueRewardA payout will be made for this issue
relayMessage may call the target functions with less gas than was anticipated by its sender
Summary
The relayMessage inside CrossDomainMessenger does not check the minGasLimit specified by the user correctly and can call the function with less gas than specified by the user.
Vulnerability Detail
Security check for _minGasLimit inside the relaymessage() inside the CrossDomainMessenger contract is implemented such as:
require(
gasleft() >= _minGasLimit + RELAY_GAS_REQUIRED,
"CrossDomainMessenger: insufficient gas to relay message"
);
However, while the baseGas used by the sendMessage function does calculate the 1/64 of the gas that is reserved through internal calls according to EIP-150, is not considered by the implemented security check by relayMessage. It should be mentioned that the user has to pay for it on the other chain, where baseGas calculates this amount.
While a user can provide the correct amount of _minGasLimit to the protocol, the target function can be called with less gas and can fail by running out of gas. The transaction should then be replayed later with a greater gas value as it gets stored in failedMessages.
This issue is highlighted when the amount of _minGasLimit is increased. If it is more than RELAY_GAS_REQUIRED * 64 = 45000 * 64 = 2880000, the problem will show itself. In the below PoC, target function is called with more than 6000 gas less than _minGasLimit, this problem increases with the amount of _minGasLimit.
Code Snippet
// SPDX-License-Identifier: MITpragma solidity0.8.15;
import"../contracts/universal/CrossDomainMessenger.sol";
import"forge-std/Test.sol";
contractPoCisTest {
CrossDomainMessenger cdm;
TargetContract target;
uint256 minGas =3000000;
function setUp() public {
cdm =newCDM();
target =newTargetContract(minGas);
}
function testMinGas() public {
console.log("Starting the test");
cdm.relayMessage{gas: 3065000}(
cdm.messageNonce(), // It is ok to use the same messanger nonce here, does not matter for our caseaddress(1),
address(target),
0,
minGas,
abi.encodeWithSignature("targetFunction()")
);
}
}
contractCDMisCrossDomainMessenger {
constructor() CrossDomainMessenger(address(0)) initializer {
__CrossDomainMessenger_init(); // We do not care if it is behind a proxy for this test!
}
function _sendMessage(
address_to,
uint64_gasLimit,
uint256_value,
bytesmemory_data
) internaloverride {}
function _isOtherMessenger() internalviewoverridereturns (bool){
returntrue;
}
function _isUnsafeTarget(address_target) internalviewoverridereturns (bool){
returnfalse;
}
}
contractTargetContract {
uint256immutablepublic minGas;
constructor (uint256_minGas) {
minGas = _minGas;
}
function targetFunction() publicreturns(uint256gasLeft){
gasLeft =gasleft();
console.log(gasLeft); // 2993969, it is less than 3000000 specified for the function call!return gasLeft;
}
}
Tool used
Manual Review
Recommendation
The mitigation is as easy as checking the amount of gasleft() to be more than 64/63 of the current checked value for _minGasLimit:
Sign up for freeto subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelHighA valid High severity issueRewardA payout will be made for this issue
Allarious
low
relayMessage
may call the target functions with less gas than was anticipated by its senderSummary
The
relayMessage
insideCrossDomainMessenger
does not check theminGasLimit
specified by the user correctly and can call the function with less gas than specified by the user.Vulnerability Detail
Security check for
_minGasLimit
inside therelaymessage()
inside theCrossDomainMessenger
contract is implemented such as:However, while the
baseGas
used by thesendMessage
function does calculate the 1/64 of the gas that is reserved through internal calls according to EIP-150, is not considered by the implemented security check byrelayMessage
. It should be mentioned that the user has to pay for it on the other chain, wherebaseGas
calculates this amount.Related LoCs:
https://github.com/sherlock-audit/2023-01-optimism/blob/main/optimism/packages/contracts-bedrock/contracts/universal/CrossDomainMessenger.sol#L318-L321
https://github.com/sherlock-audit/2023-01-optimism/blob/main/optimism/packages/contracts-bedrock/contracts/L1/OptimismPortal.sol#L313-L316
Impact
While a user can provide the correct amount of
_minGasLimit
to the protocol, the target function can be called with less gas and can fail by running out of gas. The transaction should then be replayed later with a greater gas value as it gets stored infailedMessages
.This issue is highlighted when the amount of
_minGasLimit
is increased. If it is more thanRELAY_GAS_REQUIRED * 64 = 45000 * 64 = 2880000
, the problem will show itself. In the below PoC, target function is called with more than 6000 gas less than_minGasLimit
, this problem increases with the amount of_minGasLimit
.Code Snippet
Tool used
Manual Review
Recommendation
The mitigation is as easy as checking the amount of
gasleft()
to be more than 64/63 of the current checked value for_minGasLimit
:Where the final check should look like:
Duplicate of #96
The text was updated successfully, but these errors were encountered: