Open c4-bot-8 opened 3 months ago
Reminder that @xuwinnie had this issue in his QA report, so should be dup'd in with this one.
This is accurate. There was a fair bit of debate about whether 2 * CLOCK_EXTENSION
was actually required at the split depth so this doesn't concern me, though if we extend the limit for one side it seems reasonable to expect it to be extended for the other side as well.
zobront marked the issue as satisfactory
zobront marked the issue as selected for report
Lines of code
https://github.com/code-423n4/2024-07-optimism/blob/70556044e5e080930f686c4e5acde420104bb2c4/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol#L377-L380
Vulnerability details
Impact
In some cases, a team will not be granted enough CLOCK_EXTENSION time to generate the initial instruction trace and perform a counter claim.
Proof of Concept
In FaultDisputeGame::move, game clocks will grant extensions to ensure a team has enough time to counter a potential claim and/or generate an execution trace bisection root claim. A special case is when the potential grandchild is executiontrace bisection root claim ( SPLIT_DEPTH + 1), twice the extension time (
2 * CLOCK_EXTENSION.raw()
) should be ensured.The problem is that the current implementation might still cause a team to have less than
2 * CLOCK_EXTENSION.raw()
time to generate an execution trace bisection root claim and perform a counterclaim. Specifically,if (nextDuration.raw() > MAX_CLOCK_DURATION.raw() - CLOCK_EXTENSION.raw())
condition check is vulnerable.(https://github.com/code-423n4/2024-07-optimism/blob/70556044e5e080930f686c4e5acde420104bb2c4/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol#L377-L380)
Suppose CLOCK_EXTENSION.raw() is 3 hours, MAX_CLOCK_DURATION.raw() is 84 hours (3.5 days).
Case A: At time of move(), nextDuration.raw() is 82 hours. nextPosition is at SPLIT_DEPTH -1.
nextDuration.raw() > MAX_CLOCK_DURATION.raw() - CLOCK_EXTENSION.raw(). The grandchild is at SPLIT_DEPTH + 1 (execution trace root).
extensionPeriod: 6h (CLOCK_EXTENSION.raw() 2) nextDuration: 78h (MAX_CLOCK_DURATION.raw() - CLOCK_EXTENSION.raw() 2)
Case B: At time of move(), nextDuration.raw() is 81 hours. nextPosition is at SPLIT_DEPTH -1.
B-1: nextDuration.raw() == MAX_CLOCK_DURATION.raw() - CLOCK_EXTENSION.raw(). The grandchild is at SPLIT_DEPTH + 1 (execution trace root).
The if condition will be bypassed.
extensionPeriod: 0h nextDuration: 81h
B-2: The oppposing team attack.
B-3: The grandchild now has max. 3h to generate execution trace root claim and perform an counter claim. This is half of the intended
CLOCK_EXTENSION.raw() * 2
.As seen in caseB, in normal conditions, a team that need to create both executiontrace root claim and perform a counter claim may not get the minimum
CLOCK_EXTENSION.raw() * 2
time. A team's clock may run out prematurely.Tools Used
Manual
Recommended Mitigation Steps
Consider change to the following:
Assessed type
Other