aboutsummaryrefslogtreecommitdiff
path: root/java/openjdk6/files/icedtea/openjdk/8012453-runtime.exec.patch
diff options
context:
space:
mode:
Diffstat (limited to 'java/openjdk6/files/icedtea/openjdk/8012453-runtime.exec.patch')
-rw-r--r--java/openjdk6/files/icedtea/openjdk/8012453-runtime.exec.patch383
1 files changed, 383 insertions, 0 deletions
diff --git a/java/openjdk6/files/icedtea/openjdk/8012453-runtime.exec.patch b/java/openjdk6/files/icedtea/openjdk/8012453-runtime.exec.patch
new file mode 100644
index 000000000000..143a0c1f286d
--- /dev/null
+++ b/java/openjdk6/files/icedtea/openjdk/8012453-runtime.exec.patch
@@ -0,0 +1,383 @@
+# HG changeset patch
+# User uta
+# Date 1383008821 0
+# Tue Oct 29 01:07:01 2013 +0000
+# Node ID 20c88fd14959c6a4df2e0f36bd759b56efa6f2cb
+# Parent 3e758b40337ef9da5ad030d0ac60ab4407357277
+8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
+Reviewed-by: alanb
+
+diff -r 3e758b40337e -r 20c88fd14959 src/share/classes/java/lang/ProcessBuilder.java
+--- jdk/src/share/classes/java/lang/ProcessBuilder.java Tue Jul 30 17:20:22 2013 -0400
++++ jdk/src/share/classes/java/lang/ProcessBuilder.java Tue Oct 29 01:07:01 2013 +0000
+@@ -490,6 +490,15 @@
+ + (dir == null ? "" : " (in directory \"" + dir + "\")")
+ + exceptionInfo,
+ cause);
++ } catch (IllegalArgumentException e) {
++ String exceptionInfo = ": " + e.getMessage();
++ // It's much easier for us to create a high-quality error
++ // message than the low-level C code which found the problem.
++ throw new IOException(
++ "Cannot run program \"" + prog + "\""
++ + (dir == null ? "" : " (in directory \"" + dir + "\")")
++ + exceptionInfo,
++ e);
+ }
+ }
+ }
+diff -r 3e758b40337e -r 20c88fd14959 src/windows/classes/java/lang/ProcessImpl.java
+--- jdk/src/windows/classes/java/lang/ProcessImpl.java Tue Jul 30 17:20:22 2013 -0400
++++ jdk/src/windows/classes/java/lang/ProcessImpl.java Tue Oct 29 01:07:01 2013 +0000
+@@ -26,6 +26,9 @@
+ package java.lang;
+
+ import java.io.*;
++import java.util.ArrayList;
++import java.util.regex.Matcher;
++import java.util.regex.Pattern;
+
+ /* This class is for the exclusive use of ProcessBuilder.start() to
+ * create new processes.
+@@ -47,6 +50,66 @@
+ return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream);
+ }
+
++ private static class LazyPattern {
++ // Escape-support version:
++ // "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)";
++ private static final Pattern PATTERN =
++ Pattern.compile("[^\\s\"]+|\"[^\"]*\"");
++ };
++
++ /* Parses the command string parameter into the executable name and
++ * program arguments.
++ *
++ * The command string is broken into tokens. The token separator is a space
++ * or quota character. The space inside quotation is not a token separator.
++ * There are no escape sequences.
++ */
++ private static String[] getTokensFromCommand(String command) {
++ ArrayList<String> matchList = new ArrayList<String>(8);
++ Matcher regexMatcher = LazyPattern.PATTERN.matcher(command);
++ while (regexMatcher.find())
++ matchList.add(regexMatcher.group());
++ return matchList.toArray(new String[matchList.size()]);
++ }
++
++ private static String createCommandLine(boolean isCmdFile,
++ final String executablePath,
++ final String cmd[])
++ {
++ StringBuilder cmdbuf = new StringBuilder(80);
++
++ cmdbuf.append(executablePath);
++
++ for (int i = 1; i < cmd.length; ++i) {
++ cmdbuf.append(' ');
++ String s = cmd[i];
++ if (needsEscaping(isCmdFile, s)) {
++ cmdbuf.append('"');
++ cmdbuf.append(s);
++
++ // The code protects the [java.exe] and console command line
++ // parser, that interprets the [\"] combination as an escape
++ // sequence for the ["] char.
++ // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
++ //
++ // If the argument is an FS path, doubling of the tail [\]
++ // char is not a problem for non-console applications.
++ //
++ // The [\"] sequence is not an escape sequence for the [cmd.exe]
++ // command line parser. The case of the [""] tail escape
++ // sequence could not be realized due to the argument validation
++ // procedure.
++ if (!isCmdFile && s.endsWith("\\")) {
++ cmdbuf.append('\\');
++ }
++ cmdbuf.append('"');
++ } else {
++ cmdbuf.append(s);
++ }
++ }
++ return cmdbuf.toString();
++ }
++
+ // We guarantee the only command file execution for implicit [cmd.exe] run.
+ // http://technet.microsoft.com/en-us/library/bb490954.aspx
+ private static final char CMD_BAT_ESCAPE[] = {' ', '\t', '<', '>', '&', '|', '^'};
+@@ -128,6 +191,16 @@
+ return fileToRun.getPath();
+ }
+
++ private boolean isShellFile(String executablePath) {
++ String upPath = executablePath.toUpperCase();
++ return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT"));
++ }
++
++ private String quoteString(String arg) {
++ StringBuilder argbuf = new StringBuilder(arg.length() + 2);
++ return argbuf.append('"').append(arg).append('"').toString();
++ }
++
+
+ private long handle = 0;
+ private FileDescriptor stdin_fd;
+@@ -143,36 +216,66 @@
+ boolean redirectErrorStream)
+ throws IOException
+ {
+- // The [executablePath] is not quoted for any case.
+- String executablePath = getExecutablePath(cmd[0]);
++ String cmdstr;
++ SecurityManager security = System.getSecurityManager();
++ boolean allowAmbigousCommands = false;
++ if (security == null) {
++ String value = System.getProperty("jdk.lang.Process.allowAmbigousCommands");
++ if (value != null)
++ allowAmbigousCommands = !"false".equalsIgnoreCase(value);
++ }
++ if (allowAmbigousCommands) {
++ // Legacy mode.
+
+- // We need to extend the argument verification procedure
+- // to guarantee the only command file execution for implicit [cmd.exe]
+- // run.
+- String upPath = executablePath.toUpperCase();
+- boolean isCmdFile = (upPath.endsWith(".CMD") || upPath.endsWith(".BAT"));
++ // Normalize path if possible.
++ String executablePath = new File(cmd[0]).getPath();
+
+- StringBuilder cmdbuf = new StringBuilder(80);
++ // No worry about internal and unpaired ["] .
++ if (needsEscaping(false, executablePath) )
++ executablePath = quoteString(executablePath);
+
+- // Quotation protects from interpretation of the [path] argument as
+- // start of longer path with spaces. Quotation has no influence to
+- // [.exe] extension heuristic.
+- cmdbuf.append('"');
+- cmdbuf.append(executablePath);
+- cmdbuf.append('"');
++ cmdstr = createCommandLine(
++ false, //legacy mode doesn't worry about extended verification
++ executablePath,
++ cmd);
++ } else {
++ String executablePath;
++ try {
++ executablePath = getExecutablePath(cmd[0]);
++ } catch (IllegalArgumentException e) {
++ // Workaround for the calls like
++ // Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar")
+
+- for (int i = 1; i < cmd.length; i++) {
+- cmdbuf.append(' ');
+- String s = cmd[i];
+- if (needsEscaping(isCmdFile, s)) {
+- cmdbuf.append('"');
+- cmdbuf.append(s);
+- cmdbuf.append('"');
+- } else {
+- cmdbuf.append(s);
++ // No chance to avoid CMD/BAT injection, except to do the work
++ // right from the beginning. Otherwise we have too many corner
++ // cases from
++ // Runtime.getRuntime().exec(String[] cmd [, ...])
++ // calls with internal ["] and escape sequences.
++
++ // Restore original command line.
++ StringBuilder join = new StringBuilder();
++ // terminal space in command line is ok
++ for (String s : cmd)
++ join.append(s).append(' ');
++
++ // Parse the command line again.
++ cmd = getTokensFromCommand(join.toString());
++ executablePath = getExecutablePath(cmd[0]);
++
++ // Check new executable name once more
++ if (security != null)
++ security.checkExec(executablePath);
+ }
++
++ // Quotation protects from interpretation of the [path] argument as
++ // start of longer path with spaces. Quotation has no influence to
++ // [.exe] extension heuristic.
++ cmdstr = createCommandLine(
++ // We need the extended verification procedure for CMD files.
++ isShellFile(executablePath),
++ quoteString(executablePath),
++ cmd);
+ }
+- String cmdstr = cmdbuf.toString();
+
+ stdin_fd = new FileDescriptor();
+ stdout_fd = new FileDescriptor();
+diff -r 3e758b40337e -r 20c88fd14959 test/java/lang/Runtime/exec/ExecCommand.java
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ jdk/test/java/lang/Runtime/exec/ExecCommand.java Tue Oct 29 01:07:01 2013 +0000
+@@ -0,0 +1,163 @@
++/*
++ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++
++
++/**
++ * @test
++ * @bug 8012453
++ * @run main/othervm ExecCommand
++ * @summary workaround for legacy applications with Runtime.getRuntime().exec(String command)
++ */
++
++import java.io.BufferedWriter;
++import java.io.File;
++import java.io.FileWriter;
++import java.io.IOException;
++import java.security.AccessControlException;
++
++public class ExecCommand {
++ static class SecurityMan extends SecurityManager {
++ public static String unquote(String str)
++ {
++ int length = (str == null)
++ ? 0
++ : str.length();
++
++ if (length > 1
++ && str.charAt(0) == '\"'
++ && str.charAt(length - 1) == '\"')
++ {
++ return str.substring(1, length - 1);
++ }
++ return str;
++ }
++
++ @Override public void checkExec(String cmd) {
++ String ncmd = (new File(unquote(cmd))).getPath();
++ if ( ncmd.equals(".\\Program")
++ || ncmd.equals("\".\\Program")
++ || ncmd.equals(".\\Program Files\\do.cmd")
++ || ncmd.equals(".\\Program.cmd"))
++ {
++ return;
++ }
++ super.checkExec(cmd);
++ }
++ }
++
++ // Parameters for the Runtime.exec calls
++ private static final String TEST_RTE_ARG[] = {
++ ".\\Program Files\\do.cmd",
++ "\".\\Program Files\\doNot.cmd\" arg",
++ "\".\\Program Files\\do.cmd\" arg",
++ // compatibility
++ "\".\\Program.cmd\" arg",
++ ".\\Program.cmd arg",
++ };
++
++ private static final String doCmdCopy[] = {
++ ".\\Program.cmd",
++ ".\\Program Files\\doNot.cmd",
++ ".\\Program Files\\do.cmd",
++ };
++
++ // Golden image for results
++ private static final String TEST_RTE_GI[][] = {
++ //Pure system | Legacy mode | Legacy mode & SM
++ // [.\Program File\do.cmd]
++ new String[]{"IOException", // [.\Program] not found
++ "Success",
++ "IOException"}, //SM - no legacy mode [.\Program] - OK
++
++ // [".\Program File\doNot.cmd" arg]
++ new String[]{"Success",
++ "Success",
++ "AccessControlException"}, //SM - [".\Program] - OK,
++ // [.\\Program Files\\doNot.cmd] - Fail
++
++ // [".\Program File\do.cmd" arg]
++ // AccessControlException
++ new String[]{"Success",
++ "Success",
++ "Success"}, //SM - [".\Program] - OK,
++ // [.\\Program Files\\do.cmd] - OK
++
++ // compatibility
++ new String[]{"Success", "Success", "Success"}, //[".\Program.cmd"]
++ new String[]{"Success", "Success", "Success"} //[.\Program.cmd]
++ };
++
++ public static void main(String[] _args) throws Exception {
++ if (!System.getProperty("os.name").startsWith("Windows")) {
++ return;
++ }
++
++ // tear up
++ try {
++ new File(".\\Program Files").mkdirs();
++ for (int i = 0; i < doCmdCopy.length; ++i) {
++ try (BufferedWriter outCmd = new BufferedWriter(
++ new FileWriter(doCmdCopy[i]))) {
++ outCmd.write("@echo %1");
++ }
++ }
++ } catch (IOException e) {
++ throw new Error(e.getMessage());
++ }
++
++ // action
++ for (int k = 0; k < 3; ++k) {
++ switch (k) {
++ case 1:
++ System.setProperty("jdk.lang.Process.allowAmbigousCommands", "");
++ break;
++ case 2:
++ System.setSecurityManager( new SecurityMan() );
++ break;
++ }
++ for (int i = 0; i < TEST_RTE_ARG.length; ++i) {
++ String outRes;
++ try {
++ Process exec = Runtime.getRuntime().exec(TEST_RTE_ARG[i]);
++ exec.waitFor();
++ outRes = "Success";
++ } catch (IOException ioe) {
++ outRes = "IOException: " + ioe.getMessage();
++ } catch (IllegalArgumentException iae) {
++ outRes = "IllegalArgumentException: " + iae.getMessage();
++ } catch (AccessControlException se) {
++ outRes = "AccessControlException: " + se.getMessage();
++ }
++
++ if (!outRes.startsWith(TEST_RTE_GI[i][k])) {
++ throw new Error("Unexpected output! Step" + k + "" + i
++ + " \nArgument: " + TEST_RTE_ARG[i]
++ + "\nExpected: " + TEST_RTE_GI[i][k]
++ + "\n Output: " + outRes);
++ } else {
++ System.out.println("RTE OK:" + TEST_RTE_ARG[i]);
++ }
++ }
++ }
++ }
++}