From b0c64910b08707ac2c68125a46c978119db8182b Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Fri, 4 Dec 2015 15:58:02 -0500 Subject: [PATCH] ban RuntimePermission("getClassLoader") this gives more isolation between modules and plugins. --- .../elasticsearch/bootstrap/security.policy | 3 --- .../discovery/ec2/Ec2DiscoveryPlugin.java | 23 ++++++++++++++++ .../plugin-metadata/plugin-security.policy | 26 ++++++++++++++++++ .../script/expression/ExpressionPlugin.java | 27 +++++++++++++++++++ .../plugin-metadata/plugin-security.policy | 2 ++ .../groovy/GroovyScriptEngineService.java | 21 ++++++++++----- .../plugin-metadata/plugin-security.policy | 2 ++ .../plugin-metadata/plugin-security.policy | 2 ++ .../repository/s3/S3RepositoryPlugin.java | 24 +++++++++++++++++ .../plugin-metadata/plugin-security.policy | 24 +++++++++++++++++ 10 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 plugins/discovery-ec2/src/main/plugin-metadata/plugin-security.policy create mode 100644 plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy diff --git a/core/src/main/resources/org/elasticsearch/bootstrap/security.policy b/core/src/main/resources/org/elasticsearch/bootstrap/security.policy index b620a32fd0f..7e060cd6d90 100644 --- a/core/src/main/resources/org/elasticsearch/bootstrap/security.policy +++ b/core/src/main/resources/org/elasticsearch/bootstrap/security.policy @@ -84,9 +84,6 @@ grant { // the bug says it only happened rarely, and that its fixed, but apparently it still happens rarely! permission java.util.PropertyPermission "sun.nio.ch.bugLevel", "write"; - // needed by lucene SPI currently - permission java.lang.RuntimePermission "getClassLoader"; - // needed by Settings permission java.lang.RuntimePermission "getenv.*"; diff --git a/plugins/discovery-ec2/src/main/java/org/elasticsearch/plugin/discovery/ec2/Ec2DiscoveryPlugin.java b/plugins/discovery-ec2/src/main/java/org/elasticsearch/plugin/discovery/ec2/Ec2DiscoveryPlugin.java index a95d1a73a75..ffa76c6b9b3 100644 --- a/plugins/discovery-ec2/src/main/java/org/elasticsearch/plugin/discovery/ec2/Ec2DiscoveryPlugin.java +++ b/plugins/discovery-ec2/src/main/java/org/elasticsearch/plugin/discovery/ec2/Ec2DiscoveryPlugin.java @@ -19,6 +19,7 @@ package org.elasticsearch.plugin.discovery.ec2; +import org.elasticsearch.SpecialPermission; import org.elasticsearch.cloud.aws.AwsEc2ServiceImpl; import org.elasticsearch.cloud.aws.Ec2Module; import org.elasticsearch.common.component.LifecycleComponent; @@ -31,6 +32,8 @@ import org.elasticsearch.discovery.ec2.AwsEc2UnicastHostsProvider; import org.elasticsearch.discovery.ec2.Ec2Discovery; import org.elasticsearch.plugins.Plugin; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; @@ -38,6 +41,26 @@ import java.util.Collection; * */ public class Ec2DiscoveryPlugin extends Plugin { + + // ClientConfiguration clinit has some classloader problems + // TODO: fix that + static { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new SpecialPermission()); + } + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + try { + Class.forName("com.amazonaws.ClientConfiguration"); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + return null; + } + }); + } private final Settings settings; protected final ESLogger logger = Loggers.getLogger(Ec2DiscoveryPlugin.class); diff --git a/plugins/discovery-ec2/src/main/plugin-metadata/plugin-security.policy b/plugins/discovery-ec2/src/main/plugin-metadata/plugin-security.policy new file mode 100644 index 00000000000..42bd707b7b9 --- /dev/null +++ b/plugins/discovery-ec2/src/main/plugin-metadata/plugin-security.policy @@ -0,0 +1,26 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +grant { + // needed because of problems in ClientConfiguration + // TODO: get this fixed in aws sdk + // NOTE: no tests fail without this, but we know the problem + // exists in AWS sdk, and tests here are not thorough + permission java.lang.RuntimePermission "getClassLoader"; +}; diff --git a/plugins/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionPlugin.java b/plugins/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionPlugin.java index c1e2ed47dc4..48c7b4cb34d 100644 --- a/plugins/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionPlugin.java +++ b/plugins/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionPlugin.java @@ -19,10 +19,37 @@ package org.elasticsearch.script.expression; +import org.apache.lucene.expressions.js.JavascriptCompiler; +import org.elasticsearch.SpecialPermission; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.script.ScriptModule; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.ParseException; + public class ExpressionPlugin extends Plugin { + + // lucene expressions has crazy checks in its clinit for the functions map + // it violates rules of classloaders to detect accessibility + // TODO: clean that up + static { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new SpecialPermission()); + } + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + try { + JavascriptCompiler.compile("0"); + } catch (ParseException e) { + throw new RuntimeException(e); + } + return null; + } + }); + } @Override public String name() { diff --git a/plugins/lang-expression/src/main/plugin-metadata/plugin-security.policy b/plugins/lang-expression/src/main/plugin-metadata/plugin-security.policy index e45c1b86ceb..5bada15755e 100644 --- a/plugins/lang-expression/src/main/plugin-metadata/plugin-security.policy +++ b/plugins/lang-expression/src/main/plugin-metadata/plugin-security.policy @@ -20,4 +20,6 @@ grant { // needed to generate runtime classes permission java.lang.RuntimePermission "createClassLoader"; + // needed because of security problems in JavascriptCompiler + permission java.lang.RuntimePermission "getClassLoader"; }; diff --git a/plugins/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java b/plugins/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java index d1e7160282b..42ee05a7e03 100644 --- a/plugins/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java +++ b/plugins/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java @@ -172,13 +172,15 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri } String fake = MessageDigests.toHexString(MessageDigests.sha1().digest(script.getBytes(StandardCharsets.UTF_8))); // same logic as GroovyClassLoader.parseClass() but with a different codesource string: - GroovyCodeSource gcs = AccessController.doPrivileged(new PrivilegedAction() { - public GroovyCodeSource run() { - return new GroovyCodeSource(script, fake, BootstrapInfo.UNTRUSTED_CODEBASE); + return AccessController.doPrivileged(new PrivilegedAction() { + public Class run() { + GroovyCodeSource gcs = new GroovyCodeSource(script, fake, BootstrapInfo.UNTRUSTED_CODEBASE); + gcs.setCachable(false); + // TODO: we could be more complicated and paranoid, and move this to separate block, to + // sandbox the compilation process itself better. + return loader.parseClass(gcs); } }); - gcs.setCachable(false); - return loader.parseClass(gcs); } catch (Throwable e) { if (logger.isTraceEnabled()) { logger.trace("exception compiling Groovy script:", e); @@ -293,7 +295,14 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri @Override public Object run() { try { - return script.run(); + // NOTE: we truncate the stack because IndyInterface has security issue (needs getClassLoader) + // we don't do a security check just as a tradeoff, it cannot really escalate to anything. + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + return script.run(); + } + }); } catch (Throwable e) { if (logger.isTraceEnabled()) { logger.trace("failed to run " + compiledScript, e); diff --git a/plugins/lang-groovy/src/main/plugin-metadata/plugin-security.policy b/plugins/lang-groovy/src/main/plugin-metadata/plugin-security.policy index 55c2fab13f7..4481203994e 100644 --- a/plugins/lang-groovy/src/main/plugin-metadata/plugin-security.policy +++ b/plugins/lang-groovy/src/main/plugin-metadata/plugin-security.policy @@ -20,6 +20,8 @@ grant { // needed to generate runtime classes permission java.lang.RuntimePermission "createClassLoader"; + // needed by IndyInterface + permission java.lang.RuntimePermission "getClassLoader"; // needed by groovy engine permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect"; // needed by GroovyScriptEngineService to close its classloader (why?) diff --git a/plugins/lang-python/src/main/plugin-metadata/plugin-security.policy b/plugins/lang-python/src/main/plugin-metadata/plugin-security.policy index e45c1b86ceb..9ecbfdc7586 100644 --- a/plugins/lang-python/src/main/plugin-metadata/plugin-security.policy +++ b/plugins/lang-python/src/main/plugin-metadata/plugin-security.policy @@ -20,4 +20,6 @@ grant { // needed to generate runtime classes permission java.lang.RuntimePermission "createClassLoader"; + // needed by PySystemState init (TODO: see if we can avoid this) + permission java.lang.RuntimePermission "getClassLoader"; }; diff --git a/plugins/repository-s3/src/main/java/org/elasticsearch/plugin/repository/s3/S3RepositoryPlugin.java b/plugins/repository-s3/src/main/java/org/elasticsearch/plugin/repository/s3/S3RepositoryPlugin.java index 2911e278c38..a38a8ed3c51 100644 --- a/plugins/repository-s3/src/main/java/org/elasticsearch/plugin/repository/s3/S3RepositoryPlugin.java +++ b/plugins/repository-s3/src/main/java/org/elasticsearch/plugin/repository/s3/S3RepositoryPlugin.java @@ -19,6 +19,7 @@ package org.elasticsearch.plugin.repository.s3; +import org.elasticsearch.SpecialPermission; import org.elasticsearch.cloud.aws.S3Module; import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.inject.Module; @@ -27,6 +28,9 @@ import org.elasticsearch.plugins.Plugin; import org.elasticsearch.repositories.RepositoriesModule; import org.elasticsearch.repositories.s3.S3Repository; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -36,6 +40,26 @@ import java.util.Collections; */ public class S3RepositoryPlugin extends Plugin { + // ClientConfiguration clinit has some classloader problems + // TODO: fix that + static { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new SpecialPermission()); + } + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + try { + Class.forName("com.amazonaws.ClientConfiguration"); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + return null; + } + }); + } + @Override public String name() { return "repository-s3"; diff --git a/plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy b/plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy new file mode 100644 index 00000000000..62b29a2b78f --- /dev/null +++ b/plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +grant { + // needed because of problems in ClientConfiguration + // TODO: get this fixed in aws sdk + permission java.lang.RuntimePermission "getClassLoader"; +};