Versions Compared

Key

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

...

Output from an external process can exhaust the available buffer for the output or error stream. When this occurs, it can block the external process as well, preventing any forward progress for both the Java program and the external processes. 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 if the process sends any data to its error stream, the error stream must also be emptied.

Noncompliant Code Example (exitValue())

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.

...

Code Block
bgColor#FFcccc
public class Exec {
  public static void main(String args[]) throws IOException {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("notemaker");
    int exitVal = proc.exitValue();
  }
}

Noncompliant Code Example (waitFor())

In this noncompliant code example, the waitFor() method blocks the calling thread until the the notemaker process terminates. This 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
bgColor#FFcccc
public class Exec {
  public static void main(String args[]) throws IOException {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("notemaker");
    int exitVal = proc.waitFor();
  }
}

Noncompliant Code Example (Input Stream)

This noncompliant code example properly empties the input stream from the process, thereby preventing the input stream buffer from becoming full and blocking. However, it ignores the error stream, which can also fill and cause the process to block.

Code Block
bgColor#ffcccc
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 stream. Consequently, the program can empty the single output stream without fear of blockage.

Code Block
bgColor#ccccff
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 (Input Stream and Error Stream)

This compliant solution spawns two threads to consume the input stream and error stream. Consequently, the process does not block.

...

Code Block
bgColor#ccccff
class StreamGobbler extends Thread {
  InputStream is;
  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) {
      // handle 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?
    StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), System.err);
	
    // Any output?
    StreamGobbler outputGobbler = 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

FIO10-EX0: A process that does not read 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 streams.

Risk Assessment

Misuse of the exec() method can result in runtime exceptions and in denial of service vulnerabilities.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO10-J

low

probable

medium

P4

L3

Related Vulnerabilities

GROOVY-3275

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="6e57ddb64aea9705-49e6a8dc-45004895-ace78706-a4a4eed8cb7a930bc7ecd769"><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="bf00123de8d169b8-c8661061-41954a98-b8f2b62e-fc1bd22c38267247f9c2f309"><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="3e96dfef18b736bc-4e5ecbab-4c3d408c-a272890b-1d06822998cd9b51f49dd94a"><ac:plain-text-body><![CDATA[

[[Daconta 03

AA. Bibliography#Daconta 03]]

Pitfall 1

]]></ac:plain-text-body></ac:structured-macro>

...