Skip to content

Commit c1e1a88

Browse files
committed
Mirror upstream elastic#134454 as single snapshot commit for AI review
BASE=41fea9d8a715b1e2ffb668c3cf54c6c9645f0331 HEAD=135d74b33ba9f1ce2b0e61fa5fb2a39a3763c688 Branch=main
1 parent 41fea9d commit c1e1a88

File tree

5 files changed

+99
-13
lines changed

5 files changed

+99
-13
lines changed

libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,13 @@ private static List<Scope> createServerEntitlements(Path pidFile) {
114114
new FilesEntitlement(serverModuleFileDatas)
115115
)
116116
),
117-
new Scope("java.desktop", List.of(new LoadNativeLibrariesEntitlement())),
117+
new Scope(
118+
"java.desktop",
119+
List.of(
120+
new LoadNativeLibrariesEntitlement(),
121+
new ManageThreadsEntitlement() // For sun.java2d.Disposer. TODO: https://elasticco.atlassian.net/browse/ES-12888
122+
)
123+
),
118124
new Scope(
119125
"java.xml",
120126
List.of(

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public class PolicyManager {
5454
*/
5555
static final Logger generalLogger = LogManager.getLogger(PolicyManager.class);
5656

57-
static final Set<String> MODULES_EXCLUDED_FROM_SYSTEM_MODULES = Set.of("java.desktop", "java.xml");
57+
public static final Set<String> MODULES_EXCLUDED_FROM_SYSTEM_MODULES = Set.of("java.desktop", "java.xml");
5858

5959
/**
6060
* Identifies a particular entitlement {@link Scope} within a {@link Policy}.
@@ -94,7 +94,7 @@ public enum ComponentKind {
9494
* If this kind corresponds to a single component, this is that component's name;
9595
* otherwise null.
9696
*/
97-
final String componentName;
97+
public final String componentName;
9898

9999
ComponentKind(String componentName) {
100100
this.componentName = componentName;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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.bootstrap;
11+
12+
import org.elasticsearch.test.ESTestCase;
13+
import org.elasticsearch.test.ESTestCase.WithEntitlementsOnTestCode;
14+
15+
import java.io.ByteArrayInputStream;
16+
17+
import javax.imageio.stream.MemoryCacheImageInputStream;
18+
19+
import static java.nio.charset.StandardCharsets.UTF_8;
20+
21+
@WithEntitlementsOnTestCode
22+
public class HardcodedEntitlementsTests extends ESTestCase {
23+
24+
/**
25+
* The Tika library can do some things we don't ordinarily want to allow.
26+
* <p>
27+
* Note that {@link MemoryCacheImageInputStream} doesn't even use {@code Disposer} in JDK 26,
28+
* so it's an open question how much effort this deserves.
29+
*/
30+
public void testTikaPDF() {
31+
new MemoryCacheImageInputStream(new ByteArrayInputStream("test test".getBytes(UTF_8)));
32+
}
33+
}

test/framework/src/main/java/org/elasticsearch/bootstrap/TestScopeResolver.java

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99

1010
package org.elasticsearch.bootstrap;
1111

12+
import org.elasticsearch.core.Nullable;
1213
import org.elasticsearch.core.SuppressForbidden;
13-
import org.elasticsearch.entitlement.runtime.policy.PolicyManager;
14+
import org.elasticsearch.entitlement.runtime.policy.PolicyManager.PolicyScope;
1415
import org.elasticsearch.logging.LogManager;
1516
import org.elasticsearch.logging.Logger;
1617

18+
import java.lang.module.ModuleDescriptor;
19+
import java.lang.module.ModuleFinder;
1720
import java.net.MalformedURLException;
1821
import java.net.URL;
1922
import java.util.List;
@@ -22,39 +25,78 @@
2225
import java.util.TreeMap;
2326
import java.util.function.Function;
2427

28+
import static java.util.Objects.requireNonNull;
29+
import static java.util.stream.Collectors.toSet;
2530
import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.ALL_UNNAMED;
2631
import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.ComponentKind.PLUGIN;
32+
import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.ComponentKind.SERVER;
33+
import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.MODULES_EXCLUDED_FROM_SYSTEM_MODULES;
2734

28-
public record TestScopeResolver(Map<String, PolicyManager.PolicyScope> scopeMap) {
35+
public final class TestScopeResolver {
2936

3037
private static final Logger logger = LogManager.getLogger(TestScopeResolver.class);
38+
private final Map<String, PolicyScope> scopeMap;
39+
private static final Map<String, PolicyScope> excludedSystemPackageScopes = computeExcludedSystemPackageScopes();
3140

32-
PolicyManager.PolicyScope getScope(Class<?> callerClass) {
41+
public TestScopeResolver(Map<String, PolicyScope> scopeMap) {
42+
this.scopeMap = scopeMap;
43+
}
44+
45+
private static Map<String, PolicyScope> computeExcludedSystemPackageScopes() {
46+
// Within any one module layer, module names are unique, so we just need the names
47+
Set<String> systemModuleNames = ModuleFinder.ofSystem()
48+
.findAll()
49+
.stream()
50+
.map(ref -> ref.descriptor().name())
51+
.filter(MODULES_EXCLUDED_FROM_SYSTEM_MODULES::contains)
52+
.collect(toSet());
53+
54+
Map<String, PolicyScope> result = new TreeMap<>();
55+
ModuleLayer.boot().modules().stream().filter(m -> systemModuleNames.contains(m.getName())).forEach(m -> {
56+
ModuleDescriptor desc = m.getDescriptor();
57+
if (desc != null) {
58+
desc.packages().forEach(pkg ->
59+
// Our component identification logic returns SERVER for these
60+
result.put(pkg, new PolicyScope(SERVER, SERVER.componentName, m.getName())));
61+
}
62+
});
63+
return result;
64+
}
65+
66+
public static @Nullable PolicyScope getExcludedSystemPackageScope(Class<?> callerClass) {
67+
return excludedSystemPackageScopes.get(callerClass.getPackageName());
68+
}
69+
70+
PolicyScope getScope(Class<?> callerClass) {
3371
var callerCodeSource = callerClass.getProtectionDomain().getCodeSource();
34-
assert callerCodeSource != null;
72+
if (callerCodeSource == null) {
73+
// This only happens for JDK classes. Furthermore, for trivially allowed modules, we shouldn't even get here.
74+
// Hence, this must be an excluded system module, so check for that.
75+
return requireNonNull(getExcludedSystemPackageScope(callerClass));
76+
}
3577

3678
var location = callerCodeSource.getLocation().toString();
3779
var scope = scopeMap.get(location);
3880
if (scope == null) {
3981
// Special cases for libraries not handled by our automatically-generated scopeMap
4082
if (callerClass.getPackageName().startsWith("org.bouncycastle")) {
41-
scope = new PolicyManager.PolicyScope(PLUGIN, "security", ALL_UNNAMED);
83+
scope = new PolicyScope(PLUGIN, "security", ALL_UNNAMED);
4284
logger.debug("Assuming bouncycastle is part of the security plugin");
4385
}
4486
}
4587
if (scope == null) {
4688
logger.warn("Cannot identify a scope for class [{}], location [{}]", callerClass.getName(), location);
47-
return PolicyManager.PolicyScope.unknown(location);
89+
return PolicyScope.unknown(location);
4890
}
4991
return scope;
5092
}
5193

52-
public static Function<Class<?>, PolicyManager.PolicyScope> createScopeResolver(
94+
public static Function<Class<?>, PolicyScope> createScopeResolver(
5395
TestBuildInfo serverBuildInfo,
5496
List<TestBuildInfo> pluginsBuildInfo,
5597
Set<String> modularPlugins
5698
) {
57-
Map<String, PolicyManager.PolicyScope> scopeMap = new TreeMap<>(); // Sorted to make it easier to read during debugging
99+
Map<String, PolicyScope> scopeMap = new TreeMap<>(); // Sorted to make it easier to read during debugging
58100
for (var pluginBuildInfo : pluginsBuildInfo) {
59101
boolean isModular = modularPlugins.contains(pluginBuildInfo.component());
60102
for (var location : pluginBuildInfo.locations()) {
@@ -66,7 +108,7 @@ public static Function<Class<?>, PolicyManager.PolicyScope> createScopeResolver(
66108
String module = isModular ? location.module() : ALL_UNNAMED;
67109
scopeMap.put(
68110
getCodeSource(codeSource, location.representativeClass()),
69-
PolicyManager.PolicyScope.plugin(pluginBuildInfo.component(), module)
111+
PolicyScope.plugin(pluginBuildInfo.component(), module)
70112
);
71113
} catch (MalformedURLException e) {
72114
throw new IllegalArgumentException("Cannot locate class [" + location.representativeClass() + "]", e);
@@ -81,7 +123,7 @@ public static Function<Class<?>, PolicyManager.PolicyScope> createScopeResolver(
81123
continue;
82124
}
83125
try {
84-
scopeMap.put(getCodeSource(classUrl, location.representativeClass()), PolicyManager.PolicyScope.server(location.module()));
126+
scopeMap.put(getCodeSource(classUrl, location.representativeClass()), PolicyScope.server(location.module()));
85127
} catch (MalformedURLException e) {
86128
throw new IllegalArgumentException("Cannot locate class [" + location.representativeClass() + "]", e);
87129
}

test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
package org.elasticsearch.entitlement.runtime.policy;
1111

12+
import org.elasticsearch.bootstrap.TestScopeResolver;
1213
import org.elasticsearch.common.util.ArrayUtils;
1314
import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement;
1415
import org.elasticsearch.test.ESTestCase;
@@ -97,6 +98,10 @@ public final void clearModuleEntitlementsCache() {
9798

9899
@Override
99100
protected boolean isTrustedSystemClass(Class<?> requestingClass) {
101+
if (TestScopeResolver.getExcludedSystemPackageScope(requestingClass) != null) {
102+
// We don't trust the excluded packages even though they are in system modules
103+
return false;
104+
}
100105
ClassLoader loader = requestingClass.getClassLoader();
101106
return loader == null || loader == ClassLoader.getPlatformClassLoader();
102107
}

0 commit comments

Comments
 (0)