java -Djava.security.manager -java.security.policy=filename.policy HelloWorld.class
Where filename.policy is a file on the harddrive with no entries at all will "sufficiently" sandbox the code and prevent it from doing malicious writes/read on your PC.
The problem with just running that alone is that infinite loops are allowed and it would possibly consume all your CPU power and never stop.
The fix for that is indeed to create a new different program, which creates a new Process that it launches and only allows that Process to exist for a certain timeframe before terminating it (violently).
Here's some code I made for this (butchered from old code):
class TestProcess {
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
List<String> out = new ArrayList<>();
IntegerCallable ic = new TestProcess.IntegerCallable(out);
int returnVal = timedCall(ic);
}
private static <T> T timedCall(Callable<T> c) throws InterruptedException, ExecutionException, TimeoutException {
FutureTask<T> task = new FutureTask<>(c);
THREAD_POOL.execute(task);
return task.get(3, TimeUnit.SECONDS);
}
public static class IntegerCallable implements Callable<Integer> {
private final List<String> output;
private Process process;
public IntegerCallable(List<String> out) {
this.output = out;
}
public Integer call() throws Exception {
ProcessBuilder pb = new ProcessBuilder("java", "-cp", "execCommand/", "-Djava.security.manager", "-Djava.security.policy=execCommand/exec.policy", "-Xmx64M", "Exec");
pb.redirectErrorStream(true);
process = pb.start();
try (final Scanner scan = new Scanner(process.getInputStream())) {
while (scan.hasNext())
output.add(scan.nextLine());
}
return process.exitValue();
}
}
}
The line ProcessBuilder pb = new ProcessBuilder("java", "-cp", "execCommand/", "-Djava.security.manager", "-Djava.security.policy=execCommand/exec.policy", "-Xmx64M", "Exec");
needs to be edited to your needs. This line executes a Exec.class file inside a folder called execCommand, which is also the location of a exec.policy file, and give it a maximum of 64MB heap.