Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove JNI permissions, improve JNI testing. #10962

Merged
merged 1 commit into from May 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions pom.xml
Expand Up @@ -635,6 +635,9 @@
<tests.security.manager>${tests.security.manager}</tests.security.manager>
<tests.compatibility>${tests.compatibility}</tests.compatibility>
<java.awt.headless>true</java.awt.headless>
<!-- true if we are running tests from maven (as opposed to IDE, etc).
allows us to assert certain things work, like libsigar -->
<tests.maven>true</tests.maven>
<!-- security manager / test.policy -->
<java.security.policy>${basedir}/src/main/resources/org/elasticsearch/bootstrap/security.policy</java.security.policy>
</systemProperties>
Expand Down
56 changes: 40 additions & 16 deletions src/main/java/org/elasticsearch/bootstrap/Bootstrap.java
Expand Up @@ -19,6 +19,7 @@

package org.elasticsearch.bootstrap;

import org.apache.lucene.util.StringHelper;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.Version;
import org.elasticsearch.common.PidFile;
Expand All @@ -27,6 +28,7 @@
import org.elasticsearch.common.inject.CreationException;
import org.elasticsearch.common.inject.spi.Message;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.jna.Kernel32Library;
import org.elasticsearch.common.jna.Natives;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
Expand All @@ -38,6 +40,7 @@
import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeBuilder;
import org.elasticsearch.node.internal.InternalSettingsPreparer;
import org.hyperic.sigar.Sigar;

import java.util.Locale;
import java.util.Set;
Expand All @@ -57,24 +60,16 @@ public class Bootstrap {
private static volatile Thread keepAliveThread;
private static volatile CountDownLatch keepAliveLatch;
private static Bootstrap bootstrap;

private void setup(boolean addShutdownHook, Settings settings, Environment environment) throws Exception {
if (settings.getAsBoolean("bootstrap.mlockall", false)) {

/** initialize native resources */
public static void initializeNatives(boolean mlockAll, boolean ctrlHandler) {
// mlockall if requested
if (mlockAll) {
Natives.tryMlockall();
}

NodeBuilder nodeBuilder = NodeBuilder.nodeBuilder().settings(settings).loadConfigSettings(false);
node = nodeBuilder.build();
if (addShutdownHook) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
node.close();
}
});
}

if (settings.getAsBoolean("bootstrap.ctrlhandler", true)) {
// listener for windows close event
if (ctrlHandler) {
Natives.addConsoleCtrlHandler(new ConsoleCtrlHandler() {
@Override
public boolean handle(int code) {
Expand All @@ -89,7 +84,36 @@ public boolean handle(int code) {
}
});
}
// install SM after natives, JNA can require strange permissions
Kernel32Library.getInstance();

// initialize sigar explicitly
try {
Sigar.load();
Loggers.getLogger(Bootstrap.class).trace("sigar libraries loaded successfully");
} catch (Throwable t) {
Loggers.getLogger(Bootstrap.class).trace("failed to load sigar libraries", t);
}

// init lucene random seed. it will use /dev/urandom where available:
StringHelper.randomId();
}

private void setup(boolean addShutdownHook, Settings settings, Environment environment) throws Exception {
initializeNatives(settings.getAsBoolean("bootstrap.mlockall", false),
settings.getAsBoolean("bootstrap.ctrlhandler", true));

NodeBuilder nodeBuilder = NodeBuilder.nodeBuilder().settings(settings).loadConfigSettings(false);
node = nodeBuilder.build();
if (addShutdownHook) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
node.close();
}
});
}

// install SM after natives, shutdown hooks, etc.
setupSecurity(settings, environment);
}

Expand Down
4 changes: 0 additions & 4 deletions src/main/java/org/elasticsearch/bootstrap/Security.java
Expand Up @@ -19,7 +19,6 @@

package org.elasticsearch.bootstrap;

import org.apache.lucene.util.StringHelper;
import org.elasticsearch.env.Environment;

import java.io.*;
Expand Down Expand Up @@ -49,9 +48,6 @@ class Security {
* Can only happen once!
*/
static void configure(Environment environment) throws Exception {
// init lucene random seed. it will use /dev/urandom where available:
StringHelper.randomId();

// enable security policy: union of template and environment-based paths.
URI template = Security.class.getResource(POLICY_RESOURCE).toURI();
Policy.setPolicy(new ESPolicy(template, createPermissions(environment)));
Expand Down
18 changes: 11 additions & 7 deletions src/main/java/org/elasticsearch/common/jna/Kernel32Library.java
Expand Up @@ -22,6 +22,8 @@
import com.google.common.collect.ImmutableList;
import com.sun.jna.Native;
import com.sun.jna.win32.StdCallLibrary;

import org.apache.lucene.util.Constants;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;

Expand All @@ -46,13 +48,15 @@ private final static class Holder {
}

private Kernel32Library() {
try {
Native.register("kernel32");
logger.debug("windows/Kernel32 library loaded");
} catch (NoClassDefFoundError e) {
logger.warn("JNA not found. native methods and handlers will be disabled.");
} catch (UnsatisfiedLinkError e) {
logger.warn("unable to link Windows/Kernel32 library. native methods and handlers will be disabled.");
if (Constants.WINDOWS) {
try {
Native.register("kernel32");
logger.debug("windows/Kernel32 library loaded");
} catch (NoClassDefFoundError e) {
logger.warn("JNA not found. native methods and handlers will be disabled.");
} catch (UnsatisfiedLinkError e) {
logger.warn("unable to link Windows/Kernel32 library. native methods and handlers will be disabled.");
}
}
}

Expand Down
Expand Up @@ -82,9 +82,6 @@ grant {
// needed by groovy scripting
permission java.lang.RuntimePermission "getProtectionDomain";

// needed for natives calls
permission java.lang.RuntimePermission "loadLibrary.*";

// reflection hacks:
// needed for Striped64 (what is this doing), also enables unmap hack
permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
Expand Down
64 changes: 6 additions & 58 deletions src/test/java/org/elasticsearch/common/jna/NativesTests.java
Expand Up @@ -20,83 +20,31 @@
package org.elasticsearch.common.jna;

import org.apache.lucene.util.Constants;
import org.elasticsearch.common.jna.Kernel32Library.ConsoleCtrlHandler;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.Matchers.equalTo;

public class NativesTests extends ElasticsearchTestCase {

/**
* Those properties are set by the JNA Api and if not ignored,
* lead to tests failure (see AbstractRandomizedTest#IGNORED_INVARIANT_PROPERTIES)
*/
private static final String[] JNA_INVARIANT_PROPERTIES = {
"jna.platform.library.path",
"jnidispatch.path"
};

private Map<String, String> properties = new HashMap<>();

@Before
public void saveProperties() {
assumeTrue("Natives can't load libraries from path if security manager is enabled.", System.getSecurityManager() == null);
for (String p : JNA_INVARIANT_PROPERTIES) {
properties.put(p, System.getProperty(p));
}
}

@After
public void restoreProperties() {
for (String p : JNA_INVARIANT_PROPERTIES) {
if (properties.get(p) != null) {
System.setProperty(p, properties.get(p));
} else {
System.clearProperty(p);
}
}
}

@Test
public void testTryMlockall() {
Natives.tryMlockall();

public void testMlockall() {
if (Constants.WINDOWS) {
assertFalse("Memory locking is not available on Windows platforms", Natives.LOCAL_MLOCKALL);
}
if (Constants.MAC_OS_X) {
assertFalse("Memory locking is not available on OS X platforms", Natives.LOCAL_MLOCKALL);
}
}

@Test
public void testAddConsoleCtrlHandler() {
ConsoleCtrlHandler handler = new ConsoleCtrlHandler() {
@Override
public boolean handle(int code) {
return false;
}
};

Natives.addConsoleCtrlHandler(handler);

public void testConsoleCtrlHandler() {
if (Constants.WINDOWS) {
assertNotNull(Kernel32Library.getInstance());
assertThat(Kernel32Library.getInstance().getCallbacks().size(), equalTo(1));

} else {
assertNotNull(Kernel32Library.getInstance());
assertThat(Kernel32Library.getInstance().getCallbacks().size(), equalTo(0));

try {
Kernel32Library.getInstance().addConsoleCtrlHandler(handler);
fail("should have thrown an unsupported operation exception");
} catch (UnsatisfiedLinkError e) {
// UnsatisfiedLinkError is expected
}
}
}
}
42 changes: 42 additions & 0 deletions src/test/java/org/elasticsearch/monitor/SigarTests.java
@@ -0,0 +1,42 @@
/*
* 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.
*/

package org.elasticsearch.monitor;

import org.elasticsearch.test.ElasticsearchTestCase;
import org.hyperic.sigar.Sigar;

public class SigarTests extends ElasticsearchTestCase {

@Override
public void setUp() throws Exception {
super.setUp();
assumeTrue("we can only ensure sigar is working when running from maven",
Boolean.parseBoolean(System.getProperty("tests.maven")));
}

public void testSigarLoads() throws Exception {
Sigar.load();
}

public void testSigarWorks() throws Exception {
Sigar sigar = new Sigar();
assertNotNull(sigar.getCpu());
}
}
3 changes: 3 additions & 0 deletions src/test/java/org/elasticsearch/test/SecurityHack.java
Expand Up @@ -20,6 +20,7 @@
package org.elasticsearch.test;

import org.apache.lucene.util.TestSecurityManager;
import org.elasticsearch.bootstrap.Bootstrap;

import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsBoolean;

Expand All @@ -33,6 +34,8 @@
class SecurityHack {

static {
// just like bootstrap, initialize natives, then SM
Bootstrap.initializeNatives(true, true);
// for IDEs, we check that security.policy is set
if (systemPropertyAsBoolean("tests.security.manager", true) &&
System.getProperty("java.security.policy") != null) {
Expand Down