From within my java application, I have a requirement to run some untrusted code which is uploaded by a user. This can be done in a similar way to here:
Java security: Sandboxing plugins loaded via URLClassLoader
However, let's assume I have many users (each with a thread), and many users uploading untrusted code at the same time. Using System.setSecurityManager once before their code is ran to lock down the permissions, and then once again after is no longer going to work, as it is possible that multiple threads are calling this method at the same time (For example, thread 2 just starts the method and sets the security manager to the sandbox version, just as thread 1 sets the security manager to the all allow all security manager), and we have a problem.
To make this a bit more tricky, there are several different objects, lets just call them User objects, so if I make a synchronised block:
synchonize(this){
// set security manager lockdown permissions
// run untrusted code
// set security manager all permissions
}
This almost works apart from the fact that this is synchronized using the object (many threads cannot be inside this method, for this object particular at the same time).
What I ideally need to do is say, for all objects of this type (static?), synchronise this block. Therefore, locking out all users from using this block until it finishes. That's OK, these users can wait.
Therefore, I can imagine this working, but I don't know if it does exactly what I expect.
synchronized(User.class){
}
My question is, does all of this sound correct, and is it a sensible way to do it? I use timeouts etc (to avoid potentially the untrusted code hanging).
I would test this, but it is actually not very easy to test, and it seems rather complex (usually, when I find I am doing something overly complex, it's because it's not what I should be doing). So before I go rampaging in on this one, does the above seem correct, or am I missing something obvious?
Edit: More info:
@edharned. A little more about what is happening here may help. The server has a set of JUnit tests, the user uploads some work, the server executes the JUnit tests, but wants to do so safely. The JUnit tests are not called in a new process, but instead are ran from within the main (and only) JVM. This is so JUnitCore can be used and the calling method can work out how many tests there were, and which/how many failed using the Result object (http://junit.sourceforge.net/javadoc/org/junit/runner/Result.html) and the run listener. If these tests are ran from a new process using junit.textui.TestRunner then I believe it only shows which tests failed (and not which passed).
Perhaps the solution is to run each in it's own JVM which can have certain privileges set using a security manager which is set from within the JUnit test class itself. However, there is now a new problem which is retrieving the test results (Which passed, which failed and with reasons).