I am currently working on developing a small Java application in which trusted code must be run alongside untrusted code. To accomplish this, I have installed a custom SecurityManager
that throws SecurityException
s any time a permission is checked.
As a bridge between the trusted and untrusted code, I have a thread that uses Constructor.newInstance()
to instantiate an object of an untrusted type. At the time that it makes this call, the security manager is configured to block everything. Interestingly, the first 15 times that I try to create objects using Constructor.newInstance()
, everything works fine, but the 16th time I get a SecurityException
.
I've managed to get this down to a simple test program:
import java.lang.reflect.*;
import java.security.*;
public class Main {
/* Track how many instances have been created so that we can see when the exception
* is thrown.
*/
private static int numInstances = 0;
public Main() {
System.out.println("Number created: " + ++numInstances);
}
public static void main(String[] args) {
/* Get the constructor for Main so that we can instantiate everything
* later on.
*/
Constructor<Main> ctor;
try {
ctor = Main.class.getConstructor();
} catch (NoSuchMethodException e) {
e.printStackTrace();
return;
}
/* Install a super prohibitive security manager that disallows all operations. */
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPermission(Permission p) {
/* Nothing is allowed - any permission check causes a security
* exception.
*/
throw new SecurityException("Not permitted: " + p);
}
});
/* Continuously create new Main objects. */
try {
while (true) {
ctor.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
This program installs a SecurityManager
whose checkPermission
always throws an exception regardless of what permission is requested. It then sits in a loop and uses ctor.newInstance()
to instantiate a harmless Main
object that prints out the number of instances generated so far. The output of this program, on my system, is as follows:
Number created: 1
Number created: 2
Number created: 3
Number created: 4
Number created: 5
Number created: 6
Number created: 7
Number created: 8
Number created: 9
Number created: 10
Number created: 11
Number created: 12
Number created: 13
Number created: 14
Number created: 15
java.lang.SecurityException: Not permitted: ("java.lang.RuntimePermission" "createClassLoader")
at Main$1.checkPermission(Main.java:32)
at java.lang.SecurityManager.checkCreateClassLoader(SecurityManager.java:611)
at java.lang.ClassLoader.checkCreateClassLoader(ClassLoader.java:274)
at java.lang.ClassLoader.<init>(ClassLoader.java:316)
at sun.reflect.DelegatingClassLoader.<init>(ClassDefiner.java:72)
at sun.reflect.ClassDefiner$1.run(ClassDefiner.java:60)
at sun.reflect.ClassDefiner$1.run(ClassDefiner.java:58)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:57)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:399)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:396)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:395)
at sun.reflect.MethodAccessorGenerator.generateConstructor(MethodAccessorGenerator.java:94)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:48)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at Main.main(Main.java:39)
According to the Javadoc for RuntimePermission
, the createClassLoader
permission is a risky one to grant:
This is an extremely dangerous permission to grant. Malicious applications that can instantiate their own class loaders could then load their own rogue classes into the system. These newly loaded classes could be placed into any protection domain by the class loader, thereby automatically granting the classes the permissions for that domain.
I have two questions:
What specifically is causing this error? Why is it that on the 16th time around, I get a request for a classloader? I suspect this has to do with Java trying to optimize the reflection by generating bytecode to directly instantiate the object, but I'm not sure.
Without whitelisting the
createClassLoader
privilege, which is dangerous, is there a way to instantiate the untrusted objects from trusted code?Am I fundamentally approaching this the wrong way?
Thanks!
checkPermission
gets called 3 times before creating the 16th instance. – Augusto