|
@@ -8,6 +8,7 @@
|
|
|
|
|
|
package org.elasticsearch.bootstrap;
|
|
|
|
|
|
+import org.elasticsearch.ElasticsearchException;
|
|
|
import org.elasticsearch.cli.Command;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.core.PathUtils;
|
|
@@ -20,6 +21,10 @@ import org.elasticsearch.secure_sm.SecureSM;
|
|
|
import org.elasticsearch.transport.TcpTransport;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
+import java.lang.invoke.MethodHandle;
|
|
|
+import java.lang.invoke.MethodHandles;
|
|
|
+import java.lang.invoke.VarHandle;
|
|
|
+import java.lang.reflect.Field;
|
|
|
import java.net.SocketPermission;
|
|
|
import java.net.URISyntaxException;
|
|
|
import java.net.URL;
|
|
@@ -38,6 +43,7 @@ import java.util.Map;
|
|
|
import java.util.Set;
|
|
|
import java.util.function.Consumer;
|
|
|
|
|
|
+import static java.lang.invoke.MethodType.methodType;
|
|
|
import static org.elasticsearch.bootstrap.FilePermissionUtils.addDirectoryPath;
|
|
|
import static org.elasticsearch.bootstrap.FilePermissionUtils.addSingleFilePath;
|
|
|
|
|
@@ -92,6 +98,10 @@ final class Security {
|
|
|
/** no instantiation */
|
|
|
private Security() {}
|
|
|
|
|
|
+ static void setSecurityManager(@SuppressWarnings("removal") SecurityManager sm) {
|
|
|
+ System.setSecurityManager(sm);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Initializes SecurityManager for the environment
|
|
|
* Can only happen once!
|
|
@@ -117,7 +127,7 @@ final class Security {
|
|
|
// SecureSM matches class names as regular expressions so we escape the $ that arises from the nested class name
|
|
|
ElasticsearchUncaughtExceptionHandler.PrivilegedHaltAction.class.getName().replace("$", "\\$"),
|
|
|
Command.class.getName() };
|
|
|
- System.setSecurityManager(new SecureSM(classesThatCanExit));
|
|
|
+ setSecurityManager(new SecureSM(classesThatCanExit));
|
|
|
|
|
|
// do some basic tests
|
|
|
selfTest();
|
|
@@ -333,4 +343,47 @@ final class Security {
|
|
|
throw new SecurityException("Security misconfiguration: cannot access java.io.tmpdir", problem);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Prepopulates the system's security manager callers map with this class as a caller.
|
|
|
+ * This is loathsome, but avoids the annoying warning message at run time.
|
|
|
+ * Returns true if the callers map has been populated.
|
|
|
+ */
|
|
|
+ static boolean prepopulateSecurityCaller() {
|
|
|
+ Field f;
|
|
|
+ try {
|
|
|
+ f = getDeclaredField(Class.forName("java.lang.System$CallersHolder", true, null), "callers");
|
|
|
+ } catch (NoSuchFieldException | ClassNotFoundException ignore) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Class<?> c = Class.forName("sun.misc.Unsafe");
|
|
|
+ MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(c, MethodHandles.lookup());
|
|
|
+ VarHandle handle = lookup.findStaticVarHandle(c, "theUnsafe", c);
|
|
|
+ Object theUnsafe = handle.get();
|
|
|
+ MethodHandle mh = lookup.findVirtual(c, "staticFieldBase", methodType(Object.class, Field.class));
|
|
|
+ mh = mh.asType(mh.type().changeParameterType(0, Object.class));
|
|
|
+ Object base = mh.invokeExact(theUnsafe, f);
|
|
|
+ mh = lookup.findVirtual(c, "staticFieldOffset", methodType(long.class, Field.class));
|
|
|
+ mh = mh.asType(mh.type().changeParameterType(0, Object.class));
|
|
|
+ long offset = (long) mh.invokeExact(theUnsafe, f);
|
|
|
+ mh = lookup.findVirtual(c, "getObject", methodType(Object.class, Object.class, long.class));
|
|
|
+ mh = mh.asType(mh.type().changeParameterType(0, Object.class));
|
|
|
+ Object callers = (Object) mh.invokeExact(theUnsafe, base, offset);
|
|
|
+ if (Map.class.isAssignableFrom(callers.getClass())) {
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<Class<?>, Boolean> map = Map.class.cast(callers);
|
|
|
+ map.put(org.elasticsearch.bootstrap.Security.class, true);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ } catch (Throwable t) {
|
|
|
+ throw new ElasticsearchException(t);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressForbidden(reason = "access violation required")
|
|
|
+ private static Field getDeclaredField(Class<?> c, String name) throws NoSuchFieldException {
|
|
|
+ return c.getDeclaredField(name);
|
|
|
+ }
|
|
|
}
|