Clean up scripting permissions.
Now that groovy is factored out, we contain this dangerous stuff there. TODO: look into those test hacks inspecting class protection domains, maybe we can clean that one up too. TODO: generalize the GroovyCodeSourcePermission to something all script engines check, before entering accesscontrollerblocks. this way e.g. groovy script cannot coerce python engine into creating something with more privs if it gets ahold of it... we should probably protect the aws/gce hacks in the same way.
This commit is contained in:
parent
cbf894a2e7
commit
eeeb42abef
|
@ -166,6 +166,8 @@ final class Security {
|
||||||
m.put("repository-s3", "org.elasticsearch.plugin.repository.s3.S3RepositoryPlugin");
|
m.put("repository-s3", "org.elasticsearch.plugin.repository.s3.S3RepositoryPlugin");
|
||||||
m.put("discovery-ec2", "org.elasticsearch.plugin.discovery.ec2.Ec2DiscoveryPlugin");
|
m.put("discovery-ec2", "org.elasticsearch.plugin.discovery.ec2.Ec2DiscoveryPlugin");
|
||||||
m.put("cloud-gce", "org.elasticsearch.plugin.cloud.gce.CloudGcePlugin");
|
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-javascript", "org.elasticsearch.plugin.javascript.JavaScriptPlugin");
|
||||||
m.put("lang-python", "org.elasticsearch.plugin.python.PythonPlugin");
|
m.put("lang-python", "org.elasticsearch.plugin.python.PythonPlugin");
|
||||||
SPECIAL_PLUGINS = Collections.unmodifiableMap(m);
|
SPECIAL_PLUGINS = Collections.unmodifiableMap(m);
|
||||||
|
|
|
@ -57,6 +57,20 @@ grant codeBase "${es.security.plugin.cloud-gce}" {
|
||||||
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
|
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}" {
|
grant codeBase "${es.security.plugin.lang-javascript}" {
|
||||||
// needed to generate runtime classes
|
// needed to generate runtime classes
|
||||||
permission java.lang.RuntimePermission "createClassLoader";
|
permission java.lang.RuntimePermission "createClassLoader";
|
||||||
|
@ -106,6 +120,8 @@ grant codeBase "${es.security.jar.randomizedtesting.junit4}" {
|
||||||
grant {
|
grant {
|
||||||
|
|
||||||
// Allow executing groovy scripts with codesource of /groovy/script
|
// 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";
|
permission groovy.security.GroovyCodeSourcePermission "/groovy/script";
|
||||||
|
|
||||||
// Allow connecting to the internet anywhere
|
// Allow connecting to the internet anywhere
|
||||||
|
@ -114,15 +130,9 @@ grant {
|
||||||
// Allow read/write to all system properties
|
// Allow read/write to all system properties
|
||||||
permission java.util.PropertyPermission "*", "read,write";
|
permission java.util.PropertyPermission "*", "read,write";
|
||||||
|
|
||||||
// needed by scripting engines, etc
|
|
||||||
permission java.lang.RuntimePermission "createClassLoader";
|
|
||||||
|
|
||||||
// needed by lucene SPI currently
|
// needed by lucene SPI currently
|
||||||
permission java.lang.RuntimePermission "getClassLoader";
|
permission java.lang.RuntimePermission "getClassLoader";
|
||||||
|
|
||||||
// needed by GroovyScriptEngineService
|
|
||||||
permission java.lang.RuntimePermission "closeClassLoader";
|
|
||||||
|
|
||||||
// needed by Settings
|
// needed by Settings
|
||||||
permission java.lang.RuntimePermission "getenv.*";
|
permission java.lang.RuntimePermission "getenv.*";
|
||||||
|
|
||||||
|
@ -130,13 +140,11 @@ grant {
|
||||||
// otherwise can be provided only to test libraries
|
// otherwise can be provided only to test libraries
|
||||||
permission java.lang.RuntimePermission "modifyThread";
|
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";
|
permission java.lang.RuntimePermission "getProtectionDomain";
|
||||||
|
|
||||||
// reflection hacks:
|
|
||||||
// needed by groovy engine
|
|
||||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect";
|
|
||||||
|
|
||||||
// likely not low hanging fruit...
|
// likely not low hanging fruit...
|
||||||
permission java.lang.RuntimePermission "accessDeclaredMembers";
|
permission java.lang.RuntimePermission "accessDeclaredMembers";
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ import org.elasticsearch.script.SearchScript;
|
||||||
import org.elasticsearch.search.MultiValueMode;
|
import org.elasticsearch.search.MultiValueMode;
|
||||||
import org.elasticsearch.search.lookup.SearchLookup;
|
import org.elasticsearch.search.lookup.SearchLookup;
|
||||||
|
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -91,6 +93,10 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object compile(String script) {
|
public Object compile(String script) {
|
||||||
|
// classloader created here
|
||||||
|
return AccessController.doPrivileged(new PrivilegedAction<Expression>() {
|
||||||
|
@Override
|
||||||
|
public Expression run() {
|
||||||
try {
|
try {
|
||||||
// NOTE: validation is delayed to allow runtime vars, and we don't have access to per index stuff here
|
// NOTE: validation is delayed to allow runtime vars, and we don't have access to per index stuff here
|
||||||
return JavascriptCompiler.compile(script);
|
return JavascriptCompiler.compile(script);
|
||||||
|
@ -98,6 +104,8 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
|
||||||
throw new ScriptException("Failed to parse expression: " + script, e);
|
throw new ScriptException("Failed to parse expression: " + script, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) {
|
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) {
|
||||||
|
|
|
@ -423,6 +423,7 @@ public class MoreExpressionTests extends ESIntegTestCase {
|
||||||
|
|
||||||
// series of unit test for using expressions as executable scripts
|
// series of unit test for using expressions as executable scripts
|
||||||
public void testExecutableScripts() throws Exception {
|
public void testExecutableScripts() throws Exception {
|
||||||
|
assumeTrue("test creates classes directly, cannot run with security manager", System.getSecurityManager() == null);
|
||||||
Map<String, Object> vars = new HashMap<>();
|
Map<String, Object> vars = new HashMap<>();
|
||||||
vars.put("a", 2.5);
|
vars.put("a", 2.5);
|
||||||
vars.put("b", 3);
|
vars.put("b", 3);
|
||||||
|
|
|
@ -20,10 +20,13 @@
|
||||||
package org.elasticsearch.script.groovy;
|
package org.elasticsearch.script.groovy;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
|
|
||||||
import groovy.lang.Binding;
|
import groovy.lang.Binding;
|
||||||
import groovy.lang.GroovyClassLoader;
|
import groovy.lang.GroovyClassLoader;
|
||||||
import groovy.lang.Script;
|
import groovy.lang.Script;
|
||||||
|
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
|
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
|
||||||
|
@ -49,6 +52,8 @@ import org.elasticsearch.search.lookup.SearchLookup;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -99,17 +104,30 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
|
||||||
}
|
}
|
||||||
|
|
||||||
// Groovy class loader to isolate Groovy-land code
|
// 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
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
loader.clearCache();
|
loader.clearCache();
|
||||||
|
// close classloader here (why do we do this?)
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void run() {
|
||||||
try {
|
try {
|
||||||
loader.close();
|
loader.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Unable to close Groovy loader", e);
|
logger.warn("Unable to close Groovy loader", e);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue