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.

[3418 byte] By [reinierza] at [2007-9-19]
# 1

>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 ) ;

Why don't you run it as a seperate process rather than a thread? You would still need OS specific stuff, but you could monitor it and kill it. And it would be unlikely to kill the original process (especially if you add a security manager which prevents jni and exec.)

jschella at 2007-7-8 > top of java,Core,Core APIs...
# 2

I thought of this, but won't that top out at around 10 to 15 instances of the JVM or so, on an average modern machine (say, 700 to 1000 Mhz, with about 384 to 512MB of RAM?)

Also, how do you fire up a new process? The only way I know of is by execing 'java' or 'javaw.exe', which just sounds wrong.

reinierza at 2007-7-8 > top of java,Core,Core APIs...
# 3
Thread.stop() is deprecated, but you probably could use it to stop your plug-ins. If you put them in their own ThreadGroup, you may be able to contain the damage they do, kill them all and then try to clean up.
daneya at 2007-7-8 > top of java,Core,Core APIs...
# 4

Weird.

rogueThread.stop();

rogueThread = null;

System.gc();

drops CPU use down to 0, and reduces the memory footprint back down to the original minimum. In other words, seems to do all the required functionality.

I got the impression from the documentation explaining why stop/suspend/resume are deprecated that it wouldn't work unless the Thread was stuck in some kind of IO blocking call.

Thanks a bunch!

NB: Would anybody know of a code sample which won't respond to a stop and/or suspend? this quote from the deprecation explanation has me worried:

"It should be noted that in all situations where a waiting thread doesn't respond to Thread.interrupt, it wouldn't respond to Thread.stop either."

reinierza at 2007-7-8 > top of java,Core,Core APIs...
# 5
The problem with stop() and suspend() is not that they don't work, rather it is that they can leave the system in an inconsistent state.
daneya at 2007-7-8 > top of java,Core,Core APIs...