Search code examples
javasandboxprocessbuilder

Java Sandboxing and ProcessBuilder


I followed this tutorial to implement java sandboxing for plugin code. Plugin code gets ran with the following permission:

private PermissionCollection pluginPermissions() {
    Permissions permissions = new Permissions(); 
    permissions.add(new FilePermission("/projects", "read,write,execute"));
    return permissions;
}  

It works fine. However, I would like to allow the plugin to start a process which will also be restricted with these permissions. For example, it should be able to run a python script by running this command "python test.py" as long as the script is in the /projects directory and it does not access anywhere else. Like the following code where cmnd is "python", mainFilePath is the python script which is in the directory that is restricted to the process.

public static File startProcess(String cmnd, String mainFilePath, String directory){
        try {
            ProcessBuilder pb =
                    new ProcessBuilder( cmnd, mainFilePath);

            pb.directory(new File(directory));
            File f = pb.directory();
            System.out.println(f.exists());

            File log = new File(directory,"log.txt");

            pb.redirectErrorStream(true);
            pb.redirectOutput(ProcessBuilder.Redirect.appendTo(log));

            Process p = pb.start();
            return log;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

If I run this code from the plugin, I get the following exception:

java.security.AccessControlException: access denied ("java.io.FilePermission" "<<ALL FILES>>" "execute")
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
    at java.security.AccessController.checkPermission(AccessController.java:884)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
    at java.lang.SecurityManager.checkExec(SecurityManager.java:799)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1018)
    at engine.LogHelper.startProcess(LogHelper.java:28)
    at engine.ZEngine.build(ZEngine.java:13)
    at Main.main(Main.java:29)

It suggests that I need to give the "execute" permission to all files. But I only need that restriction for the files in the specified directory. So how to achieve sandboxing while allowing ProcessBuilder to start a process in the restricted directory?

UPDATE:

The plugin permissions are now the following:

permissions.add(new FilePermission("/Users/ziadalhalabi/IdeaProjects/JarDummy/projects/-", "read,write"));            
permissions.add(new FilePermission("/Users/ziadalhalabi/IdeaProjects/JarDummy/projects/", "read,write,execute"));     
permissions.add(new FilePermission("/usr/local/bin/python", "execute"));

It works but the python script is able to read a file that is outside the directory. I want to the sandbox to be applied to anything in the python script.


Solution

  • You run command python (unqualified), so start() doesn't know where the file is, and therefore check if you're allowed execute access to <<ALL FILES>>. Since you're not, it's rejected.

    If you specify full (absolute) path to python and grant access to the python file, it'll work.

    See javadoc of SecurityManager.checkExec​(String cmd) for description of permission check:

    Throws a SecurityException if the calling thread is not allowed to create a subprocess.

    This method is invoked for the current security manager by the exec methods of class Runtime.

    This method calls checkPermission with the FilePermission(cmd,"execute") permission if cmd is an absolute path, otherwise it calls checkPermission with FilePermission("<<ALL FILES>>","execute").