Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,13 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str
if (isAnnotationPresent == false) {
boolean isStatic = (access & ACC_STATIC) != 0;
boolean isCtor = "<init>".equals(name);
boolean hasReceiver = (isStatic || isCtor) == false;
var key = new MethodKey(className, name, Stream.of(Type.getArgumentTypes(descriptor)).map(Type::getInternalName).toList());
var instrumentationMethod = checkMethods.get(key);
if (instrumentationMethod != null) {
// LOGGER.debug("Will instrument method {}", key);
// System.out.println("Will instrument method " + key);
return new EntitlementMethodVisitor(Opcodes.ASM9, mv, isStatic, isCtor, descriptor, instrumentationMethod);
} else {
// LOGGER.trace("Will not instrument method {}", key);
// System.out.println("Will not instrument method " + key);
}
}
return mv;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Consumer;

import javax.net.ssl.HostnameVerifier;
Expand Down Expand Up @@ -522,6 +523,27 @@ public interface EntitlementChecker {

void check$java_nio_file_Files$$setOwner(Class<?> callerClass, Path path, UserPrincipal principal);

////////////////////
//
// Thread management
//

void check$java_lang_Thread$start(Class<?> callerClass, Thread thread);

void check$java_lang_Thread$setDaemon(Class<?> callerClass, Thread thread, boolean on);

void check$java_lang_ThreadGroup$setDaemon(Class<?> callerClass, ThreadGroup threadGroup, boolean daemon);

void check$java_util_concurrent_ForkJoinPool$setParallelism(Class<?> callerClass, ForkJoinPool forkJoinPool, int size);

void check$java_lang_Thread$setName(Class<?> callerClass, Thread thread, String name);

void check$java_lang_Thread$setPriority(Class<?> callerClass, Thread thread, int newPriority);

void check$java_lang_Thread$setUncaughtExceptionHandler(Class<?> callerClass, Thread thread, Thread.UncaughtExceptionHandler ueh);

void check$java_lang_ThreadGroup$setMaxPriority(Class<?> callerClass, ThreadGroup threadGroup, int pri);

// file system providers
void checkNewInputStream(Class<?> callerClass, FileSystemProvider that, Path path, OpenOption... options);

Expand All @@ -543,4 +565,5 @@ public interface EntitlementChecker {
void checkName(Class<?> callerClass, FileStore that);

void checkType(Class<?> callerClass, FileStore that);

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

package org.elasticsearch.entitlement.qa.entitled;

import org.elasticsearch.core.SuppressForbidden;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -19,9 +17,8 @@
public final class EntitledActions {
private EntitledActions() {}

@SuppressForbidden(reason = "Exposes forbidden APIs for testing purposes")
static void System_clearProperty(String key) {
System.clearProperty(key);
public static Thread newThread(Runnable runnable, String name) {
return new Thread(runnable, name);
}

public static UserPrincipal getFileOwner(Path path) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import org.elasticsearch.plugins.ExtensiblePlugin;
import org.elasticsearch.plugins.Plugin;

import static org.elasticsearch.entitlement.qa.entitled.EntitledActions.System_clearProperty;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.elasticsearch.entitlement.qa.entitled.EntitledActions.newThread;

public class EntitledPlugin extends Plugin implements ExtensiblePlugin {

Expand All @@ -28,11 +30,19 @@ public static void selfTest() {
selfTestNotEntitled();
}

private static final String SELF_TEST_PROPERTY = "org.elasticsearch.entitlement.qa.selfTest";

private static void selfTestEntitled() {
logger.debug("selfTestEntitled");
System_clearProperty(SELF_TEST_PROPERTY);
AtomicBoolean threadRan = new AtomicBoolean(false);
try {
Thread testThread = newThread(() -> threadRan.set(true), "testThread");
testThread.start();
testThread.join();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
if (threadRan.get() == false) {
throw new AssertionError("Self-test thread did not run");
}
}

private static void selfTestNotEntitled() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.elasticsearch.common.Strings;
import org.elasticsearch.core.CheckedRunnable;
import org.elasticsearch.core.SuppressForbidden;
import org.elasticsearch.entitlement.qa.entitled.EntitledActions;
import org.elasticsearch.logging.LogManager;
import org.elasticsearch.logging.Logger;
import org.elasticsearch.rest.BaseRestHandler;
Expand Down Expand Up @@ -47,13 +48,16 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;

import static java.lang.Thread.currentThread;
import static java.util.Map.entry;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
import static org.elasticsearch.entitlement.qa.test.RestEntitlementsCheckAction.CheckAction.alwaysDenied;
Expand Down Expand Up @@ -180,7 +184,25 @@ static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {
entry("runtime_load", forPlugins(LoadNativeLibrariesCheckActions::runtimeLoad)),
entry("runtime_load_library", forPlugins(LoadNativeLibrariesCheckActions::runtimeLoadLibrary)),
entry("system_load", forPlugins(LoadNativeLibrariesCheckActions::systemLoad)),
entry("system_load_library", forPlugins(LoadNativeLibrariesCheckActions::systemLoadLibrary))
entry("system_load_library", forPlugins(LoadNativeLibrariesCheckActions::systemLoadLibrary)),

entry("java_lang_Thread$start", forPlugins(RestEntitlementsCheckAction::java_lang_Thread$start)),
entry("java_lang_Thread$setDaemon", deniedToPlugins(RestEntitlementsCheckAction::java_lang_Thread$setDaemon)),
entry("java_lang_ThreadGroup$setDaemon", deniedToPlugins(RestEntitlementsCheckAction::java_lang_ThreadGroup$setDaemon)),
entry(
"java_util_concurrent_ForkJoinPool$setParallelism",
deniedToPlugins(RestEntitlementsCheckAction::java_util_concurrent_ForkJoinPool$setParallelism)
),
entry("java_lang_Thread$setName", deniedToPlugins(RestEntitlementsCheckAction::java_lang_Thread$setName)),
entry("java_lang_Thread$setPriority", deniedToPlugins(RestEntitlementsCheckAction::java_lang_Thread$setPriority)),
entry(
"java_lang_Thread$setUncaughtExceptionHandler",
deniedToPlugins(RestEntitlementsCheckAction::java_lang_Thread$setUncaughtExceptionHandler)
),
entry(
"java_lang_ThreadGroup$setMaxPriority",
deniedToPlugins(RestEntitlementsCheckAction::java_lang_ThreadGroup$setMaxPriority)
)
),
getTestEntries(FileCheckActions.class),
getTestEntries(SpiActions.class),
Expand Down Expand Up @@ -423,7 +445,45 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
return channel -> {
logger.info("Calling check action [{}]", actionName);
checkAction.action().run();
logger.debug("Check action [{}] returned", actionName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional or leftover from debugging?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At one point, I wanted to know whether the action actually returned, as opposed to throwing. By and large, when I add log statements during debugging, I don't remove them before merging because if they're helpful once, they're likely to be helpful again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍
Should we change the "matching" logger level too? (2 lines above) (if it makes sense)

channel.sendResponse(new RestResponse(RestStatus.OK, Strings.format("Succesfully executed action [%s]", actionName)));
};
}

static void java_lang_Thread$start() throws InterruptedException {
AtomicBoolean threadRan = new AtomicBoolean(false);
Thread thread = EntitledActions.newThread(() -> threadRan.set(true), "test");
thread.start();
thread.join();
assert threadRan.get();
}

static void java_lang_Thread$setDaemon() {
currentThread().setDaemon(currentThread().isDaemon());
}

static void java_lang_ThreadGroup$setDaemon() {
currentThread().getThreadGroup().setDaemon(currentThread().getThreadGroup().isDaemon());
}

static void java_util_concurrent_ForkJoinPool$setParallelism() {
ForkJoinPool.commonPool().setParallelism(ForkJoinPool.commonPool().getParallelism());
}

static void java_lang_Thread$setName() {
currentThread().setName(currentThread().getName());
}

static void java_lang_Thread$setPriority() {
currentThread().setPriority(currentThread().getPriority());
}

static void java_lang_Thread$setUncaughtExceptionHandler() {
currentThread().setUncaughtExceptionHandler(currentThread().getUncaughtExceptionHandler());
}

static void java_lang_ThreadGroup$setMaxPriority() {
currentThread().getThreadGroup().setMaxPriority(currentThread().getThreadGroup().getMaxPriority());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public abstract class AbstractEntitlementsIT extends ESRestTestCase {
builder.value("inbound_network");
builder.value("outbound_network");
builder.value("load_native_libraries");
builder.value("manage_threads");
builder.value(
Map.of(
"write_system_properties",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class EntitlementsTestRule implements TestRule {

// entitlements that test methods may use, see EntitledActions
private static final PolicyBuilder ENTITLED_POLICY = (builder, tempDir) -> {
builder.value(Map.of("write_system_properties", Map.of("properties", List.of("org.elasticsearch.entitlement.qa.selfTest"))));
builder.value("manage_threads");
builder.value(
Map.of(
"files",
Expand Down Expand Up @@ -74,6 +74,8 @@ protected void before() throws Throwable {
.systemProperty("es.entitlements.enabled", "true")
.systemProperty("es.entitlements.testdir", () -> testDir.getRoot().getAbsolutePath())
.setting("xpack.security.enabled", "false")
// Logs in libs/entitlement/qa/build/test-results/javaRestTest/TEST-org.elasticsearch.entitlement.qa.EntitlementsXXX.xml
.setting("logger.org.elasticsearch.entitlement", "DEBUG")
.build();
ruleChain = RuleChain.outerRule(testDir).around(tempDirSetup).around(cluster);
}
Expand Down
2 changes: 1 addition & 1 deletion libs/entitlement/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

exports org.elasticsearch.entitlement.runtime.api;
exports org.elasticsearch.entitlement.runtime.policy;
exports org.elasticsearch.entitlement.runtime.policy.entitlements to org.elasticsearch.server;
exports org.elasticsearch.entitlement.instrumentation;
exports org.elasticsearch.entitlement.bootstrap to org.elasticsearch.server;
exports org.elasticsearch.entitlement.initialization to java.base;
exports org.elasticsearch.entitlement.runtime.policy.entitlements to org.elasticsearch.server;

uses org.elasticsearch.entitlement.instrumentation.InstrumentationService;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.elasticsearch.entitlement.runtime.policy.entitlements.ExitVMEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.ManageThreadsEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.ReadStoreAttributesEntitlement;

Expand Down Expand Up @@ -136,18 +137,20 @@ private static PolicyManager createPolicyManager() {
new CreateClassLoaderEntitlement(),
new InboundNetworkEntitlement(),
new OutboundNetworkEntitlement(),
new LoadNativeLibrariesEntitlement()
new LoadNativeLibrariesEntitlement(),
new ManageThreadsEntitlement()
)
),
new Scope("org.apache.httpcomponents.httpclient", List.of(new OutboundNetworkEntitlement())),
new Scope("io.netty.transport", List.of(new InboundNetworkEntitlement(), new OutboundNetworkEntitlement())),
new Scope("org.apache.lucene.core", List.of(new LoadNativeLibrariesEntitlement())),
new Scope("org.apache.lucene.core", List.of(new LoadNativeLibrariesEntitlement(), new ManageThreadsEntitlement())),
new Scope("org.apache.logging.log4j.core", List.of(new ManageThreadsEntitlement())),
new Scope("org.elasticsearch.nativeaccess", List.of(new LoadNativeLibrariesEntitlement()))
)
);
// agents run without a module, so this is a special hack for the apm agent
// this should be removed once https://github.com/elastic/elasticsearch/issues/109335 is completed
List<Entitlement> agentEntitlements = List.of(new CreateClassLoaderEntitlement());
List<Entitlement> agentEntitlements = List.of(new CreateClassLoaderEntitlement(), new ManageThreadsEntitlement());
var resolver = EntitlementBootstrap.bootstrapArgs().pluginResolver();
return new PolicyManager(serverPolicy, agentEntitlements, pluginPolicies, resolver, AGENTS_PACKAGE_NAME, ENTITLEMENTS_MODULE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Consumer;

import javax.net.ssl.HostnameVerifier;
Expand Down Expand Up @@ -1000,6 +1001,52 @@ public void checkNewInputStream(Class<?> callerClass, FileSystemProvider that, P
// TODO: policyManger.checkFileSystemRead(path);
}

// Thread management

@Override
public void check$java_lang_Thread$start(Class<?> callerClass, Thread thread) {
policyManager.checkManageThreadsEntitlement(callerClass);
}

@Override
public void check$java_lang_Thread$setDaemon(Class<?> callerClass, Thread thread, boolean on) {
policyManager.checkManageThreadsEntitlement(callerClass);
}

@Override
public void check$java_lang_ThreadGroup$setDaemon(Class<?> callerClass, ThreadGroup threadGroup, boolean daemon) {
policyManager.checkManageThreadsEntitlement(callerClass);
}

@Override
public void check$java_util_concurrent_ForkJoinPool$setParallelism(Class<?> callerClass, ForkJoinPool forkJoinPool, int size) {
policyManager.checkManageThreadsEntitlement(callerClass);
}

@Override
public void check$java_lang_Thread$setName(Class<?> callerClass, Thread thread, String name) {
policyManager.checkManageThreadsEntitlement(callerClass);
}

@Override
public void check$java_lang_Thread$setPriority(Class<?> callerClass, Thread thread, int newPriority) {
policyManager.checkManageThreadsEntitlement(callerClass);
}

@Override
public void check$java_lang_Thread$setUncaughtExceptionHandler(
Class<?> callerClass,
Thread thread,
Thread.UncaughtExceptionHandler ueh
) {
policyManager.checkManageThreadsEntitlement(callerClass);
}

@Override
public void check$java_lang_ThreadGroup$setMaxPriority(Class<?> callerClass, ThreadGroup threadGroup, int pri) {
policyManager.checkManageThreadsEntitlement(callerClass);
}

@Override
public void checkGetFileStoreAttributeView(Class<?> callerClass, FileStore that, Class<?> type) {
policyManager.checkWriteStoreAttributes(callerClass);
Expand Down
Loading