Skip to content

Commit

Permalink
[POC] [Security Manager Replacement] GraalVM sandboxing
Browse files Browse the repository at this point in the history
Signed-off-by: Andriy Redko <[email protected]>
  • Loading branch information
reta committed Dec 18, 2024
1 parent ef44e86 commit ed8cd55
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 0 deletions.
44 changes: 44 additions & 0 deletions libs/espresso-sm/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import org.opensearch.gradle.info.BuildParams

apply plugin: 'opensearch.publish'

base {
archivesName = 'esspresso-sm'
}

dependencies {
implementation "org.graalvm.polyglot:polyglot:24.1.1"
implementation "org.graalvm.sdk:nativeimage:24.1.1"
implementation "org.graalvm.sdk:collections:24.1.1"
implementation "org.graalvm.sdk:word:24.1.1"
implementation "org.graalvm.sdk:jniutils:24.1.1"
implementation "org.graalvm.llvm:llvm-api:24.1.1"
implementation "org.graalvm.llvm:llvm-language:24.1.1"
implementation "org.graalvm.llvm:llvm-language-native:24.1.1"
implementation "org.graalvm.llvm:llvm-language-native-resources:24.1.1"
implementation "org.graalvm.llvm:llvm-language-nfi:24.1.1"
implementation "org.graalvm.truffle:truffle-api:24.1.1"
implementation "org.graalvm.truffle:truffle-compiler:24.1.1"
implementation "org.graalvm.truffle:truffle-nfi:24.1.1"
implementation "org.graalvm.truffle:truffle-nfi-libffi:24.1.1"
implementation "org.graalvm.truffle:truffle-runtime:24.1.1"
implementation "org.graalvm.espresso:espresso-language:24.1.1"
implementation "org.graalvm.espresso:espresso-libs-resources-linux-amd64:24.1.1"
implementation "org.graalvm.espresso:espresso-runtime-resources-linux-amd64:24.1.1"
implementation project(":server")
}

tasks.named('forbiddenApisMain').configure {
replaceSignatureFiles 'jdk-signatures'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

package org.opensearch.espresso.sandbox;

import org.opensearch.client.Client;
import org.opensearch.client.node.NodeClient;
import org.opensearch.common.settings.Settings;
import org.opensearch.threadpool.ThreadPool;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.HostAccess;
import org.graalvm.polyglot.PolyglotAccess;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.io.IOAccess;

/**
* GraalVM Sandbox
*/
public class Sandbox {
/**
* GraalVM Sandbox runner
*/
public static void main(String[] args) throws IOException, InterruptedException {
final String opensearchHome = args[0];
System.out.println("OpenSearch home: " + opensearchHome);

final Engine engine = Engine.newBuilder().build();

System.out.println("Host JVM version: " + Runtime.version());
final String plugin = loadPlugin(opensearchHome, engine);
System.out.println(plugin);
}

private static String loadPlugin(String opensearchHome, Engine engine) throws IOException {
// See please:
// - https://github.com/oracle/graal/issues/10239
// -
// https://github.com/oracle/graal/blob/master/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java
// -
// https://github.com/oracle/graal/blob/master/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java
final Context context = Context.newBuilder("java")
.option("java.JavaHome", "/usr/lib/jvm/java-21-openjdk-amd64/")
.option(
"java.Classpath",
("${opensearchHome}/lib/lucene-core-9.12.0.jar:"
+ "${opensearchHome}/lib/opensearch-cli-3.0.0-SNAPSHOT.jar:"
+ "${opensearchHome}/lib/jackson-core-2.17.2.jar:"
+ "${opensearchHome}/lib/jackson-dataformat-cbor-2.17.2.jar:"
+ "${opensearchHome}/lib/jackson-dataformat-smile-2.17.2.jar:"
+ "${opensearchHome}/lib/jackson-dataformat-yaml-2.17.2.jar:"
+ "${opensearchHome}/lib/snakeyaml-2.1.jar:"
+ "${opensearchHome}/lib/opensearch-3.0.0-SNAPSHOT.jar:"
+ "${opensearchHome}/lib/opensearch-core-3.0.0-SNAPSHOT.jar:"
+ "${opensearchHome}/lib/opensearch-common-3.0.0-SNAPSHOT.jar:"
+ "${opensearchHome}/lib/opensearch-x-content-3.0.0-SNAPSHOT.jar:"
+ "${opensearchHome}/lib/opensearch-secure-sm-3.0.0-SNAPSHOT.jar:"
+ "${opensearchHome}/lib/log4j-core-2.21.0.jar:"
+ "${opensearchHome}/lib/log4j-jul-2.21.0.jar:"
+ "${opensearchHome}/lib/log4j-api-2.21.0.jar:"
+ "${opensearchHome}/plugins/identity-shiro/slf4j-api-1.7.36.jar:"
+ "${opensearchHome}/plugins/identity-shiro/passay-1.6.3.jar:"
+ "${opensearchHome}/plugins/identity-shiro/identity-shiro-3.0.0-SNAPSHOT.jar:"
+ "${opensearchHome}/plugins/identity-shiro/shiro-core-1.13.0.jar").replaceAll(
"[$][{]opensearchHome[}]",
opensearchHome
)
)
.option("java.Properties.java.security.manager", "allow")
.option("java.PolyglotInterfaceMappings", getInterfaceMappings())
.option("java.Polyglot", "true")
.allowExperimentalOptions(true)
.allowNativeAccess(true)
.allowCreateThread(true)
.allowHostAccess(HostAccess.NONE)
.allowIO(IOAccess.NONE)
.allowPolyglotAccess(PolyglotAccess.newBuilder().allowBindingsAccess("java").build())
.engine(engine)
.build();

final Value runtime = context.getBindings("java").getMember("java.lang.Runtime");
System.out.println("Polyglot JVM version: " + runtime.invokeMember("version").toString());

final Path homePath = new File(opensearchHome).toPath();
final Path configPath = new File(opensearchHome + "/config").toPath();
context.getBindings("java")
.getMember("org.opensearch.bootstrap.QuickBoostrap")
.invokeMember("bootstrap", configPath.toString(), homePath.toString());

final Value securityManager = context.getBindings("java").getMember("java.lang.System").invokeMember("getSecurityManager");
System.out.println("Security Manager? " + securityManager.toString());

final Value settings = context.getBindings("java").getMember("org.opensearch.common.settings.Settings").getMember("EMPTY");
final Value result = context.getBindings("java").getMember("org.opensearch.identity.shiro.ShiroIdentityPlugin");
final Value instance = result.newInstance(settings);
System.out.println("Shiro Plugin? " + instance.toString());

final Client client = new NodeClient(Settings.EMPTY, new ThreadPool(Settings.EMPTY));
final Value socket = instance.invokeMember("getSocket", client);
return socket.toString();
}

private static String getInterfaceMappings() {
return "org.opensearch.client.Client;" + "org.opensearch.client.AdminClient;";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.watcher.ResourceWatcherService;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;
Expand Down Expand Up @@ -138,6 +140,16 @@ public void handleRequest(RestRequest request, RestChannel channel, NodeClient c
}
}

/**
* Deliberately introducing the network access attempt to trigger SecurityException
*/
public ServerSocket getSocket(Client client) throws IOException {
System.out.println("Client? " + client);
System.out.println("AdminClient? " + client.admin());
client.admin().cluster().prepareState().execute().actionGet();
return new ServerSocket(0);
}

public PluginSubject getPluginSubject(Plugin plugin) {
return new ShiroPluginSubject(threadPool);
}
Expand Down
60 changes: 60 additions & 0 deletions server/src/main/java/org/opensearch/bootstrap/QuickBoostrap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.bootstrap;

import org.opensearch.cli.UserException;
import org.opensearch.common.logging.LogConfigurator;
import org.opensearch.common.settings.Settings;
import org.opensearch.env.Environment;
import org.opensearch.node.InternalSettingsPreparer;
import org.opensearch.node.Node;
import org.opensearch.node.NodeValidationException;

import java.io.IOException;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;

/**
* Quick bootstrap
*/
public class QuickBoostrap {
/**
* This method is invoked by {@link OpenSearch#main(String[])} to startup opensearch.
*/
public static void bootstrap(final String configPath, final String homePath) throws BootstrapException, NodeValidationException,
UserException {

// force the class initializer for BootstrapInfo to run before
// the security manager is installed
BootstrapInfo.init();

Settings settings = Settings.builder().put(Environment.PATH_HOME_SETTING.getKey(), homePath).build();
final Environment environment = InternalSettingsPreparer.prepareEnvironment(
settings,
Collections.emptyMap(),
Paths.get(configPath),
// HOSTNAME is set by opensearch-env and opensearch-env.bat so it is always available
() -> System.getenv("HOSTNAME")
);

LogConfigurator.setNodeName(Node.NODE_NAME_SETTING.get(environment.settings()));
try {
LogConfigurator.configure(environment);
} catch (IOException e) {
throw new BootstrapException(e);
}

try {
Security.configure(environment, BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING.get(settings));
} catch (IOException | NoSuchAlgorithmException e) {
throw new BootstrapException(e);
}
}
}

0 comments on commit ed8cd55

Please sign in to comment.