Shutting down rogue threads: impossible?
While designing a system that accepts 'plugins' that are sent by untrusted users, I ran across this problem:
Imagine a malicious user intentionally sends this plugin:
public void init()
{
int[][] a = new int[123456][10]; //allocate tons of memory.
while ( true ) ; //waste tons of CPU cycles.
}
I want to 'defend' against this kind of thing, whether done intentionally or not.
So far, I have found out the following things:
A) There is no java-based profiler information. In other words, there is no such thing as a thread.getCpuLoad() kind of method. There is the JVMPI, so for now I guess I'll write various JNI libraries that will make the JVMPI interface callable from java.
B) Even if the thread is identified, there is no way at all to destroy it. Thread.destroy() is unimplemented (returns NoSuchMethodError). Thread.suspend() still works, eventhough it is deprecated, and will stop a thread when doing something like while ( true ) ;. However, I have not found a way of reclaiming any allocated memory. Removing all references to the thread object and then running the garbage collector didn't help.
C) There does not appear to be any thread kill functionality in JVMPI, though I might have missed something.
D) There does not appear to be a relatively simple way to start up a new 'lite' JVM to run the untrusted code in. Starting up an entire new java executable through Runtime.getRuntime.process() might work, but the endgoal is to get tons of these little plugins running in their own threads. One JVM can actually handle this admirably, but I doubt one system can handle 70 to 80 concurrent JVMs.
leading me to the conclusion:
There is no way to really 'sandbox' untrusted code. Even if you can prevent them from opening files and such, they can perform a DoS attack bij allocating large amounts of memory and getting stuck in while ( true ) ; loops. Even if this behaviour is detected, there is no way to guard against it happening aside from suspending the thread and accepting the memory as unreclaimable until the JVM is restarted.
I *really* hope there is a better solution than suspending and writing off the used memory, but if there is no way to really kill a thread, perhaps this can be worked on ASAP for the next release? destroy() exists. It needs implementation.
Incidentally, there is no risk here of contaminating the state or causing deadlocks due to monitors being locked 'forever', as each such 'plugin' uses its own loader and cannot exchange data between the main system or any other plugin, except through serialized/deserialized stuff. While I understand the dangers of just cutting threads off, in this case, I have already taken precautions that one 'plugin' can't mess in any way with another.
I did a 'test run' and wrote exactly such an applet. While it didn't hang the web-browser (Opera), it did cause Opera to use up all free CPU cycles, and there was no way to stop Opera from using up all CPU (or reclaiming the memory), short of completely exiting the browser.
Didn't test with IE, or netscape.
(That's Opera using JDK1.4 as JVM).
I could of course be mistaken in all this and completely missed a way to completely kill an unresponsive thread, so I am hopefully awaiting corrections.
--Reinier Zwitserloot.

