Merge pull request #13844 from rmuir/lock_down_classloader_and_reflection

Clean up scripting permissions.
This commit is contained in:
Robert Muir 2015-09-29 10:35:52 -04:00
commit d54dd63825
5 changed files with 60 additions and 23 deletions

View File

@ -166,6 +166,8 @@ final class Security {
m.put("repository-s3", "org.elasticsearch.plugin.repository.s3.S3RepositoryPlugin");
m.put("discovery-ec2", "org.elasticsearch.plugin.discovery.ec2.Ec2DiscoveryPlugin");
m.put("cloud-gce", "org.elasticsearch.plugin.cloud.gce.CloudGcePlugin");
m.put("lang-expression", "org.elasticsearch.script.expression.ExpressionPlugin");
m.put("lang-groovy", "org.elasticsearch.script.groovy.GroovyPlugin");
m.put("lang-javascript", "org.elasticsearch.plugin.javascript.JavaScriptPlugin");
m.put("lang-python", "org.elasticsearch.plugin.python.PythonPlugin");
SPECIAL_PLUGINS = Collections.unmodifiableMap(m);

View File

@ -57,6 +57,20 @@ grant codeBase "${es.security.plugin.cloud-gce}" {
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
grant codeBase "${es.security.plugin.lang-expression}" {
// needed to generate runtime classes
permission java.lang.RuntimePermission "createClassLoader";
};
grant codeBase "${es.security.plugin.lang-groovy}" {
// needed to generate runtime classes
permission java.lang.RuntimePermission "createClassLoader";
// needed by groovy engine
permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect";
// needed by GroovyScriptEngineService to close its classloader (why?)
permission java.lang.RuntimePermission "closeClassLoader";
};
grant codeBase "${es.security.plugin.lang-javascript}" {
// needed to generate runtime classes
permission java.lang.RuntimePermission "createClassLoader";
@ -106,6 +120,8 @@ grant codeBase "${es.security.jar.randomizedtesting.junit4}" {
grant {
// Allow executing groovy scripts with codesource of /groovy/script
// TODO: make our own general ScriptServicePermission we check instead and
// check-before-createClassLoader for all scripting engines.
permission groovy.security.GroovyCodeSourcePermission "/groovy/script";
// Allow connecting to the internet anywhere
@ -114,15 +130,9 @@ grant {
// Allow read/write to all system properties
permission java.util.PropertyPermission "*", "read,write";
// needed by scripting engines, etc
permission java.lang.RuntimePermission "createClassLoader";
// needed by lucene SPI currently
permission java.lang.RuntimePermission "getClassLoader";
// needed by GroovyScriptEngineService
permission java.lang.RuntimePermission "closeClassLoader";
// needed by Settings
permission java.lang.RuntimePermission "getenv.*";
@ -130,12 +140,10 @@ grant {
// otherwise can be provided only to test libraries
permission java.lang.RuntimePermission "modifyThread";
// needed by groovy scripting
// needed by ExceptionSerializationTests and RestTestCase for
// some hackish things they do. otherwise only needed by groovy
// (TODO: clean this up?)
permission java.lang.RuntimePermission "getProtectionDomain";
// reflection hacks:
// needed by groovy engine
permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect";
// likely not low hanging fruit...
permission java.lang.RuntimePermission "accessDeclaredMembers";

View File

@ -43,6 +43,8 @@ import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.MultiValueMode;
import org.elasticsearch.search.lookup.SearchLookup;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Map;
@ -91,12 +93,18 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
@Override
public Object compile(String script) {
try {
// NOTE: validation is delayed to allow runtime vars, and we don't have access to per index stuff here
return JavascriptCompiler.compile(script);
} catch (ParseException e) {
throw new ScriptException("Failed to parse expression: " + script, e);
}
// classloader created here
return AccessController.doPrivileged(new PrivilegedAction<Expression>() {
@Override
public Expression run() {
try {
// NOTE: validation is delayed to allow runtime vars, and we don't have access to per index stuff here
return JavascriptCompiler.compile(script);
} catch (ParseException e) {
throw new ScriptException("Failed to parse expression: " + script, e);
}
}
});
}
@Override

View File

@ -423,6 +423,7 @@ public class MoreExpressionTests extends ESIntegTestCase {
// series of unit test for using expressions as executable scripts
public void testExecutableScripts() throws Exception {
assumeTrue("test creates classes directly, cannot run with security manager", System.getSecurityManager() == null);
Map<String, Object> vars = new HashMap<>();
vars.put("a", 2.5);
vars.put("b", 3);

View File

@ -20,10 +20,13 @@
package org.elasticsearch.script.groovy;
import java.nio.charset.StandardCharsets;
import com.google.common.hash.Hashing;
import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.Script;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.Scorer;
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
@ -49,6 +52,8 @@ import org.elasticsearch.search.lookup.SearchLookup;
import java.io.IOException;
import java.math.BigDecimal;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
@ -99,17 +104,30 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
}
// Groovy class loader to isolate Groovy-land code
this.loader = new GroovyClassLoader(getClass().getClassLoader(), config);
// classloader created here
this.loader = AccessController.doPrivileged(new PrivilegedAction<GroovyClassLoader>() {
@Override
public GroovyClassLoader run() {
return new GroovyClassLoader(getClass().getClassLoader(), config);
}
});
}
@Override
public void close() {
loader.clearCache();
try {
loader.close();
} catch (IOException e) {
logger.warn("Unable to close Groovy loader", e);
}
// close classloader here (why do we do this?)
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
loader.close();
} catch (IOException e) {
logger.warn("Unable to close Groovy loader", e);
}
return null;
}
});
}
@Override