Running a Neko Module in a Sandbox
It is sometimes necessary to dynamically load and run untrusted neko modules, such as server plugins. Haxe makes it possible to do this without putting your server at risk. This is done by restricting what library functions the module can call. The restrictions only affect the untrusted module, and only prevent it from calling specified library functions.
Create the Untrusted Module
The untrusted module, Plugin.hx:
// file Plugin.hx class Plugin { public function new() {} public function doSomething1(fname) { trace(neko.FileSystem.stat(fname)); } public function doSomething2(fname) { trace(neko.FileSystem.deleteFile(fname)); } }
The module makes a call to "neko.FileSystem.stat()" and "neko.FileSystem.deleteFile()." In this example we'll allow the call to "stat" but prevent the call to "delete." Compile it with
haxe -neko plugin.n Plugin
Create the Server Application
Create Main.hx in another directory. Copy plugin.n to the new directory.
// file Main.hx import neko.vm.Loader; import neko.vm.Module; class Main { static function main() { var outOfSandbox = function(f:Array<Dynamic>):Dynamic { throw "sandbox exception"; } var loadPrimitive = function(name:String, nargs:Int):Dynamic { if (name == "std@file_delete") return Reflect.makeVarArgs(outOfSandbox); return Loader.local().loadPrimitive(name, nargs); } var safeLoader = Loader.make(loadPrimitive, Loader.local().loadModule); var module = safeLoader.loadModule("plugin"); var classes : Dynamic = module.exportsTable().__classes; var plugin = Type.createInstance(classes.Plugin, []); plugin.doSomething1("testfile.txt"); plugin.doSomething2("testfile.txt"); } }
The main program defines two functions. outOfSandbox simply throws an exception. It will be called in place of library functions that we decide the module should not call. loadPrimitive returns the desired functions if it is allowed, otherwise it returns the outOfSandbox function.
Then we create a custom loader using the loadPrimitive we defined and use it to load the "plugin" module. The module loading code above is based on an example from the book "Professional HaXe and Neko." Once we have the module, we call its methods to test the sandbox.
Compile with:
haxe -neko main.n -main Main
Create the file "testfile.txt" in the same directory. It's contents don't matter.
Run the Test
Run with:
neko Mai
The output should resemble
Plugin.hx:8: { mode => 33206, rdev => 20, size => 16, ctime => 2008-08-07 09:50:20, dev => 20, gid => 0, ino => 0, uid => 0, mtime => 2008-08-07 09:50:20, nlink => 1, atime => 2008-08-07 09:50:20 }
Called from <null> line 2
Called from Main.hx line 42
Called from Plugin.hx line 13
Called from neko/FileSystem.hx line 87
Called from Main.hx line 20
Uncaught exception - sandbox exception
The first line shows that the call to "stat" was successfull. The output below that shows that the sandbox exception was thrown in the "delete" call.