Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Parasoft Jtest 2021.1

External programs can be invoked from Java code using the The exec() method of the java.lang.Runtime class . As a result, a reference to the Process class is returned to the JVM. The exitValue() method can be used to observe the return value of the process. There are several nuances of Rutime.exec() that are discussed below.

Noncompliant Code Example

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 may require input to be sent to their input stream, and they may also produce output on their output stream, their error stream, or both. Incorrect handling of such external programs can cause unexpected exceptions, denial of service (DoS), and other security problems.

A process that tries to read input on an empty input stream will block until input is supplied. Consequently, input must be supplied when invoking such a process.

Output from an external process can exhaust the available buffer reserved for its output or error stream. When this occurs, the Java program can block the external process as well, preventing any forward progress for both the Java program and the external process. Note that many platforms limit the buffer size available for output streams. Consequently, when invoking an external process, if the process sends any data to its output stream, the output stream must be emptied. Similarly, 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.

This noncompliant code example invokes notemaker using the exec() method, which returns a 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 IllegalThreadStateExceptionThis noncompliant code example calls notemaker, a hypothetical cross-platform notepad application. Despite compiling successfully, it throws an IllegalThreadStateException if the notemaker process has not completed.

Code Block
bgColor#FFcccc

public class Exec {
  public static void main(String args[]) {
    trythrows IOException {
      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec("notemaker");
      int exitVal = proc.exitValue();
    } catch (Throwable t) { t.printStackTrace();}
  }
}
}
}

Noncompliant Code Example (waitFor())

In this noncompliant code example, By using the waitFor() method for blocking, this code can be modified as shown in the modified noncompliant example below. This also has a shortcoming: the program hangs due to the limited buffer size used for standard output streams on many platforms. This is the result of failure in reading/writing to the streams in a timely fashionblocks the calling thread until 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
bgColor#FFcccc

public class Exec {
  public static void main(String args[]) {
    try
                          throws IOException, InterruptedException {
      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec("notemaker");
      int exitVal = proc.waitFor();
    } catch (Throwable t) { t.printStackTrace();}
  }
}

Compliant Solution

Noncompliant Code Example (Process Output Stream)

This noncompliant code example properly empties the process's output stream, thereby preventing the 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 blockAn inefficient solution would be to exhaust the output (or stderr) stream before beginning to wait for the process. A better option is to empty both the stderr and output streams. The code below shows this but is not the best solution since it does not process any arguments passed to the external program (notemaker) and in turn exits with an OS-specific non-zero exit code.

Code Block
bgColor#ccccff#ffcccc

public class Exec {
  public static void main(String args[]) {
    try
                     throws IOException, InterruptedException {
      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec("notemaker");
      InputStream stderris = proc.getErrorStreamgetInputStream();
      InputStreamReader isr = new InputStreamReader(stderr);
      BufferedReader br = new BufferedReader(isr);

      while ( (line = br.readLineint c;
    while ((c = is.read()) != null-1)   {
        System.out.println(lineprint((char) c);
  //prints the error lines}

      int exitVal = proc.waitFor();
    } catch (Throwable t) { t.printStackTrace(); }
  }
}
}
}

Compliant Solution (redirectErrorStream())

This compliant solution redirects the process's error stream to its output stream. Consequently, the program can empty the single output stream without fear of blockageThe second compliant solution spawns a command interpreter and executes the user supplied command. It uses a separate OutputStream to write the output that is read in from the external process.

Code Block
bgColor#ccccff

public class Exec extends Thread  {
  InputStreampublic is;
static void main(String type;args[])
  OutputStream os;

  Exec(InputStream is, String type) {
    this(is, type, null);
  }

  Exec(InputStream is, String type, OutputStream redirect) {
 throws IOException, InterruptedException this.is{
 = is;
  ProcessBuilder pb this.type= = typenew ProcessBuilder("notemaker");
    this.ospb = redirectpb.redirectErrorStream(true);
   }

 Process publicproc void= runpb.start() {;
    tryInputStream {
is = proc.getInputStream();
    PrintWriter pw = nullint c;
    while ((c if= is.read(os)) != null-1) {
        pw = new PrintWriter(osSystem.out.print((char) c);
      }  
     
      InputStreamReader isrint exitVal = new InputStreamReader(isproc.waitFor();
  }
}

Compliant Solution (Process Output Stream and Error Stream)

This compliant solution spawns two threads to consume the process's output stream and error stream. Consequently, the process cannot 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
bgColor#ccccff
class StreamGobbler implements Runnable {
 BufferedReader brprivate =final new BufferedReader(isr)InputStream is;
  private final   String line=nullPrintStream os;
 
  StreamGobbler(InputStream is, PrintStream os)  while{
 ( (line = br.readLine()) != null) {this.is = is;
    this.os = os;
  }

 if (pwpublic !=void nullrun() {
    try {
      pw.println(line)int c;
      while ((c =   pwis.flushread());
         }!= -1)
 
         System.out.println(type + ">" + lineos.print((char) c);
       }
 
       if catch (pwIOException != null)x) {
      //   pw.flush();Handle error
    } catch (IOException ioe) { ioe.printStackTrace(); }
  }
}
	
public class ExecMeExec {
  public static void main(String[] args)
  {
  throws IOException, // ... perform command argument check  ...
	
    try {
	  FileOutputStream fos = new FileOutputStream("c:\\output.txt");
	InterruptedException {

    Runtime rt = Runtime.getRuntime();
	    Process proc = rt.exec("notemaker");

	    // anyAny error message?
	    ExecThread errorGobbler
      = new Thread(new ExecStreamGobbler(proc.getErrorStream(), "ERROR"System.err));
	 
	    // anyAny output?
	    ExecThread outputGobbler
      = new ExecThread(new StreamGobbler(proc.getInputStream(), "OUTPUT", fosSystem.out));
	
	    errorGobbler.start();
	    outputGobbler.start();
	
	    // anyAny error?
	    int exitVal = proc.waitFor();
	    errorGobbler.join();     //handle Handle condition where the
          outputGobbler.join();    // process ends before the threads finish 

	  fos.flush();
	  fos.close();
    } catch (Throwable t) { t.printStackTrace(); }
  }
}

Risk Assessment

}

Exceptions

FIO07-J-EX0: Failure to supply input to a process that never reads input from its input stream 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

Failure to properly manage the I/O streams of external processes can result in runtime exceptions and in DoS vulnerabilitiesMisusing exec() can seriously compromise the security of a Java application.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO02

FIO07-J

high

Low

probable

Probable

high

Medium

P6

P4

L2

L3

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

ToolVersionCheckerDescription
Parasoft Jtest
Include Page
Parasoft_V
Parasoft_V
CERT.FIO07.EXECDo not use 'Runtime.exec()'

Related Vulnerabilities

GROOVY-3275

Bibliography


...

Image Added Image Added Image Added Wiki Markup\[[Daconta 00|AA. Java References#Daconta 00]\] \[[Daconta 03|AA. Java References#Daconta 03]\] Pitfall 1 \[[API 06|AA. Java References#API 06]\] [exec()|http://java.sun.com/javase/6/docs/api/java/lang/Runtime.html#exec(java.lang.String)]