I have plans to integrate scripting in the engine I'm working on now, but have bigger fish to fry with the code base at the moment. I prefer to use the standalone version of Rhino distributed by Mozilla. Not only is it a newer distribution, as Riven pointed out, it also seems to be more feature rich. I tried out the internal scripting engine over the weekend and was disappointed in the lack of documentation. I couldn't find a clear cut way to do things such as class shuttering (locking down what Java classes/methods are visible to a script) which may not matter in your scenario, but can be important if you plan to allow users to write custom scripts. There is a little more setup to do with Rhino, but it's nothing overly complex.

That being said, I've got a few work projects that utilize scripting to control application logic and found Rhino to be rock solid in real world use cases. I also recommend considering the approach mentioned by mwarner of exporting only classes that you want to be accessible to the engine. I usually take it one step further and write wrapper classes for the objects that I want to export instead of exporting the core objects directly. It has the advantage of added flexibility in respect to what the scripting environment can access.

Lol that's true. I'm a javascript n00b so I actually appreciate the java-styled javascript much better.

The benefit of javascript for me is being able to easily block access by untrusted users to the JVM and server computer, but still allow them to run scripts on my server.

I look forward to being able to take javascript code typed by someone in a browser and execute it on my server without fear that it can trash my Tomcat webserver JVM. For example I could use javascript to call java methods on my server which could fetch data from the database, and manipulate it on the server in javascript and send back the results to the browser.Or I could allow players in a game to program their own AI in javascript and then execute it on my server in-game.

Using janino (http://docs.codehaus.org/display/JANINO/Home) and real java rather than javascript would be better but I don't know how to properly restrict access to the sensitive libraries in the JVM from malicious users.I've tried to learn about java's security policies but everytime I try it seems far too complicated. I also remember how Riven ran the tiny code program competition and challenged you to hack it and somehow you did. Since Riven overlooked whatever hole you found in his security, I've decided to not even try.

But with Nashorn/Rhino/Javascript I can easily block out the dangerous bits of java so there's no calls to System.exit() etc.

BeanShell is much more popular than Janino for some reason, but I think it's much worse since it's slower.Janino converts code into real java classes that run as fast as any other java code. BeanShell is interpreted and slow.

I don't know how to restrict classloaders for that purpose, I assume it's through using SecurityManager which I'm yet to figure out. Also I think that Apache Tomcat (and most java webservers) do their own magic with classloaders which might make it even harder.

I use BeanShell because I want to execute the scripts directly, not compile them in which case, I would have used normal Java. Also BeanShell is not slow, it is used in David Brackeen's book Developing Games in Java and more importantly while creating a 3D software renderer, and the code performed at 70-80 fps on my old laptop with no graphics card.

Janino compiles and runs the script, there's no disadvantages of using Janino, only the benefit of it being faster.

About your example that ran a 3d game, I doubt the entire game was written in BeanShell or else the FPS would be very low. I'm guessing that BeanShell just called the update method and the rest was done in normal java and openGL, so the bottleneck was not the scripting, in which case it wouldn't matter what scripting engine you use.

I also remember how Riven ran the tiny code program competition and challenged you to hack it and somehow you did. Since Riven overlooked whatever hole you found in his security, I've decided to not even try.

Don't draw too many conclusions from that. I decided to do it the easy way at the time, by not allowing capitals in the sourcecode. This did the trick surprisingly well, except that Abuse found a class in the JRE that didn't adhere to the Java naming conventions and the method call halted the JVM. How lucky he was

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

Janino compiles and runs the script, there's no disadvantages of using Janino, only the benefit of it being faster.

Yes, I think @SHC is missing the point of Janino. I use it in Praxis LIVE so that users can write custom components on-the-fly, that run at the same speed as anything built in.

Janino does have a disadvantage though, in that you're pretty much stuck with Java 1.4 source code features. There's a few things I have planned for the future that might require things like annotations. Now, there is a Janino interface for javac as well, that handles all the in-memory class loading, expression wrapping, etc. - the only problem is that it requires the user to have a JDK.

Hence, I spent yesterday afternoon refactoring javac and the Janino JDK interfaces into a stand-alone compiler lib. Working so far, though a fair bit more testing to do. Weird coincidence this thread!

... would be better but I don't know how to properly restrict access to the sensitive libraries in the JVM from malicious users.

In many ways if we're talking about end-user scripts I'm less concerned about that (unless you're promoting distribution of course) - let them break their own stuff! I would love to find a good way of controlling things like infinite loops, without adding loads of extra overhead / memory inconsistency.

... would be better but I don't know how to properly restrict access to the sensitive libraries in the JVM from malicious users.

In many ways if we're talking about end-user scripts I'm less concerned about that (unless you're promoting distribution of course) - let them break their own stuff! I would love to find a good way of controlling things like infinite loops, without adding loads of extra overhead / memory inconsistency.

Ah I see, your application runs on the client's machine.I want to run code on my server that the client submits, so I'd like a way to restrict what they can do. I ws reading about SecurityManagers but they seem to restrict the whole JVM. I'll have to look into Roquen's suggestion of using ClassLoaders.

About the problem of infinite loops, I was reading a while back that it can be mathematically/logically impossible to tell if a program will ever stop. But I guess by having a timer you could just terminate a thread that ran for too long.

I want to run code on my server that the client submits, so I'd like a way to restrict what they can do. I ws reading about SecurityManagers but they seem to restrict the whole JVM. I'll have to look into Roquen's suggestion of using ClassLoaders.

Ah, I see you like playing with fire!

The Janino ClassLoader already has the ability to provide a ProtectionDomain for classes compiled through it. That would appear to be the way to do this, but I've never tried.

About the problem of infinite loops, I was reading a while back that it can be mathematically/logically impossible to tell if a program will ever stop. But I guess by having a timer you could just terminate a thread that ran for too long.

Exactly. The timer issue is that you then need a second monitoring thread, which potentially brings in thread switching issues - in particular one thing I'm looking at doing at the moment is live coding audio DSP. Extra threads could be an issue there.

The bigger thing is what to do with a thread stuck in a loop. Call stop() on it? That would have to be very carefully thought out if anything's shared. Would have thought that would be even worse for you - could have more serious effects on a server!

Hmm, interesting problem about the thread stopping. I guess Thread.interrupt won't work in an infinite loop. I've never used it but how about byte code injection? That seems to be a way of adding arbitrary code over the top of someone else's code. Maybe you could inject some code that checks a flag at the start of every loop to see if the thread should die?? Another thing, why is it an issue for you if your user breaks his own program by making an infinite loop?

On preventing run-away scripts. An other option is to do code weaving and have the script itself bail if it taking too long. If you've never goofed with compilers this might be too much of a time commitment. Luckily with janino (or javac framework) you can manipulate the AST instead of asm. The upside is that you could do other code inspection and weaving. Say disallowing most calls of 'new' or whatever else.

Humm...I'm not familiar with the ProtectionDomain class and glancing at the source it looks like it would take longer for me to figure out than just writing a classloader. If this notion isn't clear...shout out.

Another thing, why is it an issue for you if your user breaks his own program by making an infinite loop?

Simply that it isn't very user friendly! Praxis LIVE is a graphical patcher / dataflow environment where you can add fragments of code (Java, GLSL, etc.) to the processing graph at runtime. The idea is that you can incrementally change and back out code as it runs. Entering an infinite loop would completely stall the media pipeline, forcing a restart and losing some changes. If someone writes a while(true) loop without thinking, they get what they deserve - as you implied, some infinite loops are more subtle.

I may consider a protected environment, probably as Roquen suggests using AST manipulation rather than byte-code manipulation, if I can get it to run without losing too much performance. It's not a high-priority though.

With serverside 3rd party code, you have to not only worry about cpu-cycle consuming runaway scripts. Memory consuming scripts are much more dangerous, because you basically can't gracefully recover from code like this:

1 2 3 4

Strings = "";while(true) {s += " ";}

as random, unrelated, critical code will start throwing OutOfMemoryErrors - it will very likely pull your service down when the GC panics, and maybe even the entire server, due to excessive swapping.

With ASM, you can rewrite bytecode to intercept every new and anew instruction, and manage the allocation count your script is allowed to reach. It's not easy to make this water tight, because almost all the JRE classes expose methods that do allocations behind the scenes (like StringBuilder.append, as per the above example)

I'd propose the 3rd party code to run in a separate, bolted down JVM, which can be nuked from orbit when it misbehaves. Not very practical, but what ya gonna do. With a bit of trickery, you *could* use MappedByteBuffers to share a read-only view of your business objects. (if they are backed by buffers - where are structs when you need 'em)

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

I suppose a small plug for Starsector (formerly Starfarer) would not be entirely inappropriate here, given its use of Janino in its scripting & extensive modding support.I don't know if Alex (the game's creator) frequents these forums, but he could undoubtedly cast some valuable light upon the usability & security of using Janino in this scenario.

@Riven's comment: This is related to disallowing almost all 'new' invocations in user scripts (the almost part is to allow things like boxing). Have all instances come from SDK calls. Disallow StringBuilder and StringBuffer in the script classloader. In fact disallow pretty much every class that isn't from the SDK (the SDK's classloader can handle arbitrary classes) and required for basic operation.

On code weaving: I was initially thinking of weaving in a method call (which checks for timeout and tosses an exception if needed) at the entry of all user defined methods (at least to start with...you can get clever later) and at the top of loops. But if your inspecting for user-defined loops...you could just disallow them and only allow iterating on SDK provided collections.

You could create a callback prior to every new, newarray, anewarray, multianewarray, invoke*, goto, goto_w, if*, if_*, jsr, ret and athrow though. That way you can be reasonably sure you can intercept a runaway script, assuming that it can only create a limited amount of instances as you limit the number of instructions that can be executed, without being at the mercy of the OS thread scheduler.

Anyway, this is getting a bit offtopic.

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org