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

Godot sandbox & modding support #7753

Closed
touilleMan opened this issue Feb 7, 2017 · 47 comments
Closed

Godot sandbox & modding support #7753

touilleMan opened this issue Feb 7, 2017 · 47 comments

Comments

@touilleMan
Copy link
Member

Introduction

Just coming back from GodotCon where I had a really interesting discussion with @Fabless about adding a sandbox feature in Godot. So here is a summary:

Godot with GDscript acts a lot like a web browser with Javascript: a core generic engine running on the user's OS and interpreting some higher level script code.

A cool feature about web browser is they enforce a sandbox pattern: no matter how bad or malicious the high level code is, it can never break you OS (well obviously as long as the sandbox doesn't have security hole !).

However, the big difference with web is a Godot application is provided to the user with both the Godot generic engine and the GDscript code. So one can just add any malicious code to the Godot engine distributed inside his game to trivially bypass the sandbox...

Considering this, the sandbox would be a way not to protect the user from the game developer (you install it software, so you trust him), but to allow out-of-the-box modding.

So the player would be able to download 3rd party mods, put them in a mod:// folder (this would shadow resources from res://) and have the guarantee that thanks to the sandbox only the game can break (just like if you download a bad chrome plugin, it can only mess with the webpages you consult - which is a lot scarier than messing with just a Godot game btw -, not with your entire OS).

@Faless stated this is a dangerous pattern to trust unknown code and so modding should be a feature developers add with custom code, allowing to modders only to change configuration instead of having access to the GDscript.

A quick search on the internet show that there is two way of adding mod into Unity: give full C# access (simple but dangerous way, chosen for example by KSP) or embed a lua interpreter and expose and API from there (see https://www.roguevector.com/category/mod-support/, https://forum.unity3d.com/threads/making-a-moddable-game.312490/ and https://forum.unity3d.com/threads/could-adding-modding-support-by-loading-modders-assemblies-create-risk-of-malicious-code.447879/)

While I agree trusting unknown code is never good, being able to advertise Godot as a game engine with modding for free seems a big argument given how many indie games tends to build a community around this feature (Factorio, KSP, Minecraft etc.).

In the end, the question is the complexity to add a solid enough sandbox mode for GDscript vs. the benefit of providing powerful-but-safe-enough modding out of the box (I guess we could even provide on the Godot assets site a generic Godot app mods manager which would list the mod available and start the real game with a --mod-path=... option configured accordingly).

@Faless thinks if available, this sandbox mode should be activated by default given most games would work pretty well with it and more security for the same price is always better ;-)

Implementation

The idea would be to have a switch in the project configuration to enable/disable sandbox mode for the project.

Enabling the sandbox mode would cause the following changes:

Stub OS singleton

OS singleton contains dangerous methods which allow to manipulate processes
such as:

  • execute
  • kill
  • shell_open
  • get_process_ID

I think we could create a new MethodFlags (like METHOD_FLAG_UNSAFE) to easily flag those methods so implementing a check during call would be trivial.

Limited load access

Sandboxed mode should only allow res:// and user:// style of path for open.
Beside, only user:// should allow write mode.
Path should be fully resolved before using it to make sure no malicious path (i.g. user://../../secret.txt) can go through the check.

@Faless thing this could still be a trouble given a malicious program could try to write tons of dummy data into the filesystem in order to break it.

We could add rules to limit the size of the files that could be wrote, but then we will have to deal with program doing intensive small I/O to stall the HDD...
This is too cumbersome from my point of view, beside my guess is messing with the HDD this way is really visible and given the attacker cannot steal or destroy any user's information it is a minor issue.

Shared modules

Modders should not be able to provide .so modules given those just bypass the sandbox and can do anything. For the moment this is not a concern but this should be taken into account with @bojidar-bg & @karroffel DLscript making it way to the master.
A solution could be to allow DLscripts only to be loaded from res:// (so mod:// can't)

Protect project settings !

We obviously have to make sure you can't temper the project settings when running it otherwise it would be trivial to disable the sandbox mode.

@reduz
Copy link
Member

reduz commented Feb 7, 2017 via email

@neikeq
Copy link
Contributor

neikeq commented Feb 7, 2017

  1. If you want to exploit Godot to do something malicious, you can do anyway, it's not that protected

And even if you protect it, someone will find the way to bypass your protection in no time. Not worth the effort IMO.

@bojidar-bg
Copy link
Contributor

I think, all we developers need to make modding is a quick and simple {GD,Visual,etc?}Script sandbox, and to be let to decide which classes and singletons it can access (globals must be separate for the sandbox). That should be enough for most cases, and in the worst situation you are going to have a global mocking each real class or something like it. (but, frankly, as long as the sandboxed content can't get access to File, ResourceLoader and Script classes, all should be pretty good)

@TeddyDD
Copy link

TeddyDD commented Mar 7, 2017

I would prefer white list rather than sandbox approach - basically a method to load script from user:// with custom defined API, singletons etc.

@zicklag
Copy link

zicklag commented Apr 19, 2017

I love @touilleMan's Sandbox proposal. Me and my group of upstart game designers have dreamed of designing games where almost any user could be a modder and have just as much power to control the game as the programmers who made it. In the last month, I have been experimenting with Godot and have been blown away by its awesome data model and how easy to use it was. It seemed to be the ideal model for allowing users to mod, where they could inherit from our base scenes, like guns, ordinances, and soldiers, and extend them with their own functionality if they so dared. Instead of having to provide a custom modding interface to the user, where they would only get a fraction of the power to change the game, I could just allow them to build scenes, using Godot, that could be dynamically loaded at run-time.

Or so I thought.

As I tried to implement this model, I ran into this very article, which pointed out that executing 3rd party, user GDScript wasn't actually safe for my gamer's operating system! I hadn't realized this security concern. This Sandbox proposal would exactly what I need.

I haven't contributed to Godot yet, but I would be willing to try and work on this feature as it is perfect for what I and my team are trying to accomplish in our games. Having to design a custom API or interface for the user to mod, would drastically increase the amount of work that I would have to put in while at the same time decreasing the ability the users had to improve their game. Having spent hour upon hour trying to use the painful modding interface of another FPS game, I am very acquainted with trying to improve or extend a game somebody else has made. For me and my team having the ability to expose the actual way we made the game through a safe mod interface, is worth almost as much as the game itself.

@zicklag
Copy link

zicklag commented Apr 20, 2017

I would like to start working on this issue, but I don't really have much of an idea where to start. I know Python pretty well and have done a bit of programming in Java, C#, and Javascript. I know programming concepts well, but I have no experience with C++ or the Godot engine. I would tremendously appreciate any help on implementing this. I've got the time and this is definitely in the critical path for my team, so I am going to start experimenting in my fork.

@avril-gh
Copy link
Contributor

Im not sure if developer who create commercial game with InAppPurchases are dreaming about his app being easly modded... Its rather nightmare.

@Calinou
Copy link
Member

Calinou commented Apr 20, 2017

Im not sure if developer who create commercial game with InAppPurchases are dreaming about his app being easly modded... Its rather nightmare.

The whole point of such a modding support is to make it optional, you could very much close it off you wanted.

@zicklag
Copy link

zicklag commented Apr 20, 2017

@touilleMan and @Faless,

I wanted to ask what you thought about the following high-level modding workflow. This is just my initial idea about the process you would use to design mods for a game using the sandbox approach.

Example

Say I have a simple game that looks something like this:

res://game.scn # The main scene
res://BasePistol/BasePistol.scn # A base scene for making pistols
res://BasePistol/BasePistol.gd
res://FastPistol/FastPistol.scn # An inherited scene based on BasePistol.scn

My goal is to have user be able to add mods that can inherit from scenes that are built into the game. For example:

mod://AwesomeMod/SuperPistol/SuperPistol.scn # An inherited scene based on BasePistol.scn

Optimally, you would be able to see files in the mod:// path from the editor in the FileSystem Dock, along with the files in res://.

To distribute the mod, the user could pack the mod://AwesomeMod/ folder into a .pck/.zip using the existing export options. To install the mod you could drop the .pck/.zip into mod:// which could be loaded using GlobalConfig.load_resource_pack(). load_resource_pack() would have to be restricted so that loading a resource pack from mod:// would not have the ability to patch files in res://.

In this example I am exposing the whole game source to the user, which a large majority of developers may not want to do. If you didn't want to expose the game source, you could have a project that contains just the base scenes or limited versions of the scenes that would be given to the user for a modding environment. When they package the mod they can then drop it in with the compiled version of the game where it would reference the full versions of the scenes. This is my least favorite part of the workflow, but I'm not sure if there is a better way to do it.

Notes

This is just my first draft of how this could work. I am open to suggestions and other ideas for how it could work.

@touilleMan
Copy link
Member Author

load_resource_pack() would have to be restricted so that loading a resource pack from mod:// would not have the ability to patch files in res://.

In the workflow I posted earlier, I proposed to have the mod://foo path resolve just like res://foo but with an higher priority (hence the game load the modded version of the resource).
A solution to control what could be modded would be to add a modable flag to resources, enabling such higher priority.
The trouble I smell is a modded script could be able to do monkey patching on regular resources, hence modifying them even if it is not allowed to... I don't think so far GDscript supports runtime modification of class (but it's the kind of feature that could appear and break the security without anyone knowing about...), but you could mess with the node instances parameters anyway.

In the end, I think the sandbox feature can be achieved to protect the user's computer from untrusted code running into Godot but it cannot help protecting vanilla game's assets&code.
The reason is what a mod can modify is really game-specific so providing a generic way to do that would be too complexe to implement and cumbersome to use.

@zicklag
Copy link

zicklag commented Apr 21, 2017

In the end, I think the sandbox feature can be achieved to protect the user's computer from untrusted code running into Godot but it cannot help protecting vanilla game's assets&code.

I definitely agree with that. I believe that it is simply a risk that the user takes when installing a mod that it could potentially do funky stuff to the game.

...Now that I am looking back at your previous post, I just realized that you meant to restrict all scripts in the game, because most games would run just fine with the sandbox restrictions.

Actually, the reason that I was worried about patching res:// was because I was thinking that you would only restrict mod:// scripts. Before Godot runs a script, it would check it's resource path and put the script in sandbox mode if necessary. That way, any code in res:// would have the full GDscript API while any code in mod:// would have the limitations that you mentioned. This would be even less intrusive for developers because it doesn't change anything for res:// code.

I haven't checked out out the current implementation for running scripts, though, so I am not sure how easy that would be to set up. Restricting all scripts would probably be easier.

@zicklag
Copy link

zicklag commented Apr 25, 2017

I have so far, in my fork, added a new resource path mod:// by adding the necessary code to the dir_access, file_access, and the different os classes to provide for a path nearly exactly like user:// with a different location on the operating system.

My next task is to load the mods:// path into the filesystem dock in the editor. After looking at the classes in filesystem_dock and editor_file_system, I saw that a lot of the code was specific to the res:// path and I was having a hard time refactoring it to work for both res:// and mod://.

I'm not sure how much code there is that would have to be modified to accommodate such a change. Being that I don't know a whole lot about C++, it would be good if I didn't have to make a major re-organization of the involved classes. If anybody has any suggestions on how to do this, or maybe an alternative implementation, I would appreciate it.

There wouldn't be a good way to implement this as a module would there? I don't think so, but I'm not sure.

@godotengine godotengine deleted a comment Feb 12, 2018
@godotengine godotengine deleted a comment Feb 12, 2018
@godotengine godotengine deleted a comment Feb 12, 2018
@godotengine godotengine deleted a comment Feb 12, 2018
@godotengine godotengine deleted a comment Feb 12, 2018
@godotengine godotengine deleted a comment Feb 12, 2018
@godotengine godotengine deleted a comment Feb 12, 2018
@godotengine godotengine deleted a comment Feb 12, 2018
@godotengine godotengine unlocked this conversation Feb 12, 2018
@mhilbrunner
Copy link
Member

Have to agree with @willnationsdev and the others. AFAIK, most popular modded games have no sandboxes. Minecraft mods, Skyrim mods, you mostly depend on the mod authors. I think solid modding support is more important than sandboxing.

@EIREXE
Copy link
Contributor

EIREXE commented Feb 12, 2018

The biggest problem I can see with modding inside godot is that in order to use load() with resources you need to have them converted in the .import folder, which is a pain in the neck, for example, I have a system where content is divided in content packs and if I want to load an icon added by the user I have to do it manually using the Image classs.

It would be nice to have a way to load() stuff without having to import them first on runtime.

@mhilbrunner indeed, but it would be nice if there was a way to enable sandboxing, just as an option.

@EIREXE
Copy link
Contributor

EIREXE commented Mar 1, 2018

I returned here to tell you guys that godot already has modding support and I just didn't realise it, however it's currently broken in the editor because of #16798 , but in a game that uses PCKs for the base content it works perfectly 👌

@ElfEars
Copy link

ElfEars commented Apr 21, 2018

I think another important thing to discuss here is custom multiplayer data.

In many popular multiplayer games servers can host custom maps for players to play on and while I think that installing a mod being considered "at your own risk" is reasonable, I also think allowing players to play on player created scene files downloaded from a server without being at risk of having their system bricked or having to create a custom file format on a case by case basis is of reasonable interest

@zauberparacelsus
Copy link

As a note, the Mono Framework (which Godot 3.0 uses for C# support) has support for running untrusted code in a sandbox.

http://www.mono-project.com/docs/advanced/sandbox/

@EIREXE
Copy link
Contributor

EIREXE commented Apr 30, 2018

@ElfEars What you posted is already possible in Godot currently, however to test it in the editor #16798 should be fixed.

@Shadowblitz16
Copy link

Shadowblitz16 commented Apr 12, 2020

so what if the user wants to make a custom api and only allow certain functions and classes to be used?

for example if someone wanted to make a custom cos and sin function that uses turns or degrees?

I doubt anyone wants to expose their games nodes to the modding api.

what I see as ideal modding support is the following...

  • the ability to whitelist functions, classes and resources (by default they are all disabled)
  • the ability to run scripts that are limited to the above
  • the ability to mark resources to be imported/exported as json on game start.

@willnationsdev
Copy link
Contributor

willnationsdev commented Apr 14, 2020

the ability to mark resources to be imported/exported as json on game start.

Not sure how you would expect this to work. People can already configure autoloads that manually read a JSON file and stick their information into a data structure. Are you wanting some sort of utility that automates that process and creates globally-accessible read-only JSON Dictionaries as configuration for a project?

Identifying the best way of making JSON-based configuration easier to use sounds deserving of its own Proposal entirely to see if people think it's worth it to bake a utility like that into the engine rather than keeping it in a plugin.

the ability to whitelist functions, classes and resources (by default they are all disabled)
the ability to run scripts that are limited to the above

I like this idea, and it's been mentioned before, but the question remains: how would this actually be done in a clean way? You'd have to define a whitelist of symbols and accessible resources and then intercept every potential reference to them. Each language will have a different syntax for submitting those queries, so you either have to implement changes to each scripting language to support this behavior, or you have to write something in the core to accommodate it.

The core, however, would not make use of this behavior itself, so it doesn't really belong there. The best scenario would be some minimal alteration to the core to empower modules to more easily do the work, but even that is something devs might not want bloating the engine core.

Personally, I think the latter approach could work well, but the question to me is really how we would go about intercepting all of these function/class/resource references without overcomplicating everything.

@Shadowblitz16
Copy link

Shadowblitz16 commented Apr 14, 2020

@willnationsdev

the ability to whitelist functions, classes and resources (by default they are all disabled)

this could be a editor in the project settings

the ability to run scripts that are limited to the above

this could just be a simple GDScript("filename").run() or MonoScript("filename").run()

the ability to mark resources to be imported/exported as json on game start.

this would just be a right click menu on resource types to mark it as exported/imported json

@akien-mga
Copy link
Member

Feature and improvement proposals for the Godot Engine are now being discussed and reviewed in a dedicated Godot Improvement Proposals (GIP) (godotengine/godot-proposals) issue tracker. The GIP tracker has a detailed issue template designed so that proposals include all the relevant information to start a productive discussion and help the community assess the validity of the proposal for the engine.

The main (godotengine/godot) tracker is now solely dedicated to bug reports and Pull Requests, enabling contributors to have a better focus on bug fixing work. Therefore, we are now closing all older feature proposals on the main issue tracker.

If you are interested in this feature proposal, please open a new proposal on the GIP tracker following the given issue template (after checking that it doesn't exist already). Be sure to reference this closed issue if it includes any relevant discussion (which you are also encouraged to summarize in the new proposal). Thanks in advance!


This issue has a lot of relevant discussion, and reopening it as a new, summarized GIP would IMO be beneficial.

I think we should however have separate proposals for modding support in general, and sandbox which is relevant for modding but not absolutely necessary.

@ballerburg9005
Copy link

ballerburg9005 commented Nov 15, 2021

@ElfEars What you posted is already possible in Godot currently, however to test it in the editor #16798 should be fixed.

Please explain how Godot already has modding support and how you can load custom scenes (which of course by all odds must contain many new scripts as well), so you can e.g. create custom maps, monsters, mini-games, etc and distribute them on a server.

For all I know, if you did e.g. a Quake 1 clone in Godot, then you couldn't even really distribute community maps on a community server, since community servers and maps are both untrusted. They can contain custom scenes which may execute custom scripts. Even if you went through a third format, like using Quake 3 .map files, then the importer plugin "Quodot" requires you to import those maps into a new scene before Godot can make sense of them.

Any multi-player game needs community content to be successful. Even more so open source games, which thrive exclusively on community content like custom maps and especially unrestricted community servers. I don't see how this is possible in Godot currently. If you do it, right now you basically allow arbitrary code execution. So anyone can make a server and upload arbitrary code to your machine. What's the solution to that?

Thinking even beyond: maps nowadays aren't as simple as they were at the time of Quake 1. Maps are basically just custom environments, that will have new interactions and new content. In times of Quake, there were only polygons with textures as walls, and monsters with different models that all ran straight at you. It was very simplistic, hence maps were also simplistic. Now maps contain new interactible items at random, items that change the the environment and the player, intelligent behaviors of entities within them, environments within environments, API calls to things outside of the game and so forth. Maps without new scripts are most of the time only possible if you think of them in a very simple 90s-alike way. Community maps really really need script support, especially if thinking of what is, can be and will be important in the future.

@Calinou
Copy link
Member

Calinou commented Nov 15, 2021

For all I know, if you did e.g. a Quake 1 clone in Godot, then you couldn't even really distribute community maps on a community server, since community servers and maps are both untrusted

Quake 1, 2 and 3 don't use any form of sandboxing for custom content. In fact, Quake 2 mods are all about downloading native libraries (.dll/.so) that power mods when connecting to a server! Quake 3 isn't much better in this regard either, as the QVM used for mods has many known security vulnerabilities. (At least, it's platform and architecture-independent.)

Even if you went through a third format, like using Quake 3 .map files, then the importer plugin "Quodot" requires you to import those maps into a new scene before Godot can make sense of them.

It's technically possible for something like Qodot to run in an exported project, but I'm not sure if it can do that. It's likely relying on editor-functionality right now.

Thinking even beyond: maps nowadays aren't as simple as they were at the time of Quake 1. Maps are basically just custom environments, that will have new interactions and new content. In times of Quake, there were only polygons with textures as walls, and monsters with different models that all ran straight at you. It was very simplistic, hence maps were also simplistic. Now maps contain new interactible items at random, items that change the the environment and the player, intelligent behaviors of entities within them, environments within environments, API calls to things outside of the game and so forth. Maps without new scripts are most of the time only possible if you think of them in a very simple 90s-alike way. Community maps really really need script support, especially if thinking of what is, can be and will be important in the future.

Server-side modding makes this all possible. When only the server is running executable code, the clients aren't taking any risk by connecting to it. This is the approach taken by games like Minetest. (Client-side modding is available, but servers can't deliver client-side mods to clients, so clients have to install those unrelated mods manually.)

Either way, your concerns would likely be addressed by godotengine/godot-proposals#389, so the discussion should be continued there instead.

@theraot
Copy link
Contributor

theraot commented Jul 29, 2022

It looks like we have come a long way since "this is pointless": godotengine/godot-proposals#5010

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

No branches or pull requests