-
Notifications
You must be signed in to change notification settings - Fork 1
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
WIP: Add support for uninterrupted delegatecall chains #10
base: master
Are you sure you want to change the base?
Conversation
The commit fafba65 (as a parent of 631f555) contains errors. |
### Context variable for the `entry_point_role` value | ||
|
||
During the execution of the `Sender`, `Paymaster` or a `Deployer` code as defined by the `AA_TX_TYPE` transaction, | ||
the global `entry_point_role` variable is set to the corresponding role. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this variable accessed from EVM? A new opcode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variable is not actually visible inside the EVM. It is used by the EVM implementation to decide which code section to enter when using DELEGATECALL
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could encode that variable into ORIGIN
so instead of 0x7701000000000000000000000000000000007701
it would return 0x7701000000000000000000000000000000000000 | entry_point_role
but I'm not sure if we should. May be useful if a function called by the role's code section needs to know the context. OTOH the code itself could pass it as an arg if it's needed.
If the specified contract does not contain such a section, or is not an EOF contract, | ||
execution starts at code section 0, and pc is set to 0. | ||
|
||
The transaction is considered invalid if it never reached a code section corresponding to the current `entry_point_role` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know the goal is to support legacy proxies but it seems risky:
- Suppose a contract that implements user-controlled callbacks (such as an ERC-1155 token that calls
onERC1155BatchReceived
) is called this way. An attacker could deploy a contract that implements the methodsig ofonERC1155BatchReceived
to call its ownrole_sender_validation
androle_sender_execution
sections which accept the transaction. Will this result in executing the attacker's call from the token contract? - DoS resistance. Many proxies could point to the same implementation, which could then invalidate many mempool transactions. We have no way to associate the proxy with the implementation and ensure 1:1 relation. How do we mitigate this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re 1: The the entry_point_role
is only preserved (and can activate) through an uninterrupted chain of DELEGATECALL
s. Calling the malicious contract with a regular CALL
does not carry the entry_point_role
, and the callbacks cannot authorize a transaction.
Re 2: As the implementation in this scenario is an EOF contract, which means it has no SELFDESTRUCT
or any other way to modify its own code, and must be called with DELEGATECALL
meaning its storage cannot be accessed, I don't see a way for the "owner" of the implementation contract to invalidate a transaction. Am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re 2: Its storage can't be accessed, but environment opcodes can still be used, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. That makes sense. I previously misunderstood the uninterrupted chain of DELEGATECALLs part. Looks like it does solve the proxy case, neat.
Re 2: As the implementation in this scenario is an EOF contract, which means it has no SELFDESTRUCT or any other way to modify its own code,
Since it's a chain, a non-EOF link in the chain could break the chain and never reach an EOF contract. But your assumption still holds since there's no SELFDESTRUCT for an existing non-EOF contract either and it can't access its own storage. Therefore invalidation can only be done in the account itself, making it an O(n) attack. Seems fine.
Re 2: Its storage can't be accessed, but environment opcodes can still be used, no?
Since it can't use storage to divert the flow to a different implementation, the opcodes during offchain simulation and block inclusion are the same. Therefore the ERC-7562 rules can ensure that no banned opcodes are used.
### Accepting the transaction by `Sender` or `Paymaster` | ||
|
||
In order for the `Sender` or `Paymaster` contracts to accept the transaction, | ||
they must perform a `CALL` to the `AA_ORIGIN` address with the appropriate acceptance data as call data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the call have to be performed by the actual Sender
/ Paymaster
, or just in its context? If it's the former then the above proxy-support method, then proxies won't work. If the latter, then the security concerns I wrote above apply.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think supporting existing proxy contracts is essential, so the call must be made in the context of the Sender
/ Paymaster
. As I replied, I don't think there is a security concern unless there is a DELEGATECALL
to an untrusted contract, in which case the attack does not require messing with roles.
### Context variable for the `entry_point_role` value | ||
|
||
During the execution of the `Sender`, `Paymaster` or a `Deployer` code as defined by the `AA_TX_TYPE` transaction, | ||
the global `entry_point_role` variable is set to the corresponding role. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could encode that variable into ORIGIN
so instead of 0x7701000000000000000000000000000000007701
it would return 0x7701000000000000000000000000000000000000 | entry_point_role
but I'm not sure if we should. May be useful if a function called by the role's code section needs to know the context. OTOH the code itself could pass it as an arg if it's needed.
ATTENTION: ERC-RELATED PULL REQUESTS NOW OCCUR IN ETHEREUM/ERCS
--
When opening a pull request to submit a new EIP, please use the suggested template: https://github.com/ethereum/EIPs/blob/master/eip-template.md
We have a GitHub bot that automatically merges some PRs. It will merge yours immediately if certain criteria are met: