Skip to content

Commit

Permalink
fix: [quantstamp-16] Disallow using dependencies for hooks
Browse files Browse the repository at this point in the history
Allowing hooks to be dependencies can lead to hooks being called in
unexpected contexts, such as state-changing validation hooks being
called outside of validation or one of a pre- and post-exec hook pair
being called without the other. To prevent this without changing the
interface from the spec, we disallow this case entirely.
  • Loading branch information
dphilipson committed Jan 18, 2024
1 parent 61ff1d3 commit 6ecf507
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 1,083 deletions.
34 changes: 28 additions & 6 deletions src/account/PluginManagerInternals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
_addUserOpValidationFunction(
mv.executionSelector,
_resolveManifestFunction(
mv.associatedFunction, plugin, dependencies, ManifestAssociatedFunctionType.NONE
mv.associatedFunction, plugin, dependencies, true, ManifestAssociatedFunctionType.NONE
)
);

Expand All @@ -498,6 +498,7 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
mv.associatedFunction,
plugin,
dependencies,
true,
ManifestAssociatedFunctionType.RUNTIME_VALIDATION_ALWAYS_ALLOW
)
);
Expand All @@ -517,6 +518,7 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
mh.associatedFunction,
plugin,
dependencies,
false,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
)
);
Expand All @@ -536,6 +538,7 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
mh.associatedFunction,
plugin,
dependencies,
false,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
)
);
Expand All @@ -551,10 +554,14 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
_addExecHooks(
mh.executionSelector,
_resolveManifestFunction(
mh.preExecHook, plugin, dependencies, ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
mh.preExecHook,
plugin,
dependencies,
false,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
),
_resolveManifestFunction(
mh.postExecHook, plugin, dependencies, ManifestAssociatedFunctionType.NONE
mh.postExecHook, plugin, dependencies, false, ManifestAssociatedFunctionType.NONE
)
);

Expand All @@ -573,12 +580,14 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
manifest.permittedCallHooks[i].preExecHook,
plugin,
dependencies,
false,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
),
_resolveManifestFunction(
manifest.permittedCallHooks[i].postExecHook,
plugin,
dependencies,
false,
ManifestAssociatedFunctionType.NONE
)
);
Expand Down Expand Up @@ -695,12 +704,14 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
args.manifest.permittedCallHooks[i].preExecHook,
args.plugin,
dependencies,
false,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
),
_resolveManifestFunction(
args.manifest.permittedCallHooks[i].postExecHook,
args.plugin,
dependencies,
false,
ManifestAssociatedFunctionType.NONE
)
);
Expand All @@ -717,10 +728,14 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
_removeExecHooks(
mh.executionSelector,
_resolveManifestFunction(
mh.preExecHook, args.plugin, dependencies, ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
mh.preExecHook,
args.plugin,
dependencies,
false,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
),
_resolveManifestFunction(
mh.postExecHook, args.plugin, dependencies, ManifestAssociatedFunctionType.NONE
mh.postExecHook, args.plugin, dependencies, false, ManifestAssociatedFunctionType.NONE
)
);

Expand All @@ -740,6 +755,7 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
mh.associatedFunction,
args.plugin,
dependencies,
false,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
)
);
Expand All @@ -760,6 +776,7 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
mh.associatedFunction,
args.plugin,
dependencies,
false,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
)
);
Expand Down Expand Up @@ -939,13 +956,18 @@ abstract contract PluginManagerInternals is IPluginManager, AccountStorageV1 {
ManifestFunction memory manifestFunction,
address plugin,
FunctionReference[] memory dependencies,
bool allowDependencyType,
// Indicates which magic value, if any, is permissible for the function to resolve.
ManifestAssociatedFunctionType allowedMagicValue
) internal pure returns (FunctionReference) {
if (manifestFunction.functionType == ManifestAssociatedFunctionType.SELF) {
return FunctionReferenceLib.pack(plugin, manifestFunction.functionId);
} else if (manifestFunction.functionType == ManifestAssociatedFunctionType.DEPENDENCY) {
return dependencies[manifestFunction.dependencyIndex];
if (allowDependencyType) {
return dependencies[manifestFunction.dependencyIndex];
} else {
revert InvalidPluginManifest();
}
} else if (manifestFunction.functionType == ManifestAssociatedFunctionType.RUNTIME_VALIDATION_ALWAYS_ALLOW)
{
if (allowedMagicValue == ManifestAssociatedFunctionType.RUNTIME_VALIDATION_ALWAYS_ALLOW) {
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/IPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct ManifestExternalCallPermission {
struct PluginManifest {
// List of ERC-165 interfaceIds to add to account to support introspection checks.
bytes4[] interfaceIds;
// If this plugin depends on other plugins' validation functions and/or hooks, the interface IDs of
// If this plugin depends on other plugins' validation functions, the interface IDs of
// those plugins MUST be provided here, with its position in the array matching the `dependencyIndex`
// members of `ManifestFunction` structs used in the manifest.
bytes4[] dependencyInterfaceIds;
Expand Down
Loading

0 comments on commit 6ecf507

Please sign in to comment.