I have been trying to execute bash commands in Java. I have done it with a couple of ovations, for instance:
try {
Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "cd " + folder + "&& find . -type f | grep :*.txt "});
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
return stdInput.lines().count();
} catch (IOException e) {
throw new RuntimeException(e);
}
This code works properly, without any errors.
I have tried to use docker with java, in 2 different ways. First way was the "Runtime.exec()", as in the previous example:
Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "cd", "~/IdeaProjects/test/src/main/java/Docker", "&& docker", "build", " -f", "Dockerfile.txt", "-t", "java-app9", "."});
The other way was to use the "ProcessBuilder", as in the following example:
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("sh","cd", "/home/alex/IdeaProjects/test/src/main/java/Docker", "&& docker", "build", " -f", "Dockerfile.txt", "-t", "java-app1", ".");
Process process =processBuilder.start();
Both ways do not work without throwing any error.
I have tried also to do it in python:
import os
os.system('''cd /home/alex/IdeaProjects/test/src/main/java/Docker && docker build -f Dockerfile.txt -t java-app3 . ''')
The python works as it is presented in the following picture:
I expect from this code to run java and create custom containers directly from java. I am using Java 19 and Docker version 20.10.21 .
2
Answers
try to add "/c" at the end of your string, it use to start the command you refer.
When you invoke a command in Unix, you provide a sequence of "words". These are not processed or reinterpreted at all; the first word is the command to invoke and the remaining words are its arguments. (In a Dockerfile, compare to the JSON-array exec-form syntax of
CMD
.)In your examples, you’re trying to mix this string-array syntax with shell constructs. If you try to run
"bash", "foo", "&&", "bar"
, then it will specifically usebash
as an interpreter to runfoo
as a shell script, passing it two arguments&&
andbar
. In your very first example you usesh -c
passing the rest of the command as a single argument. This has the right effect, but it makes you vulnerable to a shell injection attack if, for example, thefolder
name includes a semicolon.All of your commands are of the form
cd directory && command
. You can useProcessBuilder.directory()
to set the directory name, and then directly runcommand
without actually involving a shell. This both solves your problem and the security issue.The actual right answer to this is to use a Docker SDK rather than invoke the
docker
CLI tool. Using docker-java, for example, you might writeRemember in any case that, if you can access the Docker socket at all, then you can launch a new container, running as root, bind-mounting the host filesystem, and take over the whole machine.