...
Threads
...
always
...
preserve
...
class
...
invariants
...
when
...
they
...
are
...
allowed
...
to
...
exit
...
normally.
...
Programmers
...
often
...
try
...
to
...
forcefully
...
terminate
...
threads
...
when
...
they
...
believe
...
that
...
the
...
task
...
is
...
accomplished,
...
the
...
request
...
has
...
been
...
canceled
...
or
...
the
...
program
...
needs
...
to
...
quickly
...
shutdown.
...
A
...
few
...
thread
...
APIs
...
were
...
introduced
...
to
...
facilitate
...
thread
...
suspension,
...
resumption
...
and
...
termination
...
but
...
were
...
later
...
deprecated
...
due
...
to
...
inherent
...
design
...
weaknesses.
...
The
...
Thread.stop()
...
method
...
is
...
one
...
example.
...
It
...
throws
...
a
...
ThreadDeath
...
exception
...
to
...
stop
...
the
...
thread.
...
Two
...
cases
...
arise:
...
- If
ThreadDeath
is left uncaught, it allows the execution of afinally
block which performs the usual cleanup operations. Use of theThread.stop()
...
- method
...
- is
...
- highly
...
- inadvisable
...
- because
...
- of
...
- two
...
- reasons.
...
- First,
...
- no
...
- particular
...
- thread
...
- can
...
- be
...
- forcefully
...
- stopped
...
- because
...
- an
...
- arbitrary
...
- thread
...
- can
...
- catch
...
- the
...
- thrown
...
ThreadDeath
...
- exception
...
- and
...
- simply
...
- choose
...
- to
...
- ignore
...
- it.
...
- Second,
...
- stopping
...
- threads
...
- abruptly
...
- results
...
- in
...
- the
...
- release
...
- of
...
- all
...
- the
...
- associated
...
- monitors,
...
- violating
...
- the
...
- guarantees
...
- provided
...
- by
...
- the
...
- critical
...
- sections.
...
- Moreover,
...
- the
...
- objects
...
- end
...
- up
...
- in
...
- an
...
- inconsistent
...
- state,
...
- nondeterministic
...
- behavior
...
- being
...
- a
...
- typical
...
- outcome.
...
- As a remediation measure,
...
- catching
...
- the
...
ThreadDeath
...
- exception
...
- on
...
- the
...
- other
...
- hand
...
- can
...
- itself
...
- ensnarl
...
- multithreaded
...
- code.
...
- For
...
- one,
...
- the
...
- exception
...
- can
...
- be
...
- thrown
...
- anywhere,
...
- making
...
- it
...
- difficult
...
- to
...
- trace
...
- and
...
- effectively
...
- recover
...
- from
...
- the
...
- exceptional
...
- condition.
...
- Also,
...
- there
...
- is
...
- nothing
...
- stopping
...
- a
...
- thread
...
- from
...
- throwing
...
- another
...
ThreadDeath
...
- exception
...
- while
...
- recovery
...
- is
...
- in
...
- progress.
...
Noncompliant Code Example (Deprecated Thread.stop()
...
)
...
This
...
noncompliant
...
code
...
example
...
shows
...
a
...
thread that fills a vector with strings. The thread is shut down after a fixed period of time time.
Code Block | ||
---|---|---|
| ||
public class Container implements Runnable { private final Vector<String> vector = new Vector<String>(); public Vector<String> getVector() { return vector; } public void run() { String string = null; do { System.out.println("Enter another string"); BufferedReader in = new BufferedReader(new InputStreamReader(System.in) that forcefully comes to a halt when the {{Thread.stop()}} method is invoked. Neither the {{catch}} nor the {{finally}} block executes. Any monitors that are held are immediately released, leaving the object in a delicate state. {mc} Try to retain the debug statements in the NCE to illustrate the problem {mc} {code:bgColor=#FFcccc} class BadStop implements Runnable { public void run() { try { Thread.currentThread().sleep(1000); } catch(InterruptedException ie)try { // Not executed string = Systemin.out.println("Performing cleanup"readLine(); } finallycatch { // Not executed (IOException e) { System.out.println("Closing resources"); // Forward to handler } } } } class Controller {vector.add(string); } while (!"END".equals(string)); } public static void main(String[] args) throws InterruptedException { ThreadContainer tc = new Container(); Thread( thread = new BadStopThread()c); tthread.start(); tThread.interruptsleep(5000); // Artificially induce an InterruptedException tthread.stop(); // Force thread cancellation } } |
Since vector
is thread-safe, it is only accessible to this program while in a consistent state. That is, the Vector.size()
method always reflects the true number of elements in the vector. When a new element is added to the vector, it adjusts its internal data and its internal data is temporarily inconsistent. But the vector uses its own intrinsic lock to prevent other threads from accessing it while its state is inconsistent.
Wiki Markup |
---|
However, the {{Thread.stop()}} method causes the thread to stop what it is doing and throw a {{ThreadDeath}} object, and also to release all locks \[[API 06|AA. Java References#API 06]\]. If the thread is currently adding a new string to the vector when it gets stopped, then the vector may become visible while in an inconsistent state. This might mean, for instance, that {{Vector.size()}} is 3 while the vector actually only contains 2 elements. |
Compliant Solution (volatile
flag)
This compliant example stops the thread by making use of a volatile
flag. An accessor method shutdown()
is used to set the flag to true
, after which the thread can start the cancellation process.
Code Block | ||
---|---|---|
| ||
public class Container implements Runnable {
private final Vector<String> vector = new Vector<String>();
private volatile boolean done = false;
public Vector<String> getVector() {
return vector;
}
public void shutdown() {
done = true;
}
public void run() {
String string = null;
do {
System.out.println("Enter another string");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
string = in.readLine();
} catch (IOException e) {
// Forward to handler
}
vector.add(string);
} while (!done && !"END".equals(string));
}
public static void main(String[] args) throws InterruptedException {
Container c = new Container();
Thread thread = new Thread(c);
thread.start();
Thread.sleep(5000);
c.shutdown();
return;
}
}
|
Compliant Solution (Interruptible)
This compliant example stops the thread by making use of a volatile
flag. An accessor method shutdown()
is used to set the flag to true
, after which the thread can start the cancellation process.
Code Block | ||
---|---|---|
| ||
public class Container implements Runnable {
private final Vector<String> vector = new Vector<String>();
public Vector<String> getVector() {
return vector;
}
public void run() {
String string = null;
do {
System.out.println("Enter another string");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
string = in.readLine();
} catch (IOException e) {
// Forward to handler
}
vector.add(string);
} while (!Thread.interrupted() && !"END".equals(string));
}
public static void main(String[] args) throws InterruptedException {
Container c = new Container();
Thread thread = new Thread(c);
thread.start();
Thread.sleep(5000);
thread.interrupt();
}
}
|
Compliant Solution (RuntimePermission stopThread
)
Remove the default permission java.lang.RuntimePermission
stopThread
from the security policy file to deny the Thread.stop()
invoking code, the required privileges.
Noncompliant Code Example (blocking IO)
This noncompliant code example uses the advice suggested in the previous compliant solution. However, this does not help in terminating the thread because it is blocked on some network IO as a consequence of using the readLine()
method.
Code Block | ||
---|---|---|
| ||
{code} The {{Thread.interrupt()}} method is frequently used to awaken a blocked thread before it can be stopped. It awakens threads that are blocked on {{wait()}} methods of class {{Object}}, and {{join}} and {{sleep}} methods of class {{Thread}}. In these cases, the thread's interrupt status is cleared and it receives an {{InterruptedException}}. If the thread is blocked on I/O operations upon an interruptible channel, the channel is closed, the thread's interrupt status is set and it receives a {{ClosedByInterruptException}}. Similarly, a thread waiting on a selector also returns from the operation with its interrupted status set. \[[API 06|AA. Java References#API 06]\] The {{java.lang.ThreadGroup.interrupt()}} is not deprecated and is often seen as an option to interrupt all the threads belonging to a thread group. "This is no guarantee that a program will terminate, however, because libraries that you have used may have created user threads that do not respond to interrupt requests. The AWT graphics library is one well-known example." \[[JPL 06|AA. Java References#JPL 06]\]. Moreover, using the {{ThreadGroup}} API is discouraged (see [CON17-J. Avoid using ThreadGroup APIs]). h2. Compliant Solution (1) ({{volatile}} flag) This compliant example uses a {{boolean}} flag called {{done}} to indicate whether the thread should be stopped after any necessary cleanup code has finished executing. An accessor method {{shutdown()}} is used to set the flag to {{true}}, after which the thread can start the cancellation process. The {{done}} flag is also set immediately after the execution of the {{finally}} block's resource clean-up statements so that the system does not continue relinquishing resources that it has already released, in the event of the {{done}} flag staying {{false}}. {code:bgColor=#ccccff} class ControlledStop implements Runnable{ protected volatile boolean done = false; public void run() { while(!done) { try { Thread.currentThread().sleep(1000); } catch(InterruptedException ie) { // Handle the exception } finally { done = true; } } done = false; // Reset for later use System.out.println("Done!"); } protected void shutdown(){ done = true; } } class Controller { public static void main(String[] args) throws InterruptedException { ControlledStop c = new ControlledStop(); Thread t = new Thread(c); t.start(); t.interrupt(); // Artificially induce an InterruptedException Thread.sleep(1000); // Wait for some time to allow the exception // to be caught (demonstration only) c.shutdown(); } } {code} h2. Compliant Solution (2) ({{RuntimePermission stopThread}}) Remove the default permission {{java.lang.RuntimePermission}} {{stopThread}} from the security policy file to deny the {{Thread.stop()}} invoking code, the required privileges. h2. Noncompliant Code Example (blocking IO) This noncompliant code example uses the advice suggested in the previous compliant solution. However, this does not help in terminating the thread because it is blocked on some network IO as a consequence of using the {{readLine()}} method. {code:bgColor=#FFcccc} class StopSocket extends Thread { private Socket s; private volatile boolean done = false; public void run() { while(!done) { try { s = new Socket("somehost", 25); BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); String s = null; while((s = br.readLine()) != null) { // Blocks until end of stream (null) } } catch (IOException ie) { // Forward to handler } finally { done = true; } } } public void shutdown() throws IOException { done = true; } } class Controller { public static void main(String[] args) throws InterruptedException, IOException { StopSocket ss = new StopSocket(); Thread t = new Thread(ss); t.start(); Thread.sleep(1000); ss.shutdown(); } } {code} A {{Socket}} connection is not affected by the {{InterruptedException}} that results with the use of the {{ |
A Socket
connection is not affected by the InterruptedException
that results with the use of the Thread.interrupt()
...
method.
...
The
...
boolean
...
flag
...
solution
...
does
...
not
...
work
...
in
...
such
...
cases.
...
Compliant
...
Solution
...
(close
...
socket
...
connection)
...
This
...
compliant
...
solution
...
closes
...
the
...
socket
...
connection,
...
both
...
using
...
the
...
shutdown()
...
method
...
as
...
well
...
as
...
the
...
finally
...
block.
...
As
...
a
...
result,
...
the
...
thread
...
is
...
bound
...
to
...
stop
...
due
...
to
...
a
...
SocketException
...
.
...
Note
...
that
...
there
...
is
...
no
...
way
...
to
...
keep
...
the
...
connection
...
alive
...
if
...
the
...
thread
...
is
...
to
...
be
...
cleanly
...
halted
...
immediately.
Code Block | ||
---|---|---|
| ||
{code:bgColor=#ccccff} class StopSocket extends Thread { private Socket s; public void run() { try { s = new Socket("somehost", 25); BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); String s = null; while((s = br.readLine()) != null) { // Blocks until end of stream (null) } } catch (IOException ie) { // Handle the exception } finally { try { if(s != null) s.close(); } catch (IOException e) { /* Forward to handler */ } } } public void shutdown() throws IOException { if(s != null) s.close(); } } class Controller { public static void main(String[] args) throws InterruptedException, IOException { StopSocket ss = new StopSocket(); Thread t = new Thread(ss); t.start(); Thread.sleep(1000); ss.shutdown(); } } {code} A {{boolean}} flag can be used (as described earlier) if additional |
A boolean
flag can be used (as described earlier) if additional clean-up operations need to be performed.
Compliant Solution (2) (interruptible channel)
This compliant solution uses an interruptible channel, SocketChannel
instead of a Socket
connection. If the thread performing the network IO is interrupted using the Thread.interrupt()
method, for instance, while reading the data, the thread receives a ClosedByInterruptException
and the channel is closed immediately. The thread's interrupt status is also set.
Code Block | ||
---|---|---|
| ||
clean-up operations need to be performed. h2. Compliant Solution (2) (interruptible channel) This compliant solution uses an interruptible channel, {{SocketChannel}} instead of a {{Socket}} connection. If the thread performing the network IO is interrupted using the {{Thread.interrupt()}} method, for instance, while reading the data, the thread receives a {{ClosedByInterruptException}} and the channel is closed immediately. The thread's interrupt status is also set. {code:bgColor=#ccccff} class StopSocket extends Thread { private volatile boolean done = false; public void run() { while(!done) { try { InetSocketAddress addr = new InetSocketAddress("somehost", 25); SocketChannel sc = SocketChannel.open(addr); ByteBuffer buf = ByteBuffer.allocate(1024); sc.read(buf); // ... } catch (IOException ie) { // Handle the exception } finally { done = true; } } } public void shutdown() throws IOException { done = true; } } {code} h2. Risk Assessment Trying to force thread shutdown can result in inconsistent object state and corrupt the object. Critical resources may also leak if cleanup operations are not carried out as required. || Rule || Severity || Likelihood || Remediation Cost || Priority || Level || | CON13- J | low | probable | medium | {color:green}{*}P4{*}{color} | {color:green}{*}L3{*}{color} | h3. Automated Detection TODO h3. Related Vulnerabilities Search for vulnerabilities resulting from the violation of this rule on the [CERT website|https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON35-J]. h2. References \[[API 06|AA. Java References#API 06]\] Class Thread, method {{stop}} \[[Darwin 04|AA. Java References#Darwin 04]\] 24.3 Stopping a Thread \[[JDK7 08|AA. Java References#JDK7 08]\] Concurrency Utilities, More information: Java Thread Primitive Deprecation \[[JPL |
Risk Assessment
Trying to force thread shutdown can result in inconsistent object state and corrupt the object. Critical resources may also leak if cleanup operations are not carried out as required.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON13- J | low | probable | medium | P4 | L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[API 06|AA. Java |
...
References#API 06]\] |
...
Class Thread, method {{stop}} \[[ |
...
Darwin 04|AA. Java |
...
References#Darwin 04]\] |
...
24.3 Stopping a Thread |
...
\[[JDK7 08|AA. Java References#JDK7 08]\] Concurrency Utilities, More information: Java Thread Primitive Deprecation
\[[JPL 06|AA. Java References#JPL 06]\] 14.12.1. Don't stop and 23.3.3. Shutdown Strategies
\[[JavaThreads 04|AA. Java References#JavaThreads 04]\] 2.4 Two Approaches to Stopping a Thread |
...
CON12-J. Avoid deadlock by requesting and releasing locks in the same order 11. Concurrency (CON) VOID CON14-J. Ensure atomicity of 64-bit operations