Skip to content

Commit 3202262

Browse files
authored
Add temp dir access to all modules (elastic#122525) (elastic#122558)
Temp dir access is necessary all over Elasticsearch, and in general is not sensitive. With Security Manager all code in ES, including plugins, are given read/write access to the temp dir. This commit mimicks that behavior with entitlements.
1 parent 6950482 commit 3202262

File tree

5 files changed

+120
-60
lines changed

5 files changed

+120
-60
lines changed

libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ private static Class<?>[] findClassesToRetransform(Class<?>[] loadedClasses, Set
128128
private static PolicyManager createPolicyManager() {
129129
Map<String, Policy> pluginPolicies = EntitlementBootstrap.bootstrapArgs().pluginPolicies();
130130
Path[] dataDirs = EntitlementBootstrap.bootstrapArgs().dataDirs();
131+
Path tempDir = EntitlementBootstrap.bootstrapArgs().tempDir();
131132

132133
// TODO(ES-10031): Decide what goes in the elasticsearch default policy and extend it
133134
var serverPolicy = new Policy(
@@ -167,7 +168,15 @@ private static PolicyManager createPolicyManager() {
167168
// this should be removed once https://github.com/elastic/elasticsearch/issues/109335 is completed
168169
List<Entitlement> agentEntitlements = List.of(new CreateClassLoaderEntitlement(), new ManageThreadsEntitlement());
169170
var resolver = EntitlementBootstrap.bootstrapArgs().pluginResolver();
170-
return new PolicyManager(serverPolicy, agentEntitlements, pluginPolicies, resolver, AGENTS_PACKAGE_NAME, ENTITLEMENTS_MODULE);
171+
return new PolicyManager(
172+
serverPolicy,
173+
agentEntitlements,
174+
pluginPolicies,
175+
resolver,
176+
AGENTS_PACKAGE_NAME,
177+
ENTITLEMENTS_MODULE,
178+
tempDir
179+
);
171180
}
172181

173182
private static Stream<InstrumentationService.InstrumentationInfo> fileSystemProviderChecks() throws ClassNotFoundException,

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@
2020
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
2121

2222
public final class FileAccessTree {
23-
public static final FileAccessTree EMPTY = new FileAccessTree(FilesEntitlement.EMPTY);
2423
private static final String FILE_SEPARATOR = getDefaultFileSystem().getSeparator();
2524

2625
private final String[] readPaths;
2726
private final String[] writePaths;
2827

29-
private FileAccessTree(FilesEntitlement filesEntitlement) {
28+
private FileAccessTree(FilesEntitlement filesEntitlement, Path tempDir) {
3029
List<String> readPaths = new ArrayList<>();
3130
List<String> writePaths = new ArrayList<>();
3231
for (FilesEntitlement.FileData fileData : filesEntitlement.filesData()) {
@@ -38,15 +37,19 @@ private FileAccessTree(FilesEntitlement filesEntitlement) {
3837
readPaths.add(path);
3938
}
4039

40+
// everything has access to the temp dir
41+
readPaths.add(tempDir.toString());
42+
writePaths.add(tempDir.toString());
43+
4144
readPaths.sort(String::compareTo);
4245
writePaths.sort(String::compareTo);
4346

4447
this.readPaths = readPaths.toArray(new String[0]);
4548
this.writePaths = writePaths.toArray(new String[0]);
4649
}
4750

48-
public static FileAccessTree of(FilesEntitlement filesEntitlement) {
49-
return new FileAccessTree(filesEntitlement);
51+
public static FileAccessTree of(FilesEntitlement filesEntitlement, Path tempDir) {
52+
return new FileAccessTree(filesEntitlement, tempDir);
5053
}
5154

5255
boolean canRead(Path path) {

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

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -70,24 +70,6 @@ record ModuleEntitlements(
7070
entitlementsByType = Map.copyOf(entitlementsByType);
7171
}
7272

73-
public static ModuleEntitlements none(String componentName) {
74-
return new ModuleEntitlements(componentName, Map.of(), FileAccessTree.EMPTY);
75-
}
76-
77-
public static ModuleEntitlements from(String componentName, List<Entitlement> entitlements) {
78-
FilesEntitlement filesEntitlement = FilesEntitlement.EMPTY;
79-
for (Entitlement entitlement : entitlements) {
80-
if (entitlement instanceof FilesEntitlement) {
81-
filesEntitlement = (FilesEntitlement) entitlement;
82-
}
83-
}
84-
return new ModuleEntitlements(
85-
componentName,
86-
entitlements.stream().collect(groupingBy(Entitlement::getClass)),
87-
FileAccessTree.of(filesEntitlement)
88-
);
89-
}
90-
9173
public boolean hasEntitlement(Class<? extends Entitlement> entitlementClass) {
9274
return entitlementsByType.containsKey(entitlementClass);
9375
}
@@ -101,12 +83,34 @@ public <E extends Entitlement> Stream<E> getEntitlements(Class<E> entitlementCla
10183
}
10284
}
10385

86+
// pkg private for testing
87+
ModuleEntitlements defaultEntitlements(String componentName) {
88+
return new ModuleEntitlements(componentName, Map.of(), defaultFileAccess);
89+
}
90+
91+
// pkg private for testing
92+
ModuleEntitlements policyEntitlements(String componentName, List<Entitlement> entitlements) {
93+
FilesEntitlement filesEntitlement = FilesEntitlement.EMPTY;
94+
for (Entitlement entitlement : entitlements) {
95+
if (entitlement instanceof FilesEntitlement) {
96+
filesEntitlement = (FilesEntitlement) entitlement;
97+
}
98+
}
99+
return new ModuleEntitlements(
100+
componentName,
101+
entitlements.stream().collect(groupingBy(Entitlement::getClass)),
102+
FileAccessTree.of(filesEntitlement, tempDir)
103+
);
104+
}
105+
104106
final Map<Module, ModuleEntitlements> moduleEntitlementsMap = new ConcurrentHashMap<>();
105107

106108
private final Map<String, List<Entitlement>> serverEntitlements;
107109
private final List<Entitlement> apmAgentEntitlements;
108110
private final Map<String, Map<String, List<Entitlement>>> pluginsEntitlements;
109111
private final Function<Class<?>, String> pluginResolver;
112+
private final Path tempDir;
113+
private final FileAccessTree defaultFileAccess;
110114

111115
public static final String ALL_UNNAMED = "ALL-UNNAMED";
112116

@@ -141,7 +145,8 @@ public PolicyManager(
141145
Map<String, Policy> pluginPolicies,
142146
Function<Class<?>, String> pluginResolver,
143147
String apmAgentPackageName,
144-
Module entitlementsModule
148+
Module entitlementsModule,
149+
Path tempDir
145150
) {
146151
this.serverEntitlements = buildScopeEntitlementsMap(requireNonNull(serverPolicy));
147152
this.apmAgentEntitlements = apmAgentEntitlements;
@@ -151,6 +156,9 @@ public PolicyManager(
151156
this.pluginResolver = pluginResolver;
152157
this.apmAgentPackageName = apmAgentPackageName;
153158
this.entitlementsModule = entitlementsModule;
159+
this.defaultFileAccess = FileAccessTree.of(FilesEntitlement.EMPTY, tempDir);
160+
161+
this.tempDir = tempDir;
154162

155163
for (var e : serverEntitlements.entrySet()) {
156164
validateEntitlementsPerModule(SERVER_COMPONENT_NAME, e.getKey(), e.getValue());
@@ -425,7 +433,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
425433
if (pluginName != null) {
426434
var pluginEntitlements = pluginsEntitlements.get(pluginName);
427435
if (pluginEntitlements == null) {
428-
return ModuleEntitlements.none(pluginName);
436+
return defaultEntitlements(pluginName);
429437
} else {
430438
final String scopeName;
431439
if (requestingModule.isNamed() == false) {
@@ -439,10 +447,10 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
439447

440448
if (requestingModule.isNamed() == false && requestingClass.getPackageName().startsWith(apmAgentPackageName)) {
441449
// The APM agent is the only thing running non-modular in the system classloader
442-
return ModuleEntitlements.from(APM_AGENT_COMPONENT_NAME, apmAgentEntitlements);
450+
return policyEntitlements(APM_AGENT_COMPONENT_NAME, apmAgentEntitlements);
443451
}
444452

445-
return ModuleEntitlements.none(UNKNOWN_COMPONENT_NAME);
453+
return defaultEntitlements(UNKNOWN_COMPONENT_NAME);
446454
}
447455

448456
private ModuleEntitlements getModuleScopeEntitlements(
@@ -452,9 +460,9 @@ private ModuleEntitlements getModuleScopeEntitlements(
452460
) {
453461
var entitlements = scopeEntitlements.get(moduleName);
454462
if (entitlements == null) {
455-
return ModuleEntitlements.none(componentName);
463+
return defaultEntitlements(componentName);
456464
}
457-
return ModuleEntitlements.from(componentName, entitlements);
465+
return policyEntitlements(componentName, entitlements);
458466
}
459467

460468
private static boolean isServerModule(Module requestingModule) {

libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ private static Path path(String s) {
3636
}
3737

3838
public void testEmpty() {
39-
var tree = FileAccessTree.of(FilesEntitlement.EMPTY);
39+
var tree = accessTree(FilesEntitlement.EMPTY);
4040
assertThat(tree.canRead(path("path")), is(false));
4141
assertThat(tree.canWrite(path("path")), is(false));
4242
}
4343

4444
public void testRead() {
45-
var tree = FileAccessTree.of(entitlement("foo", "read"));
45+
var tree = accessTree(entitlement("foo", "read"));
4646
assertThat(tree.canRead(path("foo")), is(true));
4747
assertThat(tree.canRead(path("foo/subdir")), is(true));
4848
assertThat(tree.canRead(path("food")), is(false));
@@ -54,7 +54,7 @@ public void testRead() {
5454
}
5555

5656
public void testWrite() {
57-
var tree = FileAccessTree.of(entitlement("foo", "read_write"));
57+
var tree = accessTree(entitlement("foo", "read_write"));
5858
assertThat(tree.canWrite(path("foo")), is(true));
5959
assertThat(tree.canWrite(path("foo/subdir")), is(true));
6060
assertThat(tree.canWrite(path("food")), is(false));
@@ -66,7 +66,7 @@ public void testWrite() {
6666
}
6767

6868
public void testTwoPaths() {
69-
var tree = FileAccessTree.of(entitlement("foo", "read", "bar", "read"));
69+
var tree = accessTree(entitlement("foo", "read", "bar", "read"));
7070
assertThat(tree.canRead(path("a")), is(false));
7171
assertThat(tree.canRead(path("bar")), is(true));
7272
assertThat(tree.canRead(path("bar/subdir")), is(true));
@@ -77,23 +77,23 @@ public void testTwoPaths() {
7777
}
7878

7979
public void testReadWriteUnderRead() {
80-
var tree = FileAccessTree.of(entitlement("foo", "read", "foo/bar", "read_write"));
80+
var tree = accessTree(entitlement("foo", "read", "foo/bar", "read_write"));
8181
assertThat(tree.canRead(path("foo")), is(true));
8282
assertThat(tree.canWrite(path("foo")), is(false));
8383
assertThat(tree.canRead(path("foo/bar")), is(true));
8484
assertThat(tree.canWrite(path("foo/bar")), is(true));
8585
}
8686

8787
public void testNormalizePath() {
88-
var tree = FileAccessTree.of(entitlement("foo/../bar", "read"));
88+
var tree = accessTree(entitlement("foo/../bar", "read"));
8989
assertThat(tree.canRead(path("foo/../bar")), is(true));
9090
assertThat(tree.canRead(path("foo")), is(false));
9191
assertThat(tree.canRead(path("")), is(false));
9292
}
9393

9494
public void testForwardSlashes() {
9595
String sep = getDefaultFileSystem().getSeparator();
96-
var tree = FileAccessTree.of(entitlement("a/b", "read", "m" + sep + "n", "read"));
96+
var tree = accessTree(entitlement("a/b", "read", "m" + sep + "n", "read"));
9797

9898
// Native separators work
9999
assertThat(tree.canRead(path("a" + sep + "b")), is(true));
@@ -104,6 +104,18 @@ public void testForwardSlashes() {
104104
assertThat(tree.canRead(path("m/n")), is(true));
105105
}
106106

107+
public void testTempDirAccess() {
108+
Path tempDir = createTempDir();
109+
var tree = FileAccessTree.of(FilesEntitlement.EMPTY, tempDir);
110+
111+
assertThat(tree.canRead(tempDir), is(true));
112+
assertThat(tree.canWrite(tempDir), is(true));
113+
}
114+
115+
FileAccessTree accessTree(FilesEntitlement entitlement) {
116+
return FileAccessTree.of(entitlement, createTempDir());
117+
}
118+
107119
FilesEntitlement entitlement(String... values) {
108120
List<Object> filesData = new ArrayList<>();
109121
for (int i = 0; i < values.length; i += 2) {

0 commit comments

Comments
 (0)