-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CALL_STIPEND is injected in gas left directly when a call has value #45
Comments
Severity: Invalid Comment: Invalid; the gas estimation is done by the RPC in all cases. While gas_required does not fully reflect the actual required gas for the execution, it returns a heuristic corresponding to gas_limit - gas_left. No funds at risk, no exploit path possible |
dmvt marked the issue as unsatisfactory: |
Hi @dmvt, I believe this is a valid issue.
For the bytecode mentioned in this report : Gas estimate
Gas Consumed using respective estimates
Transaction Status using respective estimates
Trace Diff using EVM estimate for bothEVM on the left, Kakarot EVM on the right [ [
{ {
"pc": 0, "pc": 0,
"op": "PUSH0", "op": "PUSH0",
"gas": 36616, "gas": 36616,
"gasCost": 2, "gasCost": 2,
"depth": 1, "depth": 1,
"stack": [] "stack": []
}, },
{ {
"pc": 1, "pc": 1,
"op": "PUSH0", "op": "PUSH0",
"gas": 36614, "gas": 36614,
"gasCost": 2, "gasCost": 2,
"depth": 1, "depth": 1,
"stack": [ "stack": [
"0x0" "0x0"
] ]
}, },
{ {
"pc": 2, "pc": 2,
"op": "PUSH0", "op": "PUSH0",
"gas": 36612, "gas": 36612,
"gasCost": 2, "gasCost": 2,
"depth": 1, "depth": 1,
"stack": [ "stack": [
"0x0", "0x0",
"0x0" "0x0"
] ]
}, },
{ {
"pc": 3, "pc": 3,
"op": "PUSH0", "op": "PUSH0",
"gas": 36610, "gas": 36610,
"gasCost": 2, "gasCost": 2,
"depth": 1, "depth": 1,
"stack": [ "stack": [
"0x0", "0x0",
"0x0", "0x0",
"0x0" "0x0"
] ]
}, },
{ {
"pc": 4, "pc": 4,
"op": "PUSH1", "op": "PUSH1",
"gas": 36608, "gas": 36608,
"gasCost": 3, "gasCost": 3,
"depth": 1, "depth": 1,
"stack": [ "stack": [
"0x0", "0x0",
"0x0", "0x0",
"0x0", "0x0",
"0x0" "0x0"
] ]
}, },
{ {
"pc": 6, "pc": 6,
"op": "PUSH1", "op": "PUSH1",
"gas": 36605, "gas": 36605,
"gasCost": 3, "gasCost": 3,
"depth": 1, "depth": 1,
"stack": [ "stack": [
"0x0", "0x0",
"0x0", "0x0",
"0x0", "0x0",
"0x0", "0x0",
"0x1" "0x1"
] ]
}, },
{ {
"pc": 8, "pc": 8,
"op": "GAS", "op": "GAS",
"gas": 36602, "gas": 36602,
"gasCost": 2, "gasCost": 2,
"depth": 1, "depth": 1,
"stack": [ "stack": [
"0x0", "0x0",
"0x0", "0x0",
"0x0", "0x0",
"0x0", "0x0",
"0x1", "0x1",
"0xff" "0xff"
] ]
}, },
{ {
"pc": 9, "pc": 9,
"op": "CALL", "op": "CALL",
"gas": 36600, "gas": 36600,
"gasCost": 36600, | "gasCost": 34300,
"depth": 1, "depth": 1,
"stack": [ "stack": [
"0x0", "0x0",
"0x0", "0x0",
"0x0", "0x0",
"0x0", "0x0",
"0x1", "0x1",
"0xff", "0xff",
"0x8ef8" "0x8ef8"
] ]
}, },
{ {
"pc": 10, "pc": 10,
"op": "PC", "op": "PC",
"gas": 2300, "gas": 2300,
"gasCost": 2, "gasCost": 2,
"depth": 1, "depth": 1,
"stack": [ "stack": [
"0x0" "0x0"
] <
}, <
{ <
"pc": 11, <
"op": "STOP", <
"gas": 2298, <
"gasCost": 0, <
"depth": 1, <
"stack": [ <
"0x0", <
"0xa" <
] ]
} }
] ] In summary, although only Can you please check this again, thank you. |
dmvt removed the grade |
dmvt marked the issue as selected for report |
Thank you for the additional context and proof. In this case you are highlighting a denial of service that will impact protocol availability and cause annoyance for the user. It is effectively a self-griefing attack. Reinstated as a valid medium. |
Hi @dmvt, I believe protocol availability will not be impacted, but yes users will need to bump the gas estimates given by Kakarot in those cases in other for their transaction to succeed. Thanks 👍 |
Correct. No direct impact. What I was trying (and failed) to communicate is that when a transaction fails because of a bad gas estimate, the impact is the same way as griefing attacks which cause an otherwise valid transaction to fail. There is a lot of precedent stating that these types of griefing attacks are medium risk, so it makes sense to me that this issue has the same severity. |
In the EVM context "refund" only refers to the gas that is reimbursed for clearing storage, so I would say that in this case we cannot really say that the Actually, we will use the If you want, you can check the code of RETH and GETH. All EVM clients use a binary search to find an accurate gas estimation, because it is not predictible by simply analyzing the transaction simulation receipt
I highly disagree with that; as there is nothing related to Kakarot that will make DoS attack possible that will impact protocol availability in any case. This is akin to saying that hosting an RPC service with a Geth node that returns wrong gas estimates is a risk for the Ethereum protocol.
I have an opposite view, I think it's not a griefing attack on the protocol, considering that what happens here is just a transaction that was submitted with an incorrect gas limit for it to complete successfully 🤔 To summarize things:
|
Ok with the sponsor's comments, I'm in agreement. Appreciate the links to the GETH/RETH code, which helps with comparison. I was mistakenly under the impression that the fix to gas estimates had been at the node level in EVM, not at the client level. Back to invalid. |
dmvt marked the issue as unsatisfactory: |
Lines of code
https://github.com/kkrt-labs/kakarot/blob/7411a5520e8a00be6f5243a50c160e66ad285563/src/kakarot/interpreter.cairo#L820-L1040
https://github.com/kkrt-labs/kakarot/blob/7411a5520e8a00be6f5243a50c160e66ad285563/src/kakarot/instructions/system_operations.cairo#L339-L466
https://github.com/kkrt-labs/kakarot/blob/7411a5520e8a00be6f5243a50c160e66ad285563/src/kakarot/interpreter.cairo#L820-L1040
Vulnerability details
Impact
This leads to wrong estimates as the gas required ends up being lower than what's really needed.
Proof of Concept
Interpreter
System Operations
ETH RPC
When a
CALL / CALLCODE
transfer value, a call stipend is added to guarantee that the fallback function of the receiver can be called.The problem here is how it is added, directly injected in the gas left and making it seem like the operation requires less gas than what's actually need.
For instance, if we consider a simple
CALL
where an existing sender account doesn't have enough balance to cover the value of the transfer for example and assuming an initial gas limit of11600
:11600
gas will be charged in (1) (.i.e WARM_ACCESS + CALL_VALUE = 2600 + 9000)2300
(.i.e CALL_STIPED gas) will be injected directly into the gas leftgas_required
will be equal togas_limit - gas_left = 11600 - 2300 = 9300
gas_used
will be equal togas_required - gas_refund = 9300 = 9300
So if we were to use the estimate that will be provided for this call (.i.e
9300
, thegas_required
) to execute it, the execution will fail because it will be short2300
gas when charging gas in (1) since it requires11600
.Bytecode
Try deploying the following bytecode :
5f5f5f5f600160ff5af1
Transaction Results
Recommended Mitigation Steps
The call stipend needs to be treated as a refund but logic to handle refunds at the end of calls will be needed.
Assessed type
Other
The text was updated successfully, but these errors were encountered: