From b8efa8ea21788f2f19eff4be4f3b9be404ed83f2 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Mon, 4 May 2015 12:30:03 -0400 Subject: [PATCH] Remove JNI permissions, improve JNI testing. --- pom.xml | 3 + .../elasticsearch/bootstrap/Bootstrap.java | 56 +++++++++++----- .../org/elasticsearch/bootstrap/Security.java | 4 -- .../common/jna/Kernel32Library.java | 18 ++++-- .../elasticsearch/bootstrap/security.policy | 3 - .../common/jna/NativesTests.java | 64 ++----------------- .../org/elasticsearch/monitor/SigarTests.java | 42 ++++++++++++ .../org/elasticsearch/test/SecurityHack.java | 3 + 8 files changed, 105 insertions(+), 88 deletions(-) create mode 100644 src/test/java/org/elasticsearch/monitor/SigarTests.java diff --git a/pom.xml b/pom.xml index 432aa22744e..8adf415700f 100644 --- a/pom.xml +++ b/pom.xml @@ -635,6 +635,9 @@ ${tests.security.manager} ${tests.compatibility} true + + true ${basedir}/src/main/resources/org/elasticsearch/bootstrap/security.policy diff --git a/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java b/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java index d351a9d4ea2..d787ff84289 100644 --- a/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java +++ b/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java @@ -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; @@ -27,6 +28,7 @@ import org.elasticsearch.common.collect.Tuple; 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; @@ -38,6 +40,7 @@ import org.elasticsearch.monitor.process.JmxProcessProbe; 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; @@ -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) { @@ -89,7 +84,36 @@ public class Bootstrap { } }); } - // 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); } diff --git a/src/main/java/org/elasticsearch/bootstrap/Security.java b/src/main/java/org/elasticsearch/bootstrap/Security.java index a9eedb7816a..cdb79ab9b4e 100644 --- a/src/main/java/org/elasticsearch/bootstrap/Security.java +++ b/src/main/java/org/elasticsearch/bootstrap/Security.java @@ -19,7 +19,6 @@ package org.elasticsearch.bootstrap; -import org.apache.lucene.util.StringHelper; import org.elasticsearch.env.Environment; import java.io.*; @@ -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))); diff --git a/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java b/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java index 386da4a5401..04549d78f1d 100644 --- a/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java +++ b/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java @@ -22,6 +22,8 @@ package org.elasticsearch.common.jna; 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; @@ -46,13 +48,15 @@ public class Kernel32Library { } 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."); + } } } diff --git a/src/main/resources/org/elasticsearch/bootstrap/security.policy b/src/main/resources/org/elasticsearch/bootstrap/security.policy index 993868c18b3..f71105af7da 100644 --- a/src/main/resources/org/elasticsearch/bootstrap/security.policy +++ b/src/main/resources/org/elasticsearch/bootstrap/security.policy @@ -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"; diff --git a/src/test/java/org/elasticsearch/common/jna/NativesTests.java b/src/test/java/org/elasticsearch/common/jna/NativesTests.java index 7a53b8d6895..72b973c0db9 100644 --- a/src/test/java/org/elasticsearch/common/jna/NativesTests.java +++ b/src/test/java/org/elasticsearch/common/jna/NativesTests.java @@ -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 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 - } } } } diff --git a/src/test/java/org/elasticsearch/monitor/SigarTests.java b/src/test/java/org/elasticsearch/monitor/SigarTests.java new file mode 100644 index 00000000000..f582c2fdc1c --- /dev/null +++ b/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()); + } +} diff --git a/src/test/java/org/elasticsearch/test/SecurityHack.java b/src/test/java/org/elasticsearch/test/SecurityHack.java index 092eda99f7d..90223ce4ac2 100644 --- a/src/test/java/org/elasticsearch/test/SecurityHack.java +++ b/src/test/java/org/elasticsearch/test/SecurityHack.java @@ -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; @@ -33,6 +34,8 @@ import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAs 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) {