Briefly
Jython works in the JVM with a security manager. The security manager should not stop the Jython engine itself from doing its job, but it should not allow any privileged python script actions running in Jython. What is the minimum Java security policy that will do this?
In other words (long version)
This question is about using Java security mechanisms for untrusted python scripts for the sandbox. (I do not want to discuss other ways to use the sandbox pinton.) If something is fundamentally wrong with this approach to security, say so.
Invalid python code will call methods on trusted Java objects and will be embedded in Java as PyObject. This is explained in the Jythonbook example , and we will use the code from this example. This is Jython 2.5.2 on Java 1.6.
We need to give some specific instructions to the security manager, as Jython performs some proprietary privileged actions, but also executes untrusted python code that should not have any of these privileges.
First, for security, we install the SecurityManager in the Java virtual machine:
/home/me% export CLASSPATH=.:jython.jar /home/me% javac ./org/jython/book/interfaces/BuildingType.java ./org/jython/book/Main.java ./org/jython/book/util/BuildingFactory.java /home/me% java org.jython.book.Main Building Info: null BUILDING-A 100 WEST MAIN Building Info: null BUILDING-B 110 WEST MAIN Building Info: null BUILDING-C 120 WEST MAIN
Great. But for us, Building.py is unreliable code, so we are blocking the JVM. The problem is that crippling Jython:
/home/me% java -Djava.security.manager org.jython.book.Main Jul 23, 2013 7:07:17 PM org.python.google.common.base.internal.Finalizer getInheritableThreadLocalsField INFO: Couldn't access Thread.inheritableThreadLocals. Reference finalizer threads will inherit thread local values. Exception in thread "main" java.security.AccessControlException: access denied (java.util.PropertyPermission user.dir read) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323) at java.security.AccessController.checkPermission(AccessController.java:546) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) ... at java.io.File.getAbsolutePath(File.java:501) at org.python.core.PySystemState.<init>(PySystemState.java:181) at org.python.core.PySystemState.doInitialize(PySystemState.java:890) at org.python.core.PySystemState.initialize(PySystemState.java:800) at org.python.core.PySystemState.initialize(PySystemState.java:750) at org.python.core.PySystemState.initialize(PySystemState.java:743) at org.python.core.PySystemState.initialize(PySystemState.java:737) at org.python.core.PySystemState.initialize(PySystemState.java:733) at org.python.core.ThreadStateMapping.getThreadState(ThreadStateMapping.java:17) at org.python.core.Py.getThreadState(Py.java:1315) at org.python.core.Py.getThreadState(Py.java:1311) at org.python.core.Py.getSystemState(Py.java:1331) at org.python.util.PythonInterpreter.<init>(PythonInterpreter.java:102) at org.python.util.PythonInterpreter.<init>(PythonInterpreter.java:92) at org.python.util.PythonInterpreter.<init>(PythonInterpreter.java:64) at org.jython.book.util.BuildingFactory.<init>(BuildingFactory.java:22) at org.jython.book.Main.main(Main.java:21){code}
The security manager does not allow anyone to read the user.dir property. Of course, it should be good for Jython to read this property. Can I write this to a policy file like this?
/home/me% cat jython.policy grant codeBase "/home/me/*" { permission java.util.PropertyPermission "user.dir", "read"; }; /home/me% java -Djava.security.manager -Djava.security.policy=jython.policy org.jython.book.Main
Well no, I can't ... because untrusted python code also works in python interpreter classes. Thus, an unreliable python will also receive this privilege, and this is bad.
Therefore, I need to authorize only a specific jython class, in this case PySystemState. (I may also need to edit its source code so that it doPrivilegedAction certain code in a doPrivilegedAction call.)
Great. The next required privilege is doozy: the dangerous createClassLoader permission.
java.security.AccessControlException: access denied (java.lang.RuntimePermission createClassLoader) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323) at java.security.AccessController.checkPermission(AccessController.java:546) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at java.lang.SecurityManager.checkCreateClassLoader(SecurityManager.java:594) at java.lang.ClassLoader.<init>(ClassLoader.java:226) at java.security.SecureClassLoader.<init>(SecureClassLoader.java:76) at java.net.URLClassLoader.<init>(URLClassLoader.java:113) at org.python.core.BytecodeLoader$Loader.<init>(BytecodeLoader.java:81) at org.python.core.BytecodeLoader.makeClass(BytecodeLoader.java:27) at org.python.core.BytecodeLoader.makeCode(BytecodeLoader.java:67) at org.python.compiler.LegacyCompiler$LazyLegacyBundle.loadCode(LegacyCompiler.java:43) at org.python.core.CompilerFacade.compile(CompilerFacade.java:34) at org.python.core.Py.compile_flags(Py.java:1703) at org.python.core.Py.compile_flags(Py.java:1708) at org.python.core.Py.compile_flags(Py.java:1738) at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:206) at org.jython.book.util.BuildingFactory.<init>(BuildingFactory.java:23) at org.jython.book.Main.main(Main.java:22)
Hidden at the bottom of the stack, we see that PythonInterpreter.exec triggered this access request. Is exec() executed as a PrivilegedAction?
So this discovery process could go on for some time, and I was hoping that someone would just find out the answer: what classes in Jython should be authorized and what specific permissions do they need?
And if this approach is doomed to failure, then the answer to this question will be great.