Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -62,6 +62,7 @@
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
Expand Down Expand Up @@ -586,4 +587,26 @@ void checkNewByteChannel(
void checkName(Class<?> callerClass, FileStore that);

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

////////////////////
//
// 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);

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ private static Path readWriteDir() {
return testRootDir.resolve("read_write_dir");
}

static void System_clearProperty(String key) {
System.clearProperty(key);
}

public static UserPrincipal getFileOwner(Path path) throws IOException {
return Files.getOwner(path);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
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;

public class EntitledPlugin extends Plugin implements ExtensiblePlugin {

Expand All @@ -28,11 +28,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 = new Thread(() -> 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
@@ -0,0 +1,64 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.entitlement.qa.test;

import org.elasticsearch.core.SuppressForbidden;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.lang.Thread.currentThread;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;

@SuppressForbidden(reason = "testing entitlements")
@SuppressWarnings("unused") // used via reflection
class ManageThreadsActions {
private ManageThreadsActions() {}

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

@EntitlementTest(expectedAccess = PLUGINS)
static void java_lang_Thread$setDaemon() {
new Thread().setDaemon(true);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void java_lang_ThreadGroup$setDaemon() {
currentThread().getThreadGroup().setDaemon(currentThread().getThreadGroup().isDaemon());
}

@EntitlementTest(expectedAccess = PLUGINS)
static void java_lang_Thread$setName() {
currentThread().setName(currentThread().getName());
}

@EntitlementTest(expectedAccess = PLUGINS)
static void java_lang_Thread$setPriority() {
currentThread().setPriority(currentThread().getPriority());
}

@EntitlementTest(expectedAccess = PLUGINS)
static void java_lang_Thread$setUncaughtExceptionHandler() {
currentThread().setUncaughtExceptionHandler(currentThread().getUncaughtExceptionHandler());
}

@EntitlementTest(expectedAccess = PLUGINS)
static void java_lang_ThreadGroup$setMaxPriority() {
currentThread().getThreadGroup().setMaxPriority(currentThread().getThreadGroup().getMaxPriority());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,19 @@ static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {
entry("runtime_load_library", forPlugins(LoadNativeLibrariesCheckActions::runtimeLoadLibrary)),
entry("system_load", forPlugins(LoadNativeLibrariesCheckActions::systemLoad)),
entry("system_load_library", forPlugins(LoadNativeLibrariesCheckActions::systemLoadLibrary))

// MAINTENANCE NOTE: Please don't add any more entries to this map.
// Put new tests into their own "Actions" class using the @EntitlementTest annotation.
),
getTestEntries(FileCheckActions.class),
getTestEntries(SpiActions.class),
getTestEntries(SystemActions.class),
getTestEntries(FileStoreActions.class),
getTestEntries(ManageThreadsActions.class),
getTestEntries(NativeActions.class),
getTestEntries(NioFileSystemActions.class),
getTestEntries(VersionSpecificNioFileSystemActions.class),
getTestEntries(FileStoreActions.class)
getTestEntries(SpiActions.class),
getTestEntries(SystemActions.class),
getTestEntries(VersionSpecificManageThreadsActions.class),
getTestEntries(VersionSpecificNioFileSystemActions.class)
)
.flatMap(Function.identity())
.filter(entry -> entry.getValue().fromJavaVersion() == null || Runtime.version().feature() >= entry.getValue().fromJavaVersion())
Expand Down Expand Up @@ -425,7 +430,9 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
return channel -> {
logger.info("Calling check action [{}]", actionName);
checkAction.action().run();
logger.debug("Check action [{}] returned", actionName);
channel.sendResponse(new RestResponse(RestStatus.OK, Strings.format("Succesfully executed action [%s]", actionName)));
};
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.entitlement.qa.test;

import org.elasticsearch.core.SuppressForbidden;

@SuppressForbidden(reason = "testing entitlements")
@SuppressWarnings("unused") // used via reflection
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I suppose we don't really need these two lines.

class VersionSpecificManageThreadsActions {
private VersionSpecificManageThreadsActions() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.entitlement.qa.test;

import org.elasticsearch.core.SuppressForbidden;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.lang.Thread.currentThread;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;

@SuppressForbidden(reason = "testing entitlements")
@SuppressWarnings("unused") // used via reflection
class VersionSpecificManageThreadsActions {
private VersionSpecificManageThreadsActions() {}

@EntitlementTest(expectedAccess = PLUGINS)
static void java_util_concurrent_ForkJoinPool$setParallelism() {
ForkJoinPool.commonPool().setParallelism(ForkJoinPool.commonPool().getParallelism());
}
}
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.FileData;
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 @@ -143,14 +144,16 @@ private static PolicyManager createPolicyManager() {
new InboundNetworkEntitlement(),
new OutboundNetworkEntitlement(),
new LoadNativeLibrariesEntitlement(),
new ManageThreadsEntitlement(),
new FilesEntitlement(
List.of(new FilesEntitlement.FileData(EntitlementBootstrap.bootstrapArgs().tempDir().toString(), READ_WRITE))
)
)
),
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(
Expand All @@ -162,7 +165,7 @@ private static PolicyManager createPolicyManager() {
);
// 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 @@ -68,6 +68,7 @@
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
Expand Down Expand Up @@ -1219,4 +1220,51 @@ public void checkName(Class<?> callerClass, FileStore that) {
public void checkType(Class<?> callerClass, FileStore that) {
policyManager.checkReadStoreAttributes(callerClass);
}

// 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);
}

}
Loading