It's impossible to add a calldata check for neighboring byte portions (and more implications) #47
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
downgraded by judge
Judge downgraded the risk level of this issue
duplicate-17
edited-by-warden
🤖_24_group
AI based duplicate group recommendation
satisfactory
satisfies C4 submission criteria; eligible for awards
sufficient quality report
This report is of sufficient quality
Lines of code
https://github.com/code-423n4/2024-10-kleidi/blob/ab89bcb443249e1524496b694ddb19e298dca799/src/Timelock.sol#L1119-L1122,https://github.com/code-423n4/2024-10-kleidi/blob/ab89bcb443249e1524496b694ddb19e298dca799/src/Timelock.sol#L496-L501
Vulnerability details
Summary
_addCalldataCheck and checkCalldata are not fine tuned to work correctly when checking neighboring byte portions - impossible to add two calldata checks which are neighboring.
Vulnerability details
When adding a calllData check it does not allow to add check whose startIndex or endIndex are overlapping or EQUAL.
This means the closest checks possible will look like this (example using 4 byte portions):
{ startIndex: 4, endIndex: 8, ... }
and{ startIndex: 9, endIndex: 13 ... }
And on the surface this may look fine, but when we reach checkCalldata, it is calling getSliceBytesHash -> which uses sliceBytes function underneath:
And if we look at sliceBytes function:
It counts bytes from start index (i starts at 0) and keeps slicing (end - start -> 8 - 4 = 4) times. This means 4th,5th,6th and 7th bytes are sliced. This also means that the endIndex itself (8) is NOT going to be included in the slice.
From here we see that there is a discrepancy:
Which creates a 1 byte gap any time more than 1 check (with a different byte portion) is added to a single calldata.
Impact
Can't add neighboring calldata checks, because the checked indexes are applied on wrong pieces of calldata bytes. Also because the slicing is applied incorrectly, the calldata check will fail if calldata is the exact size as the checks (due to 1 byte shift, needs to have an extra byte at the end).
Tools used
Manual review + foundry tests
Proof of Concept
Lets use an example calldata with portions as follows:
0x42424242111111112222222233
arg1 and arg2 are 4 bytes each
arg3 is a single byte
[selector] [arg1 ] [arg2 ] [arg 3]
0x42424242 11111111 22222222 33
foundry test
This test will fail with "CalldataList: Calldata does not match expected value"
I've replaced the getSlicedBytesHash with explicit
keccak256(sliceBytes(toSlice, start, end))
, to get the output of sliceBytes in logs and on the failed test case they are as follows:This also means that calldata of exact size (without the 0x33) at the end will outright revert due to:
End index is greater than the length of the byte string
. Which adds more trouble to the same problemRecommended Mitigation Steps
Fine tunning of checks in adding and checking is required - two approaches come to mind:
Both of these would need another re-check if it doesn't break code elsewhere.
Assessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: