Stopping Hostile Threads in JVM - java

I'm writing a server, which may be running hostile code. To prevent an attacker from throwing a thread into an infinite loop, I want to enforce a one-second execution time limit.
An InterruptedException can be caught inside an infinite loop, thus allowing an attacker to retain control of the thread. Thus Thread.interrupt() is not an acceptable solution.
My current implementation prevents hostile threads from acquiring any resources (including locks), uses Thread.stop() to terminate execution, and reverts any changes made by the thread. My main complaint is that it uses the deprecated Thread.stop() method; I don't like using deprecated code.
I'm wondering if there is a more industry-accepted solution, short of launching/killing an entirely new JVM, which would have too much overhead for my purposes.

The only way to kill a thread is to use a separate process and kill that process. Thread.stop() throws a ThreadDeath error which can be caught and ignored. i.e. catch(Throwable t) {}
For more details on what Thread.stop() actually does Does Thread.stop() really stop a Thread?

You cannot guarantee that a thread can be stopped as several blocking methods (like sockets) do not respond to interrupt().
I would suggest a very strict security manager so you can be absolutely certain that the malicious code is sandboxed. If you need to be certain then consider a special classloader which ensures that only valid operations are being done.

Related

Does java provide a clean mechanism for ensuring thread shutdown logic runs when thread dies?

I'm wondering why there seems to be no support for thread level 'shutdown hooks', which run when a specific thread terminates; not when the JVM terminates.
So lets say someone wrote a simple thread with a run method with sudo code like this (intentionally leaving out thread interrupt here for now...):
public void run(){
SeverSocket serverSocket=new ServerSocket(port);
while(!isStopRequested){
Socket socket=serverSocket.accept();
processRequest(socket);
}
runShutdownLogic();
}
public void stopServer(){
isStopRequested=false;
//interrupt thread potentially, see below
}
This thread could die in a few ways:
someone calls stopServer, followed by either...
a. the serversocket.accept accepting one last socket and returning
b. an interrupt sent to intterupt serverSocket.accept
an exception is thrown
Someone kills the thread, directly or through executor service.
The JVM goes down.
In any of these cases we want to run the shutdownLogic method, lets say it does something more then just close the seversocket, some interface with an external source that is important to do no matter how the thread shuts down.
As I understand it this is not very easy to do, in fact it seems hard enough that I feel I must be missing some basic threading feature. the 1a case is simple and works as is. 1b case works so long as the developer doesn't swallow interruptExceptions, something that is done way to often but is easy enough to avoid if you know what an interrupt exception is.
In case of an exception you need to move the shutdown method into a finally block.
In cases 3 & 4 though this gets harder. For 3 I think threads can be killed 'nicely', with an interrupt that one can catch, check to see it's a sigkill, and then force an exit of the code, but this requires even more intelligent handling of a InterruptException that most improperly swallow; plus would get ugly fast if this check has to be done in dozens of locations that can through interrupts. You can't do much for a hard kill, but no one expects proper shutdown logic for a hard kill so that's fine.
For a JVM shutdown...I don't actually know the exact method the threads are killed. I assume a sigkill is sent to the threads with a timeout before a hard kill, I'd have to research it more. If you want to be safe you can add a shutdown hook, but there is no gaurentee of order that shutdown hooks are run and trying to add shutdown hooks for each thread requires careful writing of the hooks to ensure you don't stall or stop the JVM shutdown with a deadlock or unexpected exception in the hook....
If instead of a thread like the one above I have a thread with a finite, but potentially long, processing time, without any waits, it gets even harder since I can't listen for an interrupted exception to know that I need to give up on my threads processing and run the shutdown logic immediately.
Basically, it seems like different method is needed to handle each manner a thread can execute, and needs to be done with every thread. And still in the case of high CPU threads without waits I still don't now how to gaurente a proper shutdown occurs if the thread (not the whole JVM) is killed midway through...
Is there not a simpler solution to all of this? For instance the equivalent of a thread level shutdown hook which will run when that specific thread is being killed, regardless of how it dies; even if JVM itself is not shutting down? Is there some reason a thread level shutdownhook is not possible or dangerous to support, assuming that such doesn't exist.
At least one of the reasons is that there really is not a safe and clean mechanism, which is also why Thread.stop() is deprecated. By creating a (seemingly) simple mechanism for it, people might think that it's a simple issue and use it wildly.
The same issue exists for finalizers and shutdownhooks. They're not reliable, so it's not a good idea to let developers think that it's a normal tool that they're supposed to use.
Yes, Java provides such a mechanism. Simply use a try/finally construction in your run() method, either in your Thread subclass or in your Runnable if you are using a Runnable:
public void run() {
try {
doBody()
}
finally {
doThreadShutdown()
}
}
This should take care of all of the cases that you are looking for, including normal shutdown of the virtual machine, since the virtual machine shuts down only after all nondaemon threads exit. Exceptions would be hard stop of the thread, hard kill of the virtual machine, or if the thread is a daemon thread and the virtual machine exits.

Are there dangers to throwing a runtime exception forcibly into a thread with Thread.stop(Throwable)?

I am writing a fairly large, multithreaded application, with many differing roles for threads (e.g. event processing, metrics, networking). Currently, if there is any inconsistency that cannot be handled, it will manifest itself as an exception. Since there's really no way to recover from some of them, I've been rethrowing it as a runtime exception of type ApplicationDeathException.
Any classes that need to handle shutdown would call it from a catch block for this exception, and then rethrow it in order for it to propagate up the stack).
I am considering killing off all other threads in this same manner by calling Thread#stop(Throwable) upon them. Most are fine with sudden termination, and can catch this exception should there be a need for shutdown logic. They will simply have the exception propagate up the stack, performing shutdown logic whereever needed, and eventually just killing the thread in the end. Are there any hidden dangers that I'm missing with this approach?
Thread.stop has been deprecated since it is unsafe (see the Javadoc). Instead have each thread monitor a boolean flag of some sort (see Java: How to stop thread? and likely countless other threads on SO).
In situations like this I typically implement some sort of thread pool manager that is responsible for cleanly shutting down running threads. Then when something really bad happens you only need to notify the manager to shut things down.

How to properly handle thread interrupts

I am working on an application that at some point starts a worker thread. This thread's behaviour will vary greatly depending on the parameters used to start it, but the following list of properties apply:
It will do some minor I/O operations
It will spend minor time in 3rd party libraries
It may create some worker threads for a certain subtask (these threads will not be reused after their task is finished)
It will spend most of its time crunching numbers (there are no blocking calls present)
Due to the possible long duration (5 minutes up to several hours, depending on the input), we want to be able to abort the calculation. If we choose to abort it, we no longer care about the output, and the thread is in fact wasting valuable resources as long as it keeps running. Since the code is under our control, the advised way is to use interrupts to indicate an abort.
While most examples on the web deal with a worker thread that is looping over some method, this is not the case for me (similar question here). There are also very few blocking calls in this work thread, in which case this article advises to manually check the interrupt flag. My question is: How to deal with this interrupt?
I see several options, but can't decide which is the most "clean" approach. Despite my practical example, I'm mainly interested in the "best practice" on how to deal with this.
Throw some kind of unchecked exception: this would kill the thread in a quick and easy way, but it reminds me of the ThreadDeath approach used by the deprecated Thread#stop() method, with all its related problems. I can see this approach being acceptable in owned code (due to the known logic flow), but not in library code.
Throw some kind of checked exception: this would kill the thread in a quick and easy way, and alleviates the ThreadDeath-like problems by enforcing programmers to deal with this event. However, it places a big burden on the code, requiring the exception to be mentioned everywhere. There is a reason not everything throws an InterruptedException.
Exit the methods with a "best result so far" or empty result. Because of the amount of classes involved, this will be a very hard task. If not enough care is taken, NullPointerExceptions might arise from empty results, leading to the same problems as point 1. Finding these causes would be next to impossible in large code bases.
I suggest you check Thread.currentThread().isInterrupted() periodically at points you knwo it is safe to stop and stop if it is set.
You could do this in a method which checks this flag and throws a custom unchecked exception or error.
What about a use of ExecutorService to execute the Runnable? Checkout the methods wherein you can specify the timeout. E.g.
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new Task()), 10, TimeUnit.MINUTES); // Timeout of 10 minutes.
executor.shutdown();
Here Task of course implements Runnable.

Why Thread.stop() method isn't safe to use?

A quote from "Effective Java book" :
" The libraries provide the Thread.stop method, but this method was
deprecated long ago because it is inherently unsafe—its use can result
in data corruption. Do not use Thread.stop"
Anyone can tell me why ?
What if the thread you stop holds a critical lock? What if the thread has placed an object into an inconsistent state and hasn't had a chance to restore it yet? The correct way to stop a thread is with its cooperation, not by forcing it to stop from the outside.
Also, it simply doesn't make logical sense. All the threads in an application are supposed to be cooperating to achieve the same ends. If there's something that shouldn't be done, no thread should do it. There should be no reason to stop a thread -- it should only be coded to do something if that is something the application as whole needs done in the first place. If a thread needs to be stopped, it's only because the code it is running is broken -- doing things even if they should not be done. Just fix that code.
From the javadoc:
Why is Thread.stop deprecated?
Because it is inherently unsafe. Stopping a thread causes it to unlock
all the monitors that it has locked. (The monitors are unlocked as the
ThreadDeath exception propagates up the stack.) If any of the objects
previously protected by these monitors were in an inconsistent state,
other threads may now view these objects in an inconsistent state.
Such objects are said to be damaged. When threads operate on damaged
objects, arbitrary behavior can result. This behavior may be subtle
and difficult to detect, or it may be pronounced. Unlike other
unchecked exceptions, ThreadDeath kills threads silently; thus, the
user has no warning that his program may be corrupted. The corruption
can manifest itself at any time after the actual damage occurs, even
hours or days in the future.
For more information, read this:
http://docs.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
IMHO, It's only unsafe if you use it to stop another thread. You can use it to stop the current thread without the normal issues e.g. if you need to re-throw a checked exception.
The problem with stop(), is you have no idea where in the thread you are throwing the exception or error. The only time you would consider using it is to stop third party threads which are not behaving correctly. The problem is that such threads can catch and ignore the error this triggers. If you really have unsafe or unreliable code you need to run, I suggest you use a separate process which you can kill as required.
In a nutshell, stop aborts the thread forcibly without giving it any chance to clean up. The most typical outcome is a mess.

Why doesn't Thread.stop work in situations where Thread.interrupt doesn't work?

The official Sun Oracle stance on Thread.stop() is that it should not be used. Among other arguments, they write:
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.
But I do not understand that. If a thread is busy actively working on something (not just waiting or blocking on an external resource) and doesn't explicitly check the interrupt flag, wouldn't Thread.interrupt() do nothing while Thread.stop() will still work (throw ThreadDeath)?
But I do not understand that. If a thread is busy actively working on something (not just waiting or blocking on an external resource) and doesn't explicitly check the interrupt flag, wouldn't Thread.interrupt() do nothing while Thread.stop() will still work (throw ThreadDeath)?
I think you misunderstand the quoted text. It refers to a thread that is waiting, not a thread that is running. Specifically, it is referring to cases like the following:
When the thread is blocked in an I/O call, low-level JVM implementation issues prevent it responding to either a stop or an interrupt.
A thread that doesn't want to be stopped can catch ThreadDeath, and this is analogous to a thread that doesn't want to be interrupted simply ignoring the flag.
Thread.stop is not an issue about being good or bad coding with regard to being able to bail out threads.
You should not use it unless as a very last resort. It is possible to do your code and expect Thread.stop() to occur but in that case interrupt() will possible do just as fine.
The issue that stop() won't work where interrupt() doesn't (i.e. blocked on some native stuff): both stop and ineterrupt would use the same native signals to carry the call.
On POSIX, if SIGUSR2 (for instance) doesn't help the native code to bail out, it won't help either of interrupt/stop.
You can think of interrupt vs stop like that: both may use OS signals. The OS signals may not be honored by the native code. However, if they are: stop() also puts a Throwable on the stack that will be propagated in the java code. On the contrary interrupt only sets a flag.
The throwable, however, may pop-up in virtually any statement, so some invariants may fail to be properly handled.
Possibly, it's partly fixable via Thread.uncaughtExceptionHandler by throwing away large states, rolling back transactions, etc... Again: not advisable.
The main reason, as far as I understand, is that the ThreadDeath exception may be thrown anywhere, whereas the interupt flag has to be checked explicitly.
Consider this code running in a thread:
public void sellItem(Store s) {
synchronized (s) {
if (s.itemsAvailable > 0) {
s.itemsAvailable--;
s.itemsSold++;
}
}
}
If a ThreadDeath is thrown after s.itemsAvailable--, the Store object is left in an inconsistent state. On the other hand, this code is safe:
public void sellLoop(Store s) {
while (!Thread.interrupted())
sellItem(s);
}
Source: http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#stop%28%29
They say that Thread.stop() would not work because (I guess) the throwable can be caught and ignored.
if the JVM is too busy to interrupt the thread, it's also too busy to kill it.

Categories

Resources