Hardened (LUA) Scripting useable in JME

After searching around on how to do safe scripting in jme, allowing unsafe user supplied code to executed, I decided to give it a try and share with the world :slight_smile:

Basically this is the LuaJ project extended and adjusted for the use of unsafe scripts. Mainly this means removing everything that might escape the Interpreted sandbox, and secondly removing everything that might hog large amount of ressources (eg while true do print(‘lolololo’) end)

My motivation for this is to have smaller programmable parts in my spacegame, in the current Testszenario it is to allow long time players to adjust the bahaviour of a door in the spaceship.

Of course I see various different uses for this in other games
-> Programmable blocks in a blockworld
-> In game editor for a platformer (eg triggers for elevators)
-> Mod/Addon extension points
-> Or simply to quickly hack a prototype of a gameitem together in unity style.

Why lua?
-> Functions are first class objects, allowing for a reflection like logic and a very powerfull logic (callbacks ect.)
-> Lua can be used like a OO language, when providing the correct metatables
-> Many (non programmer)people know lua due to modding/playing around with CryEngine/Garrrysmod/Freelancer or other game engines.
-> Lua has no insane logical flaws (eg basic wich uses user provided line numbers for goto)
-> Many of the JVM embedded scripting languages are really powerfull (javascript for example), but nearly impossible to secure in terms of ressource hogging. Using a strictly interpreted languages (javascript in JVM compiles to native by default) allows vetos and limits enforced by the interpreter.
-> The Java based interpreter is fast, with comparable performance to the c one (some test cases are even faster).
-> The interpreter is really lightweight and having several hundered instances open is not costing much memory.(in my game I need around 300-900 instances running on one server)

-> The ability to have pausable Coroutines, one of my plans is to allow user scripts to create (a limited amount of ) worker Coroutine, that simply pauses when reaching the instruction limit, and will be continued in the next game tick.

local friends={'empire','jmonkeyrulez'}

local duser
local ddoor
function canOpenDoor(user,door)
  --reduce cost of canOpenDoor as it might have a very low limit, and do work in the higher limid tick call
  door.processing()
  duser = user
  ddoor = door
  
end

function tick()
  if ddoor and duser then
  print("Testing user " .. duser.name);
    if table.contains(friends, duser.name) then
      ddoor.open()
    else
      ddoor.deny()
    end
    ddoor = nil
    duser = nil
  end
end

Last but not least, I’m always happy to recieve feedback,
-> Be it unhandled security holes
-> Improvements in the limit handling
-> Common usecase java side functions to reduce interpreter cpu consumption
-> Others interested in using/embedding this into their games.Garrrysmod

12 Likes

So I finally got time to continue this a little.

-> New is the support for coroutines that pause at instruction limit.
-> The coroutines needs to be controlled by the game, and are
User level coroutines are not allowed due to security reasons (eg Thread spamming)

Eg the following code is now save and cannot anymore block the Host when using this:

local tickcount = 0;
function tick()
  while true do
    tickcount = tickcount +1;
    print("inner loop " .. tickcount);
  end
end

And this is all necessary to do
[java]
final LuaClosure tickHook = (LuaClosure) globals.get(“tick”);
final LuaThread tickWorker = new LuaThread(globals, tickHook.checkfunction());
tickWorker.resume(LuaValue.NIL); // tick 1 is expected to be immidiatly put to sleep,as no limits are yet configured
final InstructionLimit coroutineInstructionLimit = InstructionLimit.instructionLimit(tickWorker);
coroutineInstructionLimit.setMaxInstructions(50); //yield coroutine after 50 instructions
coroutineInstructionLimit.setMaxStringSize(100);

while (true) { //this would be replaced by simpleUpdate (or similar)
final Varargs returnValue = tickWorker.resume(LuaValue.NIL);

		final LuaValue processedWithoutError = returnValue.arg(1);
		if (processedWithoutError.isboolean() && !((LuaBoolean) processedWithoutError).v) {
			System.out.println("Terminating long running Task due to error " + returnValue.arg(2));
			break;
		} else {
			InstructionLimit.reset(tickWorker); //reset the instruction counter for the next tick
		}

	}

[/java]

Well, maybe i can help you with that.

I did some games with lua (one solo only, and an other with a client-server implementation).
(solo : http://sourceforge.net/projects/yuu/)
(multi: http://sourceforge.net/projects/realgame/)

you’ll likely not be able to make the multi run, as i didn’t release something usable directly (but i am still working on it).
The solo game is ok, but have a look at the mapping in the wiki before playing.

Lua is pretty cool, luaj is awesome. But if i can give you an advice, i’ll say : implement a system to have the possibility to associate a function to an event.
For exemple “onLook”, “onWalk”, “onActivate”, “onTime” etc.
Lua-side, you have something like

The idea is to have something like the relation between javascript and html.
Create a toolbox (a set of class that provide function for basic actions, like adding an object, move it, add item to inventory etc.) and give it to your script. In that toolBox, you have function like this
“addOnLook(Spatial spatial, Function function)”
When function is called, you give it a parameter which is a map with several fields like the time when the event occurs, the player/creature that triggers the event, the spatial on which the event is triggered etc.

You get something easy to use (like javascript) and powerfull (like scripts in elder scrolls).

If you plan to unloads objets and scripts (for exemple you want to restart a level and reset everything on it) juste make sure that every script is tagged with something (like a unique number associated to the level) so you can discard things like “onTime” etc. when they are no longer relevant.

Also, java comes with a javascript interpretor, so it could be interesting to give a look to it.

The big advantage to this is that is suit well with a multiplayer approach (you just change the “addItem” method from the toolbox for exemple).

1 Like

Hi,

i actually started with the javascript engine and other languages for it,
but due to the fact that they work nativly you cannot supervise them good.

Thats why I ended up with luaj, sinc eit has a pure interpreter mode it can be easily supervised, and passing java calbacks to the scripts as a LuaFunction is pretty straightforward.

Also it has no problem in running multiple instance simultanously on different cores.

I am thinking on making available javascript and lua (may be yours one). I will use javascript (lua syntax puts me away, I wonder if they could make it more javaistic or c++istic), but users will be able to use lua too.

So basically, javascript can be restricted to prevent unwanted user access as much as lua right?

but if user codes something weird (some mistake or code overlook), in java script it will be a problem but in your lua mod this problem can be minimized (I guess it will also warn user about the problem he created) right?

Basically prevent bad calls is only half of the win. (And the part that can also be done with Javascrip easily enough)

But just imagine the simple script while(true)
Without some kind of hypervisor function, like the luaj modification allows, you are unable to pause this script without a full termination. Also memory limits are a necessity if you want to prevent your sever from being crashed.

I found no possibility to do both of this with the javascript engine (or basically any of the jvm scripting engine stuff, as I need to be able to tap into the core interpreter loop for this. This is the reason I use luaj as a basis.

Anyhow what eaxactly is the problem with lua syntax, maybee i can help a bit with this.

wait wait! you mean you will allow users to run their lua scripts on your server? if is that… cool! :D, now I see a very strong reason for your lua fork. :slight_smile:

The problem is not the lua syntax, is I getting used to think in the way of coding in it :>
I program in C++, Java, Bash (and if I stay too long in bash, I type some bash in java :frowning:
So basically, the problem is that I dont want to get used to lua, and try to think and code back in java, I saw a bit how lua logic is and didnt want to learn more to not confuse me with other languages, may be some day I should take more time with it and see if I can learn it without messing my other codings thinking…
Ex. also, if I code too much in java script, I mess things a bit in java :(, javascript is too permissive…