Skip to content

Commit 0205d3f

Browse files
prdoyleelasticsearchmachine
andauthored
Entitlements: manage_threads (#122261) (#122533)
* Entitlements: manage_threads (#122261) * Refactor: protected -> private * Initial thread-related entitlements * Entitlements from manual test runs * Refactor: notEntitled method * Entitlements reporting mode * Entitlements from CI * Revert "Entitlements reporting mode" This reverts commit 443ca76. * Remove unnecessary EntitledActions.newThread * Don't log in entitlements ITs by default * Import SuppressForbidden * Respond to PR comments * Move manage_threads tests to their own file * Move ForkJoinPool.setParallelism to VersionSpecificManageThreadsActions * [CI] Auto commit changes from spotless --------- Co-authored-by: elasticsearchmachine <[email protected]>
1 parent 5118f94 commit 0205d3f

File tree

25 files changed

+298
-48
lines changed

25 files changed

+298
-48
lines changed

libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,13 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str
152152
if (isAnnotationPresent == false) {
153153
boolean isStatic = (access & ACC_STATIC) != 0;
154154
boolean isCtor = "<init>".equals(name);
155-
boolean hasReceiver = (isStatic || isCtor) == false;
156155
var key = new MethodKey(className, name, Stream.of(Type.getArgumentTypes(descriptor)).map(Type::getInternalName).toList());
157156
var instrumentationMethod = checkMethods.get(key);
158157
if (instrumentationMethod != null) {
159-
// LOGGER.debug("Will instrument method {}", key);
158+
// System.out.println("Will instrument method " + key);
160159
return new EntitlementMethodVisitor(Opcodes.ASM9, mv, isStatic, isCtor, descriptor, instrumentationMethod);
161160
} else {
162-
// LOGGER.trace("Will not instrument method {}", key);
161+
// System.out.println("Will not instrument method " + key);
163162
}
164163
}
165164
return mv;

libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import java.util.Set;
6363
import java.util.TimeZone;
6464
import java.util.concurrent.ExecutorService;
65+
import java.util.concurrent.ForkJoinPool;
6566

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

588589
void checkType(Class<?> callerClass, FileStore that);
590+
591+
////////////////////
592+
//
593+
// Thread management
594+
//
595+
596+
void check$java_lang_Thread$start(Class<?> callerClass, Thread thread);
597+
598+
void check$java_lang_Thread$setDaemon(Class<?> callerClass, Thread thread, boolean on);
599+
600+
void check$java_lang_ThreadGroup$setDaemon(Class<?> callerClass, ThreadGroup threadGroup, boolean daemon);
601+
602+
void check$java_util_concurrent_ForkJoinPool$setParallelism(Class<?> callerClass, ForkJoinPool forkJoinPool, int size);
603+
604+
void check$java_lang_Thread$setName(Class<?> callerClass, Thread thread, String name);
605+
606+
void check$java_lang_Thread$setPriority(Class<?> callerClass, Thread thread, int newPriority);
607+
608+
void check$java_lang_Thread$setUncaughtExceptionHandler(Class<?> callerClass, Thread thread, Thread.UncaughtExceptionHandler ueh);
609+
610+
void check$java_lang_ThreadGroup$setMaxPriority(Class<?> callerClass, ThreadGroup threadGroup, int pri);
611+
589612
}

libs/entitlement/qa/entitled-plugin/src/main/java/org/elasticsearch/entitlement/qa/entitled/EntitledActions.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ private static Path readWriteDir() {
3434
return testRootDir.resolve("read_write_dir");
3535
}
3636

37-
static void System_clearProperty(String key) {
38-
System.clearProperty(key);
39-
}
40-
4137
public static UserPrincipal getFileOwner(Path path) throws IOException {
4238
return Files.getOwner(path);
4339
}

libs/entitlement/qa/entitled-plugin/src/main/java/org/elasticsearch/entitlement/qa/entitled/EntitledPlugin.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import org.elasticsearch.plugins.ExtensiblePlugin;
1616
import org.elasticsearch.plugins.Plugin;
1717

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

2020
public class EntitledPlugin extends Plugin implements ExtensiblePlugin {
2121

@@ -28,11 +28,19 @@ public static void selfTest() {
2828
selfTestNotEntitled();
2929
}
3030

31-
private static final String SELF_TEST_PROPERTY = "org.elasticsearch.entitlement.qa.selfTest";
32-
3331
private static void selfTestEntitled() {
3432
logger.debug("selfTestEntitled");
35-
System_clearProperty(SELF_TEST_PROPERTY);
33+
AtomicBoolean threadRan = new AtomicBoolean(false);
34+
try {
35+
Thread testThread = new Thread(() -> threadRan.set(true), "testThread");
36+
testThread.start();
37+
testThread.join();
38+
} catch (InterruptedException e) {
39+
throw new AssertionError(e);
40+
}
41+
if (threadRan.get() == false) {
42+
throw new AssertionError("Self-test thread did not run");
43+
}
3644
}
3745

3846
private static void selfTestNotEntitled() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.entitlement.qa.test;
11+
12+
import org.elasticsearch.core.SuppressForbidden;
13+
14+
import java.util.concurrent.atomic.AtomicBoolean;
15+
16+
import static java.lang.Thread.currentThread;
17+
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
18+
19+
@SuppressForbidden(reason = "testing entitlements")
20+
@SuppressWarnings("unused") // used via reflection
21+
class ManageThreadsActions {
22+
private ManageThreadsActions() {}
23+
24+
@EntitlementTest(expectedAccess = PLUGINS)
25+
static void java_lang_Thread$start() throws InterruptedException {
26+
AtomicBoolean threadRan = new AtomicBoolean(false);
27+
Thread thread = new Thread(() -> threadRan.set(true), "test");
28+
thread.start();
29+
thread.join();
30+
assert threadRan.get();
31+
}
32+
33+
@EntitlementTest(expectedAccess = PLUGINS)
34+
static void java_lang_Thread$setDaemon() {
35+
new Thread().setDaemon(true);
36+
}
37+
38+
@EntitlementTest(expectedAccess = PLUGINS)
39+
static void java_lang_ThreadGroup$setDaemon() {
40+
currentThread().getThreadGroup().setDaemon(currentThread().getThreadGroup().isDaemon());
41+
}
42+
43+
@EntitlementTest(expectedAccess = PLUGINS)
44+
static void java_lang_Thread$setName() {
45+
currentThread().setName(currentThread().getName());
46+
}
47+
48+
@EntitlementTest(expectedAccess = PLUGINS)
49+
static void java_lang_Thread$setPriority() {
50+
currentThread().setPriority(currentThread().getPriority());
51+
}
52+
53+
@EntitlementTest(expectedAccess = PLUGINS)
54+
static void java_lang_Thread$setUncaughtExceptionHandler() {
55+
currentThread().setUncaughtExceptionHandler(currentThread().getUncaughtExceptionHandler());
56+
}
57+
58+
@EntitlementTest(expectedAccess = PLUGINS)
59+
static void java_lang_ThreadGroup$setMaxPriority() {
60+
currentThread().getThreadGroup().setMaxPriority(currentThread().getThreadGroup().getMaxPriority());
61+
}
62+
63+
}

libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,19 @@ static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {
181181
entry("runtime_load_library", forPlugins(LoadNativeLibrariesCheckActions::runtimeLoadLibrary)),
182182
entry("system_load", forPlugins(LoadNativeLibrariesCheckActions::systemLoad)),
183183
entry("system_load_library", forPlugins(LoadNativeLibrariesCheckActions::systemLoadLibrary))
184+
185+
// MAINTENANCE NOTE: Please don't add any more entries to this map.
186+
// Put new tests into their own "Actions" class using the @EntitlementTest annotation.
184187
),
185188
getTestEntries(FileCheckActions.class),
186-
getTestEntries(SpiActions.class),
187-
getTestEntries(SystemActions.class),
189+
getTestEntries(FileStoreActions.class),
190+
getTestEntries(ManageThreadsActions.class),
188191
getTestEntries(NativeActions.class),
189192
getTestEntries(NioFileSystemActions.class),
190-
getTestEntries(VersionSpecificNioFileSystemActions.class),
191-
getTestEntries(FileStoreActions.class)
193+
getTestEntries(SpiActions.class),
194+
getTestEntries(SystemActions.class),
195+
getTestEntries(VersionSpecificManageThreadsActions.class),
196+
getTestEntries(VersionSpecificNioFileSystemActions.class)
192197
)
193198
.flatMap(Function.identity())
194199
.filter(entry -> entry.getValue().fromJavaVersion() == null || Runtime.version().feature() >= entry.getValue().fromJavaVersion())
@@ -425,7 +430,9 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
425430
return channel -> {
426431
logger.info("Calling check action [{}]", actionName);
427432
checkAction.action().run();
433+
logger.debug("Check action [{}] returned", actionName);
428434
channel.sendResponse(new RestResponse(RestStatus.OK, Strings.format("Succesfully executed action [%s]", actionName)));
429435
};
430436
}
437+
431438
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.entitlement.qa.test;
11+
12+
import org.elasticsearch.core.SuppressForbidden;
13+
14+
@SuppressForbidden(reason = "testing entitlements")
15+
@SuppressWarnings("unused") // used via reflection
16+
class VersionSpecificManageThreadsActions {
17+
private VersionSpecificManageThreadsActions() {}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.entitlement.qa.test;
11+
12+
import org.elasticsearch.core.SuppressForbidden;
13+
14+
import java.util.concurrent.ForkJoinPool;
15+
16+
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
17+
18+
@SuppressForbidden(reason = "testing entitlements")
19+
@SuppressWarnings("unused") // used via reflection
20+
class VersionSpecificManageThreadsActions {
21+
private VersionSpecificManageThreadsActions() {}
22+
23+
@EntitlementTest(expectedAccess = PLUGINS)
24+
static void java_util_concurrent_ForkJoinPool$setParallelism() {
25+
ForkJoinPool.commonPool().setParallelism(ForkJoinPool.commonPool().getParallelism());
26+
}
27+
}

libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/AbstractEntitlementsIT.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public abstract class AbstractEntitlementsIT extends ESRestTestCase {
2929
builder.value("inbound_network");
3030
builder.value("outbound_network");
3131
builder.value("load_native_libraries");
32+
builder.value("manage_threads");
3233
builder.value(
3334
Map.of(
3435
"write_system_properties",

libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/EntitlementsTestRule.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class EntitlementsTestRule implements TestRule {
3333

3434
// entitlements that test methods may use, see EntitledActions
3535
private static final PolicyBuilder ENTITLED_POLICY = (builder, tempDir) -> {
36-
builder.value(Map.of("write_system_properties", Map.of("properties", List.of("org.elasticsearch.entitlement.qa.selfTest"))));
36+
builder.value("manage_threads");
3737
builder.value(
3838
Map.of(
3939
"files",
@@ -74,6 +74,8 @@ protected void before() throws Throwable {
7474
.systemProperty("es.entitlements.enabled", "true")
7575
.systemProperty("es.entitlements.testdir", () -> testDir.getRoot().getAbsolutePath())
7676
.setting("xpack.security.enabled", "false")
77+
// Logs in libs/entitlement/qa/build/test-results/javaRestTest/TEST-org.elasticsearch.entitlement.qa.EntitlementsXXX.xml
78+
// .setting("logger.org.elasticsearch.entitlement", "DEBUG")
7779
.build();
7880
ruleChain = RuleChain.outerRule(testDir).around(tempDirSetup).around(cluster);
7981
}

0 commit comments

Comments
 (0)