问题
When trying to implement a sandbox in a plugin-like environment, I came accross https://stackoverflow.com/a/5580239/2057294 which seems to be exactly what I want, however I am unable to get it working, what am I doing wrong?
I have the following setup:
final class ModURLClassLoader extends URLClassLoader {
ModURLClassLoader(final URL[] urls) {
super(urls);
}
ModURLClassLoader(final URL[] urls, final ClassLoader parent) {
super(urls, parent);
}
ModURLClassLoader(final URL[] urls, final ClassLoader parent, final URLStreamHandlerFactory factory) {
super(urls, parent, factory);
}
@Override
protected PermissionCollection getPermissions(final CodeSource codesource) {
PermissionCollection permissionCollection = super.getPermissions(codesource);
//give no permissions to the codesource
return permissionCollection;
}
@Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
int i = name.lastIndexOf('.');
if (i != -1) {
sm.checkPackageAccess(name.substring(0, i));
}
}
return super.loadClass(name, resolve);
}
}
The idea here is that code loaded through the ModURLClassLoader may have no permissions at all. I do want to be able to add extra permissions statically in case I block some permissions which a mod would generally want to have.
Then I load up my classes via the following:
public class JavaMod extends LoadableMod {
private ECSMod ecsMod;
private ModURLClassLoader modUrlClassLoader;
JavaMod(final Path modDirectory) throws ModNotLoadableException {
super(modDirectory);
}
@Override
protected void load0() throws ModNotLoadableException {
try {
Properties properties = ModLoaderHelper.getConfiguration(modDirectory);
String jarName = properties.getProperty("jar");
String entryPoint = properties.getProperty("entryPoint");
Path jarPath = modDirectory.resolve(jarName);
try {
modUrlClassLoader = AccessController.doPrivileged((PrivilegedExceptionAction<ModURLClassLoader>)() -> new ModURLClassLoader(new URL[] { jarPath.toUri().toURL() }, getClass().getClassLoader()));
} catch (PrivilegedActionException ex) {
throw new ModNotLoadableException(ex);
}
Class<?> clazz = Class.forName(entryPoint, false, modUrlClassLoader);
if (!ECSMod.class.isAssignableFrom(clazz)) {
throw new ModNotLoadableException(clazz + " does not implement ECSMod");
}
this.ecsMod = (ECSMod)clazz.newInstance();
} catch (Exception ex) {
throw new ModNotLoadableException(ex);
}
}
@Override
protected void unload0() {
try {
modUrlClassLoader.close();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
@Override
protected ECSGame createGame0() {
ECSGame ecsGame = new ECSGame();
ecsMod.setupGame(ecsGame);
return ecsGame;
}
}
Which loads an untrusted JAR that has a class that implements ECSMod, I have confirmed that both the clazz and ecsMod belong to an instance of ModURLClassLoader.
Then the malicious code:
public final class UntrustedEvilMod implements ECSMod {
@Override
public void setupGame(final ECSGame game) {
System.exit(0);
}
}
Where ECSMod and ECSGame are classes that belong to the plugin (also called mod) API and reside in the original classloader.
I'm running this without a security manager, as I believe that this would be unnecessary in this context? As the ModURLClassLoader defines the security.
Why is this not working, meaning that it still causes the program to exit, whereas I would've wanted an AccessControlException?
来源:https://stackoverflow.com/questions/26340118/extending-urlclassloader-and-overriding-getpermissions-does-not-work