11

I'm programming a Java server that has to handle Python code given by the user using Jython. Obviously, I can't just execute it without some risk of a cracker accessing files and system commands that he/she shouldn't. I've been searching for some way to restrict file permissions for specific threads for hours now, and the closest I've gotten was restricting file permissions for the entire application. Is there a class implemented that does something like this, or some method to do it?

Adam Zalcman
  • 26,643
  • 4
  • 71
  • 92
ConsciousCode
  • 563
  • 4
  • 18
  • 2
    Related (but still open) question: http://stackoverflow.com/questions/6744553/java-security-manager-per-thread – Thilo Nov 10 '11 at 04:58
  • 1
    Also (with Rhino instead of Jython): http://stackoverflow.com/questions/93911/how-can-you-run-javascript-using-rhino-for-java-in-a-sandbox – Thilo Nov 10 '11 at 05:00
  • the inheritablethreadlocal is an interesting option, but you need to be careful, because it won't be propagated to any already spawned thread (e.g. code submitted to a thread pool). so, it's probably kind of a fragile solution. – jtahlborn Nov 10 '11 at 05:11

2 Answers2

4

You could try using java.lang.SecurityManager. See also this question about using a security manager to set different security settings per thread.

You can set a security manager and security policy like this:

jython -Djava.security.manager=securitymanager -Djava.security.policy=policyfile

where securitymanager is the security manager to use and policyfile contains policy specification as described for example here. If you use a policy file as the source for the security policy, here is an example:

grant {
  permission java.security.AllPermission;
}

Jython will need some permissions to start up including the following:

grant {
  permission java.io.FilePermission "${user.home}${/}-", "read, write";
  permission java.lang.RuntimePermission "createClassLoader";
  permission java.lang.RuntimePermission "getProtectionDomain";
};

(this assumes your cachedir is under the current user's HOME directory). This will do something close to what you need allowing read and write access to files under the current user's HOME and disallowing access to all other parts of the filesystem. Here is the outcome (the first open() refers to a file under the current user's HOME directory since this is the current working directory):

>>> f1=open('test.txt', 'r')
>>> f2=open('/tmp/test.txt', 'r')
Traceback (innermost last):
  File "<console>", line 1, in ?
java.security.AccessControlException: access denied (java.io.FilePermission /tmp/test.txt read)
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:342)
    at java.security.AccessController.checkPermission(AccessController.java:553)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
    at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
    at java.io.File.exists(File.java:748)
    at org.python.core.PyFile._setup(Unknown Source)
    at org.python.core.PyFile.file_init(Unknown Source)
    at org.python.core.PyFile$1.new_impl(Unknown Source)
    at org.python.core.PyType.invoke_new_(Unknown Source)
    at org.python.core.PyType.type___call__(Unknown Source)
    at org.python.core.PyType.__call__(Unknown Source)
    at org.python.core.PyObject.__call__(Unknown Source)
    at org.python.pycode._pyx2.f$0(<console>:1)
    at org.python.pycode._pyx2.call_function(<console>)
    at org.python.core.PyTableCode.call(Unknown Source)
    at org.python.core.PyCode.call(Unknown Source)
    at org.python.core.Py.runCode(Unknown Source)
    at org.python.core.Py.exec(Unknown Source)
    at org.python.util.PythonInterpreter.exec(Unknown Source)
    at org.python.util.InteractiveInterpreter.runcode(Unknown Source)
    at org.python.util.InteractiveInterpreter.runsource(Unknown Source)
    at org.python.util.InteractiveInterpreter.runsource(Unknown Source)
    at org.python.util.InteractiveConsole.push(Unknown Source)
    at org.python.util.InteractiveConsole.interact(Unknown Source)
    at org.python.util.jython.main(Unknown Source)

java.security.AccessControlException: java.security.AccessControlException: access denied (java.io.FilePermission /tmp/test.txt read)
>>> 
Community
  • 1
  • 1
Adam Zalcman
  • 26,643
  • 4
  • 71
  • 92
  • Thanks for posting this policy; I don't think it exists anywhere else. I posted a few other necessary permissions in an answer below (rightfully a comment if comments allowed code formatting). – Travis Wilson Nov 05 '13 at 23:17
0

With jython 2.5.2 I found these permissions necessary:

permission java.io.FilePermission "${user.dir}${/}path${/}to${/}python${/}-", "read";
permission java.util.PropertyPermission "user.dir", "read";
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission java.lang.RuntimePermission "createClassLoader";
permission java.lang.RuntimePermission "getProtectionDomain";

(This should be a comment to the accepted answer, except that a comment won't format legibly.)

Travis Wilson
  • 949
  • 9
  • 19