Versions Compared

Key

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

...

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.

...

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 IllegalThreadStateException.

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();
  }
}

...

In this noncompliant code example, the waitFor() method blocks 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[])
                          throws IOException, InterruptedException {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("notemaker");
    int exitVal = proc.waitFor();
  }
}

...

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 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();
  }
}

...

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 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();
  }
}

...

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 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) {
      // 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?
    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
  }
}

...

Failure to properly manage the I/O streams of external processes can result in runtime exceptions and in DoS vulnerabilities.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO07-J

low Low

probable Probable

medium Medium

P4

L3

Related Vulnerabilities

GROOVY-3275

Bibliography

 

...