Remove java.lang.reflect.ReflectPermission "suppressAccessChecks"

Closes #13603

Squashed commit of the following:

commit 8799fb42d80297a79285beaf407b1bbecdb5854d
Author: Robert Muir <rmuir@apache.org>
Date:   Wed Sep 16 03:32:29 2015 -0400

    Add randomizedtesting snapshot note

commit 0d874d9f0f5fddaeab8f48f9816a052dcaa691be
Author: Robert Muir <rmuir@apache.org>
Date:   Wed Sep 16 03:11:01 2015 -0400

    Add a mechanism for insecure plugins and get all tests passing

commit 80540aeb9a264f6f299aaa3bc89df7f9b7923a60
Author: Robert Muir <rmuir@apache.org>
Date:   Tue Sep 15 22:59:29 2015 -0400

    Really remove, we are killing this

commit 884818c1ad44ca2e7572a6998c086580be919657
Author: Robert Muir <rmuir@apache.org>
Date:   Tue Sep 15 22:57:22 2015 -0400

    fill in TODOs

commit 34f4cb81f249edfec4d8d211da892f8c987e5948
Author: Robert Muir <rmuir@apache.org>
Date:   Tue Sep 15 22:31:43 2015 -0400

    Publish snapshots of RR and lucene and cutover

commit d68eb9d66ce059761805c64d67e41a29098c9afa
Merge: f27e208 f62da59
Author: Robert Muir <rmuir@apache.org>
Date:   Tue Sep 15 12:32:41 2015 -0400

    Merge branch 'master' into kill-setaccessible

commit f27e20855216dab6a6ad035d41018d8c67f3144c
Author: Robert Muir <rmuir@apache.org>
Date:   Tue Sep 15 12:32:21 2015 -0400

    make a real lucene snapshot
This commit is contained in:
Robert Muir 2015-09-16 04:04:51 -04:00
parent 76b027a979
commit 01e6d8e3dc
48 changed files with 206 additions and 26 deletions

View File

@ -19,6 +19,9 @@
package org.elasticsearch.bootstrap;
import java.util.Collections;
import java.util.Set;
/**
* Exposes system startup information
*/
@ -43,4 +46,14 @@ public final class BootstrapInfo {
public static boolean isMemoryLocked() {
return Natives.isMemoryLocked();
}
/**
* Returns set of insecure plugins.
* <p>
* These are plugins with unresolved issues in third-party libraries,
* that require additional privileges as a workaround.
*/
public static Set<String> getInsecurePluginList() {
return Collections.unmodifiableSet(Security.INSECURE_PLUGINS.keySet());
}
}

View File

@ -20,11 +20,14 @@
package org.elasticsearch.bootstrap;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.env.Environment;
import java.io.*;
import java.net.URL;
import java.nio.file.AccessMode;
import java.nio.file.DirectoryStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.NotDirectoryException;
@ -32,6 +35,7 @@ import java.nio.file.Path;
import java.security.Permissions;
import java.security.Policy;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.regex.Pattern;
@ -95,6 +99,8 @@ final class Security {
static void configure(Environment environment) throws Exception {
// set properties for jar locations
setCodebaseProperties();
// set properties for problematic plugins
setPluginCodebaseProperties(environment);
// enable security policy: union of template and environment-based paths.
Policy.setPolicy(new ESPolicy(createPermissions(environment)));
@ -121,6 +127,9 @@ final class Security {
static {
Map<Pattern,String> m = new IdentityHashMap<>();
m.put(Pattern.compile(".*lucene-core-.*\\.jar$"), "es.security.jar.lucene.core");
m.put(Pattern.compile(".*lucene-test-framework-.*\\.jar$"), "es.security.jar.lucene.testframework");
m.put(Pattern.compile(".*randomizedtesting-runner-.*\\.jar$"), "es.security.jar.randomizedtesting.runner");
m.put(Pattern.compile(".*junit4-ant-.*\\.jar$"), "es.security.jar.randomizedtesting.junit4");
m.put(Pattern.compile(".*securemock-.*\\.jar$"), "es.security.jar.elasticsearch.securemock");
SPECIAL_JARS = Collections.unmodifiableMap(m);
}
@ -150,6 +159,46 @@ final class Security {
}
}
// mapping of insecure plugins to codebase properties
// note that this is only read once, when policy is parsed.
static final Map<String,String> INSECURE_PLUGINS;
static {
Map<String,String> m = new HashMap<>();
m.put("repository-s3", "es.security.insecure.plugin.repository-s3");
m.put("discovery-ec2", "es.security.insecure.plugin.discovery-ec2");
m.put("cloud-gce", "es.security.insecure.plugin.cloud-gce" );
INSECURE_PLUGINS = Collections.unmodifiableMap(m);
}
/**
* Sets properties (codebase URLs) for policy files.
* we look for matching plugins and set URLs to fit
*/
@SuppressForbidden(reason = "proper use of URL")
static void setPluginCodebaseProperties(Environment environment) throws IOException {
if (Files.exists(environment.pluginsFile())) {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(environment.pluginsFile())) {
for (Path plugin : stream) {
String prop = INSECURE_PLUGINS.get(plugin.getFileName().toString());
if (prop != null) {
if (System.getProperty(prop) != null) {
throw new IllegalStateException("property: " + prop + " is unexpectedly set: " + System.getProperty(prop));
}
System.setProperty(prop, plugin.toUri().toURL().toString() + "*");
ESLogger logger = Loggers.getLogger(Security.class);
logger.warn("Adding permissions for insecure plugin [{}]", plugin.getFileName());
logger.warn("There are unresolved issues with third-party code that may reduce the security of the system");
}
}
}
}
for (String prop : INSECURE_PLUGINS.values()) {
if (System.getProperty(prop) == null) {
System.setProperty(prop, "file:/dev/null"); // no chance to be interpreted as "all"
}
}
}
/** returns dynamic Permissions to configured paths */
static Permissions createPermissions(Environment environment) throws IOException {
Permissions policy = new Permissions();

View File

@ -34,6 +34,27 @@ grant codeBase "file:${{java.ext.dirs}}/*" {
grant codeBase "${es.security.jar.lucene.core}" {
// needed to allow MMapDirectory's "unmap hack"
permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
//// Insecure plugin permissions:
//// These are dangerous permissions due to problems in third-party library code
//// We try our best to contain and protect the issues, but ultimately warn the user
//// when installing these plugins that it can introduce a security risk
grant codeBase "${es.security.insecure.plugin.repository-s3}" {
// needed because of problems in aws-sdk
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
grant codeBase "${es.security.insecure.plugin.discovery-ec2}" {
// needed because of problems in aws-sdk
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
grant codeBase "${es.security.insecure.plugin.cloud-gce}" {
// needed because of problems in cloud-gce
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
//// test framework permissions.
@ -43,6 +64,22 @@ grant codeBase "${es.security.jar.lucene.core}" {
grant codeBase "${es.security.jar.elasticsearch.securemock}" {
// needed to support creation of mocks
permission java.lang.RuntimePermission "reflectionFactoryAccess";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
grant codeBase "${es.security.jar.lucene.testframework}" {
// needed by RamUsageTester
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
grant codeBase "${es.security.jar.randomizedtesting.runner}" {
// optionally needed for access to private test methods (e.g. beforeClass)
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
grant codeBase "${es.security.jar.randomizedtesting.junit4}" {
// needed for gson serialization
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
//// Everything else:
@ -58,9 +95,6 @@ grant {
// Allow read/write to all system properties
permission java.util.PropertyPermission "*", "read,write";
// needed by junit4's gson usage
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
// needed by scripting engines, etc
permission java.lang.RuntimePermission "createClassLoader";

View File

@ -83,6 +83,13 @@ public class BootstrapForTesting {
if (systemPropertyAsBoolean("tests.security.manager", true)) {
try {
Security.setCodebaseProperties();
// if its an insecure plugin, its not easy to simulate here, since we don't have a real plugin install.
// we just do our best so unit testing can work. integration tests for such plugins are essential.
String artifact = System.getProperty("tests.artifact");
String insecurePluginProp = Security.INSECURE_PLUGINS.get(artifact);
if (insecurePluginProp != null) {
System.setProperty(insecurePluginProp, "file:/-");
}
// initialize paths the same exact way as bootstrap.
Permissions perms = new Permissions();
// add permissions to everything in classpath
@ -117,6 +124,15 @@ public class BootstrapForTesting {
Policy.setPolicy(new ESPolicy(perms));
System.setSecurityManager(new TestSecurityManager());
Security.selfTest();
if (insecurePluginProp != null) {
// initialize the plugin class, in case it has one-time hacks (unit tests often won't do this)
String clazz = System.getProperty("tests.plugin.classname");
if (clazz == null) {
throw new IllegalStateException("plugin classname is needed for insecure plugin unit tests");
}
Class.forName(clazz);
}
} catch (Exception e) {
throw new RuntimeException("unable to install test security manager", e);
}

View File

@ -1 +0,0 @@
8243b938b75818e86aa8d270d8d99529e1847578

View File

@ -0,0 +1 @@
5792c4b38aa2cf1f66c9dea8bf139907e33fa018

View File

@ -1 +0,0 @@
ba85c6e5e77e1f76c52c31d34a59558afa135d47

View File

@ -0,0 +1 @@
cd6fa25bc29718d8c964b0734fc9a009547453db

View File

@ -1 +0,0 @@
f8a38658b6393015c9b33c16b1b4122167b526b2

View File

@ -0,0 +1 @@
e4e0076ce4331309d1270a9c5b2edb51915fe32a

View File

@ -1 +0,0 @@
fa5d27ecadbe346caaf5a571ba71944b51761acf

View File

@ -0,0 +1 @@
ecfb9a923b19fac61b4e9a79275f6bd242b1f091

View File

@ -1 +0,0 @@
2c1464fcf6ede7819f8ba434b9bc7c79f5968407

View File

@ -0,0 +1 @@
49992ef742b6d3a24b551e06c96c0ab9cbad21e7

View File

@ -1 +0,0 @@
a40f9a3ef224bc042ef2ad1b713e318911b6057a

View File

@ -0,0 +1 @@
85544da78c2d33b2fdfa6f76eb621c8c963eae37

View File

@ -1 +0,0 @@
0a7642c9b98cb3d9013fb33be5c0751baf9f0b31

View File

@ -0,0 +1 @@
5c8b58d902a01cfce046e656eddee5c4e0578316

View File

@ -1 +0,0 @@
a0d6461ab9cda93ea530560b0c074a28fe0dd717

View File

@ -0,0 +1 @@
55202617e88437dd6def4e42ceb42d18d08a9f6e

View File

@ -1 +0,0 @@
85c5c7b78715c50157700c90ffd101537446533d

View File

@ -0,0 +1 @@
50b8439558061d0bbf09ddf8144d769143d33f00

View File

@ -1 +0,0 @@
70ca782d6ed458b5f777141353e09600083ed4fe

View File

@ -0,0 +1 @@
ce470e38912676ebc63838635663f17d8db844f5

View File

@ -1 +0,0 @@
b4832cdfe7a6cc7c586a3e28d7cd530acb182232

View File

@ -0,0 +1 @@
318e192d61eb28de09cc62c42d4e9d044a497e8b

View File

@ -1 +0,0 @@
bde73ae2b2324e1576c5789a7e6dd88b6543b939

View File

@ -0,0 +1 @@
043b3c3c03a5e0687884e5894754933d7e8f2f3e

View File

@ -1 +0,0 @@
8d261ff1c2333ce1e040c3aefca9784d1ae71acc

View File

@ -0,0 +1 @@
a9ab07d808456d9a2de248f3b4eba9765808b1cb

View File

@ -1 +0,0 @@
ee041e52dfcdb33a1aa6fab112042b5f33fc0c0c

View File

@ -0,0 +1 @@
c9ae48e40c89364e0e69f27c514c924d52e0d57e

View File

@ -1 +0,0 @@
a8ceb11b26e53612eee9a265ff454351f6dc99f2

View File

@ -0,0 +1 @@
8bd8fb7e75746fd7bce00b4d2813fca738d68f0b

View File

@ -1 +0,0 @@
1f92d0376ca9219b0bf96fe5bd9a913089608d6a

View File

@ -0,0 +1 @@
a71d7e2780ae064a6e6ea5b43357d070351620b8

View File

@ -1 +0,0 @@
60ee5bc1ac8ec102434e7064141a1f40281918b5

View File

@ -0,0 +1 @@
a82b7a125e7cc16c6eb050b68bafc9f1e63eb646

View File

@ -1 +0,0 @@
977aa506485d358b40602347c11238b0f912fe2c

View File

@ -0,0 +1 @@
64b4db89ab7612284b5c685769c3550fb3018bbc

View File

@ -1 +0,0 @@
61911b8400160bd206ea6ea46ba08fd9ba09e72b

View File

@ -0,0 +1 @@
a79e5ed1671d9f511c5aff273ba287557f5f9103

View File

@ -1 +0,0 @@
5a9bdf48b63562bf1ac8a73c1c6bdb4cc450439e

View File

@ -0,0 +1 @@
7b0b74aebbbfdd2175d6ce045fc538261e016417

View File

@ -27,6 +27,7 @@ import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.compute.Compute;
import com.google.api.services.compute.model.Instance;
import com.google.api.services.compute.model.InstanceList;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.inject.Inject;
@ -34,7 +35,9 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import java.io.IOException;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.security.PrivilegedExceptionAction;
import java.util.*;
/**
@ -122,7 +125,15 @@ public class GceComputeServiceImpl extends AbstractLifecycleComponent<GceCompute
.setTokenServerEncodedUrl(TOKEN_SERVER_ENCODED_URL)
.build();
credential.refreshToken();
// hack around code messiness in GCE code
// TODO: get this fixed
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws IOException {
credential.refreshToken();
return null;
}
});
logger.debug("token [{}] will expire in [{}] s", credential.getAccessToken(), credential.getExpiresInSeconds());
if (credential.getExpiresInSeconds() != null) {

View File

@ -28,6 +28,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;
@ -35,6 +37,23 @@ import java.util.Collection;
*
*/
public class Ec2DiscoveryPlugin extends Plugin {
static {
// This internal config is deserialized but with wrong access modifiers,
// cannot work without suppressAccessChecks permission right now. We force
// a one time load with elevated privileges as a workaround.
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
Class.forName("com.amazonaws.internal.config.InternalConfig$Factory");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to initialize internal aws config", e);
}
return null;
}
});
}
@Override
public String name() {

View File

@ -27,6 +27,8 @@ 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.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -35,6 +37,23 @@ import java.util.Collections;
*
*/
public class S3RepositoryPlugin extends Plugin {
static {
// This internal config is deserialized but with wrong access modifiers,
// cannot work without suppressAccessChecks permission right now. We force
// a one time load with elevated privileges as a workaround.
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
Class.forName("com.amazonaws.internal.config.InternalConfig$Factory");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to initialize internal aws config", e);
}
return null;
}
});
}
@Override
public String name() {

23
pom.xml
View File

@ -45,9 +45,14 @@
<!-- libraries -->
<lucene.version>5.4.0</lucene.version>
<lucene.snapshot.revision>1702265</lucene.snapshot.revision>
<lucene.snapshot.revision>1702855</lucene.snapshot.revision>
<lucene.maven.version>5.4.0-snapshot-${lucene.snapshot.revision}</lucene.maven.version>
<testframework.version>2.1.16</testframework.version>
<!-- we are using a snapshot of randomizedtesting with this PR:
https://github.com/randomizedtesting/randomizedtesting/pull/202
This allows us to only give the test-framework jars dangerous permissions and not
all of our code/test code. It is temporary while Dawid is on vacation. -->
<testframework.snapshot.revision>pr202</testframework.snapshot.revision>
<testframework.version>2.2.0-snapshot-${testframework.snapshot.revision}</testframework.version>
<jackson.version>2.5.3</jackson.version>
<slf4j.version>1.6.2</slf4j.version>
<log4j.version>1.2.17</log4j.version>
@ -145,8 +150,19 @@
<id>Lucene snapshots</id>
<url>https://download.elasticsearch.org/lucenesnapshots/${lucene.snapshot.revision}</url>
</repository>
<repository>
<id>Randomized Runner snapshot</id>
<url>https://download.elasticsearch.org/lucenesnapshots/rr-${testframework.snapshot.revision}</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>Randomized Runner snapshot</id>
<url>https://download.elasticsearch.org/lucenesnapshots/rr-${testframework.snapshot.revision}</url>
</pluginRepository>
</pluginRepositories>
<dependencyManagement>
<dependencies>
<dependency>
@ -633,6 +649,9 @@
<tests.cluster>${tests.cluster}</tests.cluster>
<tests.iters>${tests.iters}</tests.iters>
<tests.project>${project.groupId}:${project.artifactId}</tests.project>
<!-- these two are needed for insecure plugins, remove if possible! -->
<tests.artifact>${project.artifactId}</tests.artifact>
<tests.plugin.classname>${elasticsearch.plugin.classname}</tests.plugin.classname>
<tests.maxfailures>${tests.maxfailures}</tests.maxfailures>
<tests.failfast>${tests.failfast}</tests.failfast>
<tests.class>${tests.class}</tests.class>