Skip to content

Tighten up module loading and custom command registration #1256

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

prvyk
Copy link
Contributor

@prvyk prvyk commented Jun 17, 2025

Garnet documentation says that custom command registration requires defining ExtensionBinPaths.

This isn't what the code actually does. If no path is defined, a user can give an absolute path and the module/command will be loaded just fine if user has admin permissions or ACL is not set up.

It's a dangerous ability since user can load code to run under the server's context, and therefore I believe should be more restricted.

This PR:

  • Adds a check to ensure module loading is disabled if paths are not defined. This is overriden when --loadmodulecs command line option is used.

  • --loadmodulecs did not check module signature, which seems counterintuitive and unnecessary. The option text doesn't mention this, there's a switch to enable loading unsigned modules so the expectation is opposite, anyone who could add one option can add another, and Garnet should have a safe default. Also, change option text to be more descriptive.

  • Add supports to redis's enable-module-command directive for compatibility, though the default is to only use Garnet's restriction mechanism. Add to redis.conf import test. It works same way as enable-debug-command: Access to commands MODULE and REGISTERCS is limited by connection type. Default is 'yes' (no limit except by ExtensionBinPath), and other options are 'local' (only for local connections) or 'no' (disable the commands entirely).

  • Since I was already touching the same file, add support for DEBUG LOG for testing use.

@prvyk prvyk force-pushed the enablemodulecommand branch from c63f457 to 908b46c Compare June 17, 2025 10:23
@TalZaccai TalZaccai self-requested a review June 17, 2025 21:11
@TalZaccai
Copy link
Contributor

If no allowed bin paths are specified, no user should be able to register anything, so it is in fact disabled by default.
Which user should be allowed to run a specific command should be defined in the ACL.
I don't understand why we need this extra configuration parameter...

@prvyk
Copy link
Contributor Author

prvyk commented Jun 18, 2025

If no allowed bin paths are specified, no user should be able to register anything, so it is in fact disabled by default.

Ah, that's the intent? Because this doesn't work. Just use an absolute path for the module command (when this allowed bin path isn't defined at all) and Garnet will load anything.

I don't understand why we need this extra configuration parameter... Which user should be allowed to run a specific command should be defined in the ACL.

Because the other mechanism didn't work and I wasn't sure if this was intentional. Also, ACL is disabled by default. The current situation is that module loading is enabled by default so long as the user uses an absolute path. (Also the extra parameter is used in redis and it's a bit different type of blocking)

Can I pivot this part to fixing the bin path check? My suggestion:

  1. Fix the path check to disable anything when path is not defined, unless --loadmodulecs is used.
  2. Keep the new 'check signatures for loadmodulecs option'.
  3. Keep the new parameter for redis compat, but change it to allow by default and hide it.

@TalZaccai
Copy link
Contributor

TalZaccai commented Jun 18, 2025

If no allowed bin paths are specified, no user should be able to register anything, so it is in fact disabled by default.

Ah, that's the intent? Because this doesn't work. Just use an absolute path for the module command (when this allowed bin path isn't defined at all) and Garnet will load anything.

I don't understand why we need this extra configuration parameter... Which user should be allowed to run a specific command should be defined in the ACL.

Because the other mechanism didn't work and I wasn't sure if this was intentional. Also, ACL is disabled by default. The current situation is that module loading is enabled by default so long as the user uses an absolute path. (Also the extra parameter is used in redis and it's a bit different type of blocking)

Can I pivot this part to fixing the bin path check? My suggestion:

  1. Fix the path check to disable anything when path is not defined, unless --loadmodulecs is used.
  2. Keep the new 'check signatures for loadmodulecs option'.
  3. Keep the new parameter for redis compat, but change it to allow by default and hide it.

Yeah if that's the case that's a very bad oversight on our part...
From a quick look it seems like in ModuleUtils.LoadAssemblies you need to return an error even when allowedExtensionPaths is null. (so if (allowedExtensionPaths == null || binaryFiles.Any(f =>...)))

@prvyk prvyk force-pushed the enablemodulecommand branch from 74f573f to 2370631 Compare June 18, 2025 04:13
@prvyk
Copy link
Contributor Author

prvyk commented Jun 18, 2025

If no allowed bin paths are specified, no user should be able to register anything, so it is in fact disabled by default.
Can I pivot this part to fixing the bin path check? My suggestion:

  1. Fix the path check to disable anything when path is not defined, unless --loadmodulecs is used.
  2. Keep the new 'check signatures for loadmodulecs option'.
  3. Keep the new parameter for redis compat, but change it to allow by default and hide it.

Yeah if that's the case that's a very bad oversight on our part... From a quick look it seems like in ModuleUtils.LoadAssemblies you need to return an error even when allowedExtensionPaths is null. (so if (allowedExtensionPaths == null || binaryFiles.Any(f =>...)))

Did this. Left an opening to specify an absolute path via --loadmodulecs. If you can start a server you have the same permissions anyway, so it's not a hole?

Without looking at the git history, I suspect that's the underlying cause: --loadmodulecs was left open as much as possible (to make testing modules easier?), but opening that path accidentally opened all the module loading paths.

@prvyk prvyk force-pushed the enablemodulecommand branch from 3f8ad32 to 83560d2 Compare June 18, 2025 10:36
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.

2 participants