Skip to content
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

Allow direct plugin calls with validation & permission hooks #90

Merged
merged 26 commits into from
Jul 17, 2024

Conversation

Zer0dot
Copy link
Contributor

@Zer0dot Zer0dot commented Jul 10, 2024

Motivation

In order to support workflows where an action should be allowed only if a plugin allows it (e.g. cold storage: block all transfers unless the plugin authorizes it), we need a way for plugins to directly call into account functions.

However, having the flexibility to still attach validation (and permission) hooks would allow for account-decided limited scopes for each plugin allowed to do this, in contrast with the previously removed permitted call workflow.

Solution

Add a field for allowed direct calls to account storage. This is a mapping from caller to selector to a new struct which contains a boolean and an array of validation hooks.

In _checkPermittedCallerIfNotFromEP called from wrapNativeFunction, we can then check if the call is allowed to occur and execute its respective validation hooks.

TODO/TBD

Depends on user-supplied install configs for plugins to determine how this storage is set on installation (manifest, encoded in user-supplied data?)

Do we want to redesign the system to not need additional storage? Can we do so without complicating plugin developers' mental models of the system?

Update: Modified to use installValidation() which uses user-provided configurations.

@Zer0dot Zer0dot changed the base branch from main to adam/sample-allowlist-hook July 10, 2024 12:30
@Zer0dot Zer0dot force-pushed the zer0dot/direct-plugin-calls branch from b5f4430 to 1e8344f Compare July 10, 2024 14:04
@adamegyed adamegyed force-pushed the adam/sample-allowlist-hook branch from 78ae1eb to 5c10b0d Compare July 10, 2024 14:45
Base automatically changed from adam/sample-allowlist-hook to v0.8-develop July 10, 2024 14:49
@Zer0dot Zer0dot force-pushed the zer0dot/direct-plugin-calls branch from 66e41e6 to b11b7b4 Compare July 11, 2024 12:24
@Zer0dot
Copy link
Contributor Author

Zer0dot commented Jul 12, 2024

Migrated installation to pluginManager2's installValidation(), much nicer now imo-- this reserves the maximum functionId though h/t @adamegyed for the discussion and thought process on this.

@Zer0dot
Copy link
Contributor Author

Zer0dot commented Jul 16, 2024

For context, installing a validation with the function reference of plugin_address .. type(uint8).max is interpreted as installing a self-permit validation.

@Zer0dot Zer0dot marked this pull request as ready for review July 16, 2024 12:44
@Zer0dot Zer0dot changed the title [DRAFT] Allow direct plugin calls with validation hooks Allow direct plugin calls with validation & permission hooks Jul 16, 2024
Copy link
Contributor

@adamegyed adamegyed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Had some comments

address plugin = validationConfig.plugin();
IPlugin(plugin).onInstall(installData);
if (validationConfig.functionId() != _SELF_PERMIT_VALIDATION_FUNCTIONID) {
// Only allow global validations and signature validations if they're not direct-call validations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary to prevent an access control issue? Or is it just an anti-footgun measure?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just an anti-footgun, though I've not evaluated the consequences of having global validation for a direct call-- signature validation either.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok sounds good. It might help to support global/sig validation in some very niche cases where the direct call validation is used to create an "owner" EOA, but that seems small enough to ignore for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, happy to revisit this down the line if we see the feature's important!

src/account/AccountStorage.sol Show resolved Hide resolved
src/account/UpgradeableModularAccount.sol Outdated Show resolved Hide resolved
src/account/UpgradeableModularAccount.sol Outdated Show resolved Hide resolved
src/account/AccountStorage.sol Outdated Show resolved Hide resolved
Copy link
Contributor

@adamegyed adamegyed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Remember to address the linter comment for function ordering in the contract

src/account/UpgradeableModularAccount.sol Outdated Show resolved Hide resolved
src/account/UpgradeableModularAccount.sol Outdated Show resolved Hide resolved
src/account/UpgradeableModularAccount.sol Outdated Show resolved Hide resolved
override
returns (bytes memory)
{
require(sender == address(this), "mock direct call pre permission hook failed");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh this is an annoying linter warning because it's in a test. Maybe add an exclusion for the rule reason-string in tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 0f04d85!

Doubled line length

@Zer0dot
Copy link
Contributor Author

Zer0dot commented Jul 17, 2024

Looks good! Remember to address the linter comment for function ordering in the contract

Addressed in d263656!

@Zer0dot Zer0dot merged commit a598069 into v0.8-develop Jul 17, 2024
3 checks passed
@Zer0dot Zer0dot deleted the zer0dot/direct-plugin-calls branch July 17, 2024 15:00
@@ -136,7 +135,7 @@ contract UpgradeableModularAccount is
revert UnrecognizedFunction(msg.sig);
}

_checkPermittedCallerIfNotFromEP();
_checkPermittedCallerAndAssociatedHooks();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if a signer of the account call an execFunction? Would it fail here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I.e. if a signer, as set in the storage of SingleSignerValidation, tries to call the account? In that case, this check would fail, the signer would need to use executeWithAuthorization to trigger runtime validation.

Alternatively, if an account is only used from an EOA, you could add an EOA itself as an allowed caller by installing the EOA address + the direct call magic value as a validation. But, this wouldn't be usable via user op validation.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't we executing the pre-execution hooks currently twice in case a permitted caller is calling through fallback? Within _checkPermittedCallerAndAssociatedHooks() in L664 we do the pre-execution hooks of the function selector, but again in the following fallback() flow in L143.
Also, are we not forgetting to do the post-permission hooks in the fallback flow? 👀

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xrubes you are correct... we'll get a fix PR up soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants