dev workspace: modules on the java classpath breaks the sandbox
See original GitHub issueDespite my best efforts to find things out before merging build changes (#4343), there are some things that are only coming out in the aftermath.
Excerpts from a recent discussion in #gestalt:
If the modules are in the main classloader, they’re not really modules at all at that point. Just code included in terasology. […] So for actual release use, module code (and resources) are not on the base classloader, except the engine module or any other built-in module. Ideally development runs would reflect this partially because it would help detect security related issues and partially because some subtle behavior differences from having a slurry of module code in the base classloader
I think two things come from this:
- Empirically confirm how broken things are. This might be as straightforward as: edit a module so it imports something it shouldn’t, run
gradlew game
and Run TerasologyPC with that as a local subproject, see if it succeeds at importing that thing (and maybe invoking a method on it or something). I think there may be a possibility that modules still get loaded by the sandboxed loader despite the fact that they would be available to the default loader if it asked for them directly, but that needs research to find out if it’s true. - Decide if we’re willing to compromise on this module security when running in a dev workspace. (If there’s a vulnerability, it probably applies to all subprojects present in
/modules/
and all their dependencies, whether present as subprojects or fetched as artifacts.)
–
keturn’s understanding of how this interacts with the security model:
The thing that prevents Terasology Modules from importing code that would give them capabilities they’re not supposed to have is the classloader used; when loading the module’s class, it handles the requests for the dependencies of that class, and may deny the requests that are not approved.
If the module’s class is loaded by the classloader that loads the trusted code (for engine & facade), no such restrictions are applied. If the module’s class is on the classpath, it may be loaded by that classloader.
Issue Analytics
- State:
- Created 3 years ago
- Comments:8 (8 by maintainers)
Top GitHub Comments
ah, #4347 is the follow-up to #4343 where I’m trying to figure out what to do with those PC facade dist tasks, and I was just coming to the conclusion that it’s okay (for now) if the behavior of those dist tasks does something weird when there are modules present because the real dist for publication isn’t made that way. 😅
at the moment, that’s not guaranteed to get you a zip that includes your module and all its (transitive) dependencies and keeps them off the classpath.
(that might have worked before #4343, except when it didn’t due to #4014.)
I have lots of lingering questions about our sandbox environment and gestalt-module and classloaders in general, but I believe what we want to do here is to provide a JavaExec option that works like the previous configuration: keep modules off the classpath.
I think that much is straightforward: we set up a Configuration that doesn’t have that dependency on
:modules
. (Now I have better appreciation of why previous iterations of this build configuration kept those dependencies on a separate Configuration.)The other half of the problem is making sure all the module-dependencies are someplace the module loader can find them. I don’t think RemoteModuleGatherer, with the way it hooks in to DependencyResolutionListener, is an approach I want to keep. We’ve seen it doesn’t work for all our use cases. And though DependencyResolutionListener is a public Gradle API, it feels like meddling in gradle internals in a way that’s not in line with gradle’s design as a dependency resolver and build system.
The thing closest to the expected behavior would be to have all the dependencies end up as jar files in
/modules/
.I’m interested in whether we can give the module loader a custom search path, because I’m a little worried about getting multiple versions of things left in
/modules/
across multiple runs, but I think that’s a detail we can work out later.Long term, because I have an “in for a penny, in for a pound” attitude when it comes to gradle, I think the answer involves changing the module build config so they mark themselves as some kind of “terasology-module” variant and we teach gradle that those shouldn’t be included in the runtime classpath, but I don’t think that’s the most expedient way to fix this regression.
My current hope is to do something like this:
project(":modules")
modules/
. Might need to do a little filtering so we really are only copying in modules and not their other allowed runtime java dependencies.I think that seems like an entirely sensible plan, I just need to look up the gradle methods for the first two steps. Gradle has had a way of throwing wrenches in my sensible plans before; we’ll see.
(Open to other suggestions if they have fewer loose wrenches or unknowns.)