Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Programs may submit only tasks that support interruption using Thread.interrupt() to thread pools that require the ability to shut down the thread pool or to cancel individual tasks within the pool. Programs must not submit tasks that lack interruption support to such thread pools. According to the Java API [API 2014], the java.util.concurrent.ExecutorService

...

.shutdownNow()

...

method

attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution....

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(),

...

so

...

any

...

task

...

that

...

fails

...

to

...

respond

...

to

...

interrupts

...

may

...

never terminate.

Noncompliant Code Example (Shutting Down Thread Pools)

This noncompliant code example submits the SocketReader class as a task to the thread pool declared in PoolService:

Code Block
bgColor#FFcccc
public final class SocketReader implements Runnable { // Thread-safe class
  private final Socket socket;
  private final BufferedReader in;
  private final Object lock = new Object();

  public SocketReader(String host, int port) throws IOException {
    this.socket = new Socket(host, port);
    this.in = new BufferedReader(
        new InputStreamReader(this.socket.getInputStream())
    );
  }

  // Only one thread can use the socket at a particular time
  @Override public void run() {
    try {
      synchronized (lock) {
        readData();
      }
    } catch (IOException ie) {
      // Forward to handler
    }
  }

  public void readData() throws IOException {
    String string;
    try {
      while ((string = in.readLine()) != null) {
        // Blocks until end of stream (null)
      }
    } finally {
      shutdown();
    }
  }

  public void shutdown() throws IOException {
    socket.close();
  }
}
 terminate. 
{quote}

Consequently, care must be taken so that only interruptible tasks are submitted to the thread pool. When using worker threads that run untrusted code or dynamically loaded extension code, a way to interrupt the worker must be provided.  For instance, a worker thread in a thread pool should generally have the following structure (adopted from \[[Goetz 06|AA. Java References#Goetz 06]\]):

{code:bgColor=#ccccff}
public void run() {
  Throwable thrown = null;
  try {
    while (!isInterrupted())
      runTask(getTaskFromWorkQueue());
  } catch (Throwable e) {
    thrown = e;
  } finally {
    threadExited(this, thrown); // Notify upper layers
  }
}
{code} 

The worker thread based architecture that uses interruptible workers permits the caller to cleanly terminate misbehaving sub-tasks. If the sub-tasks die because of runtime exceptions, then the upper layers can take some suitable action such as replacing the worker thread with a new one.


h2. Noncompliant Code Example (shutting down thread pools)

This noncompliant code example uses the {{SocketReader}} class defined earlier in the Compliant Solution (close socket connection) of the guideline [CON24-J. Ensure that threads and tasks performing blocking operations can be terminated] and submits it as a task to a thread pool defined in class {{PoolService}}.  

{code:bgColor=#FFcccc}
public final class PoolService {
  private final ExecutorService pool;

  public PoolService(int poolSize) {
    pool = Executors.newFixedThreadPool(poolSize);
  }
	  
  public void doSomething() throws InterruptedException, IOException {	   
    pool.submit(new SocketReader("somehost", 8080));
    // ...
    List<Runnable> awaitingTasks = pool.shutdownNow();	      
  }

  public static void main(String[] args) throws
 InterruptedException, IOException {
    PoolService service = new PoolService(5);
    service.doSomething();
  }
}

public final class SocketReader implements Runnable {
  private final Socket socket;
throws InterruptedException, // ...
}
{code}

Because the task does not support interruption through the use of {{Thread.interrupted()}}, there is no guarantee that the {{shutdownNow()}} method will shutdown the thread pool. Using the {{shutdown()}} method will not fix the problem either, because it will wait until all executing tasks have finished. {mc} Likewise, tasks that check a {{volatile}} flag to determine whether it is safe to shutdown will also be unresponsive to these methods.  --- Unsure what this means...should prob explain in several sentences ~DS {mc}


h2. Compliant Solution (submit interruptible tasks)

Tasks that do not support interruption using {{Thread.interrupt()}} should not be submitted to a thread pool. This compliant solution submits the interruptible version of {{SocketReader}} discussed in the Compliant Solution (interruptible channel) of the guideline [CON24-J. Ensure that threads and tasks performing blocking operations can be terminated], to the thread pool.  

{code:bgColor=#ccccff}
public final class PoolService {
  // ...
}

IOException {
    PoolService service = new PoolService(5);
    service.doSomething();
  }
}

The shutdownNow() method may fail to shut down the thread pool because the task lacks support for interruption using the Thread.interrupt() method and because the shutdown() method must wait until all executing tasks have finished.

Similarly, tasks that use some mechanism other than Thread.interrupted() to determine when to shut down will be unresponsive to shutdown() and shutdownNow(). For instance, tasks that check a volatile flag to determine whether it is safe to shutdown are unresponsive to these methods. THI05-J. Do not use Thread.stop() to terminate threads provides more information on using a flag to terminate threads.

Compliant Solution (Submit Interruptible Tasks)

This compliant solution defines an interruptible version of the SocketReader class, which is instantiated and submitted to the thread pool:

Code Block
bgColor#ccccff
public final class SocketReader implements Runnable {
  private final SocketChannel sc;
  private // ...
}
{code}

Similarly, when attempting to cancel individual tasks within the thread pool using the {{Future.cancel()}} method, you must ensure that the tasks support interruption. If they do, then you must pass a {{boolean}} argument {{true}} to {{cancel()}}, otherwise you must pass {{false}}. The value {{false}} indicates that the corresponding task will be canceled if it has not already started.


h2. Exceptions

*EX1*: Tasks that execute quickly and do not block may violate this guideline.

h2. Risk Assessment

Submitting tasks that are not interruptible may preclude the shut down procedure of a thread pool and cause denial of service.

|| Rule || Severity || Likelihood || Remediation Cost || Priority || Level ||
| CON36- 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]\] interface ExecutorService
\[[Goetz 06|AA. Java References#Goetz 06]\] Chapter 7: Cancellation and shutdown

----
[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_left.png!|CON12-J. Avoid deadlock by requesting and releasing locks in the same order]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_up.png!|11. Concurrency (CON)]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_right.png!|VOID CON14-J. Ensure atomicity of 64-bit operations]
final Object lock = new Object();

  public SocketReader(String host, int port) throws IOException {
    sc = SocketChannel.open(new InetSocketAddress(host, port));
  }

  @Override public void run() {
    ByteBuffer buf = ByteBuffer.allocate(1024);
    try {
      synchronized (lock) {
        while (!Thread.interrupted()) {
          sc.read(buf);
          // ...
        }
      }
    } catch (IOException ie) {
      // Forward to handler
    }
  }
}

public final class PoolService {
  // ...
}

Exceptions

TPS02-J-EX0: Short-running tasks that execute without blocking are exempt from this rule.

Risk Assessment

Submitting tasks that are uninterruptible may prevent a thread pool from shutting down and consequently may cause DoS.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

TPS02-J

Low

Probable

Medium

P4

L3

Bibliography

[API 2014]

Interface ExecutorService

[Goetz 2006a]

Chapter 7, "Cancellation and Shutdown"

 

...

Image Added Image Added Image Added