filebot/source/net/filebot/format/SecureCompiledScript.java

108 lines
4.1 KiB
Java

package net.filebot.format;
import java.awt.AWTPermission;
import java.io.File;
import java.io.FilePermission;
import java.lang.management.ManagementPermission;
import java.lang.reflect.ReflectPermission;
import java.net.SocketPermission;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.PropertyPermission;
import java.util.logging.LoggingPermission;
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import net.filebot.ApplicationFolder;
import net.filebot.util.ExceptionUtilities;
public class SecureCompiledScript extends CompiledScript {
public static PermissionCollection getDefaultSandboxPermissions() {
Permissions permissions = new Permissions();
// give up on real security, just try to keep files read-only (because of classloading and native lib loading issues)
permissions.add(new RuntimePermission("createClassLoader"));
permissions.add(new RuntimePermission("getClassLoader"));
permissions.add(new RuntimePermission("modifyThread"));
permissions.add(new RuntimePermission("modifyThreadGroup"));
permissions.add(new RuntimePermission("loadLibrary.*"));
permissions.add(new RuntimePermission("accessClassInPackage.*"));
permissions.add(new RuntimePermission("accessDeclaredMembers"));
permissions.add(new RuntimePermission("canProcessApplicationEvents"));
permissions.add(new RuntimePermission("getenv.*"));
permissions.add(new RuntimePermission("getFileSystemAttributes"));
permissions.add(new RuntimePermission("readFileDescriptor"));
permissions.add(new RuntimePermission("preferences"));
permissions.add(new AWTPermission("toolkitModality"));
permissions.add(new AWTPermission("setWindowAlwaysOnTop"));
permissions.add(new AWTPermission("showWindowWithoutWarningBanner"));
permissions.add(new FilePermission("<<ALL FILES>>", "read"));
permissions.add(new SocketPermission("*", "connect"));
permissions.add(new PropertyPermission("*", "read"));
permissions.add(new PropertyPermission("*", "write"));
permissions.add(new LoggingPermission("control", null));
permissions.add(new ManagementPermission("monitor"));
permissions.add(new ReflectPermission("suppressAccessChecks"));
permissions.add(new ReflectPermission("newProxyInPackage.*"));
// write permissions for cache and temp folders
for (ApplicationFolder it : ApplicationFolder.values()) {
permissions.add(new FilePermission(it.getFile().getAbsolutePath() + File.separator + "-", "read, write, delete"));
}
return permissions;
}
private final CompiledScript compiledScript;
private final AccessControlContext sandbox;
public SecureCompiledScript(CompiledScript compiledScript) {
this(compiledScript, new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, getDefaultSandboxPermissions()) }));
}
public SecureCompiledScript(CompiledScript compiledScript, AccessControlContext sandbox) {
this.compiledScript = compiledScript;
this.sandbox = sandbox;
}
@Override
public Object eval(final ScriptContext context) throws ScriptException {
try {
return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws ScriptException {
return compiledScript.eval(context);
}
}, sandbox);
} catch (PrivilegedActionException e) {
AccessControlException accessException = ExceptionUtilities.findCause(e, AccessControlException.class);
// try to unwrap AccessControlException
if (accessException != null)
throw new ExpressionException(accessException);
// forward ScriptException
// e.getException() should be an instance of ScriptException,
// as only "checked" exceptions will be "wrapped" in a PrivilegedActionException
throw (ScriptException) e.getException();
}
}
@Override
public ScriptEngine getEngine() {
return compiledScript.getEngine();
}
}