The exec()
method of the java.lang.Runtime
class and the related ProcessBuilder.start()
method can be used to invoke external programs. While running, these programs are represented by a java.lang.Process
object. This process contains an input stream, output stream, and error stream. Because the Process
object allows a Java program to communicate with its external program, the process's input stream is an OutputStream
object, accessible by the Process.getOutputStream()
method. Likewise, the process's output stream and error streams are both represented by InputStream
objects, accessible by the Process.getInputStream()
and Process.getErrorStream()
methods.
These processes These programs may require input to be sent to their input stream, and they may also produce output on their output stream or , their error stream, or both. Incorrect handling of such external programs can cause unexpected exceptions, denial of service (DoS), and other security problems.
...
Output from an external process can exhaust the available buffer reserved for the its output or error stream. When this occurs, it the Java program can block the external process as well, preventing any forward progress for both the Java program and the external processesprocess. Note that many platforms limit the buffer size available for the output streams. Consequently, when invoking an external process, if the process sends any data to its output stream, the process's output stream must be emptied. And Similarly, if the process sends any data to its error stream, the error stream must also be emptied.
...
This noncompliant code example invokes a hypothetical cross-platform notepad application using the external command notemaker
. The notemaker
application does not read its input stream , but sends output to both its output stream and error stream.
This noncompliant code example invokes notemaker
using the exec()
method, which returns an object of a subclass of the abstract
class java.lang.Process
Process
object. The exitValue()
method returns the exit value for processes that have terminated, but it throws an IllegalThreadStateException
when invoked on an active process. Because this noncompliant example program fails to wait for the notemaker
process to terminate, the call to exitValue()
is likely to throw an IllegalThreadStateException
.
Code Block | ||
---|---|---|
| ||
public class Exec {
public static void main(String args[]) throws IOException {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("notemaker");
int exitVal = proc.exitValue();
}
}
|
...
In this noncompliant code example, the waitFor()
method blocks the calling thread until the the notemaker
process terminates. This approach prevents the IllegalThreadStateException
from the previous example. However, the example program may experience an arbitrary delay before termination. Output from the notemaker
process can exhaust the available buffer for the output or error stream because neither stream is read while waiting for the process to complete. If either buffer becomes full, it can block the notemaker
process as well, preventing all progress for both the notemaker
process and the Java program.
Code Block | ||
---|---|---|
| ||
public class Exec { public static void main(String args[]) throws IOException, InterruptedException { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("notemaker"); int exitVal = proc.waitFor(); } } |
Noncompliant Code Example (
...
Process Output Stream)
This noncompliant code example properly empties the input stream from the processprocess's output stream, thereby preventing the input output stream buffer from becoming full and blocking. However, it ignores the process's error stream, which can also fill and cause the process to block.
Code Block | ||
---|---|---|
| ||
public class Exec { public static void main(String args[]) throws IOException, InterruptedException { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("notemaker"); InputStream is = proc.getInputStream(); int c; while ((c = is.read()) != -1) { System.out.print((char) c); } int exitVal = proc.waitFor(); } } |
Compliant Solution (redirectErrorStream()
)
This compliant solution redirects the process's error stream to its input output stream. Consequently, the program can empty the single output stream without fear of blockage.
Code Block | ||
---|---|---|
| ||
public class Exec { public static void main(String args[]) throws IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder("notemaker"); pb = pb.redirectErrorStream(true); Process proc = pb.start(); InputStream is = proc.getInputStream(); int c; while ((c = is.read()) != -1) { System.out.print((char) c); } int exitVal = proc.waitFor(); } } |
Compliant Solution (
...
Process Output Stream and Error Stream)
This compliant solution spawns two threads to consume the input process's output stream and error stream. Consequently, the process does not blockcannot block indefinitely on those streams.
When the output and error streams are handled separately, they must be emptied independently. Failure to do so can cause the program to block indefinitely.
Code Block | ||
---|---|---|
| ||
class StreamGobbler extendsimplements ThreadRunnable { private final InputStream is; private final PrintStream os; StreamGobbler(InputStream is, PrintStream os) { this.is = is; this.os = os; } public void run() { try { int c; while ((c = is.read()) != -1) os.print((char) c); } catch (IOException x) { // handleHandle error } } } public class Exec { public static void main(String[] args) throws IOException, InterruptedException { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("notemaker"); // Any error message? StreamGobblerThread errorGobbler = new Thread(new StreamGobbler(proc.getErrorStream(), System.err)); // Any output? StreamGobblerThread outputGobbler = new Thread(new StreamGobbler(proc.getInputStream(), System.out)); errorGobbler.start(); outputGobbler.start(); // Any error? int exitVal = proc.waitFor(); errorGobbler.join(); // Handle condition where the outputGobbler.join(); // process ends before the threads finish } } |
Exceptions
FIO10FIO07-J-EX0: A Failure to supply input to a process that does not read never reads input from its input stream need not have data supplied there. Similarly, a process that does not send output to its output or error streams does not need to empty these is harmless and can be beneficial. Failure to empty the output or error streams of a process that never sends output to its output or error streams is similarly harmless or even beneficial. Consequently, programs are permitted to ignore the input, output, or error streams of processes that are guaranteed not to use those streams.
Risk Assessment
Misuse of the exec()
method Failure to properly manage the I/O streams of external processes can result in runtime exceptions and in denial of service DoS vulnerabilities.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
FIO07-J |
Low |
Probable |
Medium | P4 | L3 |
Related Vulnerabilities
Bibliography
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="2c204253-7067-449d-a1cb-b574f85ddfaa"><ac:plain-text-body><![CDATA[ | [[API 06 | AA. Bibliography#API 06]] | method [exec() | http://java.sun.com/javase/6/docs/api/java/lang/Runtime.html#exec(java.lang.String)] | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="03c5535e-315a-431d-b0f5-18f47936d084"><ac:plain-text-body><![CDATA[ | [[Daconta 00 | AA. Bibliography#Daconta 00]] |
| ]]></ac:plain-text-body></ac:structured-macro> | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="26f51ecb-9407-4597-8ba6-62f2194c2ec6"><ac:plain-text-body><![CDATA[ | [[Daconta 03 | AA. Bibliography#Daconta 03]] | Pitfall 1 | ]]></ac:plain-text-body></ac:structured-macro> |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Parasoft Jtest |
| CERT.FIO07.EXEC | Do not use 'Runtime.exec()' |
Related Vulnerabilities
Bibliography
[API 2014] | |
Pitfall 1 |
...
12. Input Output (FIO) FIO11-J. Do not attempt to read raw binary data as character data