Skip to content

Commit 57954ac

Browse files
authored
Refactor file path resolution for entitlements (#127040) (#127133) (#127160)
This change refactors the known directory resolution such as modules, plugins, lib, etc. into a PathLookup. This is one of the steps towards allowing unit tests to provide their own PathLookup for resolution so we can enable entitlements there. ES-11584
1 parent de7dbd6 commit 57954ac

File tree

12 files changed

+242
-224
lines changed

12 files changed

+242
-224
lines changed

Diff for: libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java

+26-32
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
import com.sun.tools.attach.VirtualMachine;
1616

1717
import org.elasticsearch.core.Nullable;
18+
import org.elasticsearch.core.PathUtils;
1819
import org.elasticsearch.core.SuppressForbidden;
1920
import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
21+
import org.elasticsearch.entitlement.runtime.policy.PathLookup;
22+
import org.elasticsearch.entitlement.runtime.policy.PathLookupImpl;
2023
import org.elasticsearch.entitlement.runtime.policy.Policy;
2124
import org.elasticsearch.logging.LogManager;
2225
import org.elasticsearch.logging.Logger;
@@ -37,35 +40,15 @@ public record BootstrapArgs(
3740
@Nullable Policy serverPolicyPatch,
3841
Map<String, Policy> pluginPolicies,
3942
Function<Class<?>, String> pluginResolver,
40-
Function<String, Stream<String>> settingResolver,
41-
Path[] dataDirs,
42-
Path[] sharedRepoDirs,
43-
Path configDir,
44-
Path libDir,
45-
Path modulesDir,
46-
Path pluginsDir,
43+
PathLookup pathLookup,
4744
Map<String, Path> sourcePaths,
48-
Path logsDir,
49-
Path tempDir,
50-
Path pidFile,
5145
Set<Class<?>> suppressFailureLogClasses
5246
) {
5347
public BootstrapArgs {
5448
requireNonNull(pluginPolicies);
5549
requireNonNull(pluginResolver);
56-
requireNonNull(settingResolver);
57-
requireNonNull(dataDirs);
58-
if (dataDirs.length == 0) {
59-
throw new IllegalArgumentException("must provide at least one data directory");
60-
}
61-
requireNonNull(sharedRepoDirs);
62-
requireNonNull(configDir);
63-
requireNonNull(libDir);
64-
requireNonNull(modulesDir);
65-
requireNonNull(pluginsDir);
50+
requireNonNull(pathLookup);
6651
requireNonNull(sourcePaths);
67-
requireNonNull(logsDir);
68-
requireNonNull(tempDir);
6952
requireNonNull(suppressFailureLogClasses);
7053
}
7154
}
@@ -121,23 +104,34 @@ public static void bootstrap(
121104
serverPolicyPatch,
122105
pluginPolicies,
123106
pluginResolver,
124-
settingResolver,
125-
dataDirs,
126-
sharedRepoDirs,
127-
configDir,
128-
libDir,
129-
modulesDir,
130-
pluginsDir,
107+
new PathLookupImpl(
108+
getUserHome(),
109+
configDir,
110+
dataDirs,
111+
sharedRepoDirs,
112+
libDir,
113+
modulesDir,
114+
pluginsDir,
115+
logsDir,
116+
tempDir,
117+
pidFile,
118+
settingResolver
119+
),
131120
sourcePaths,
132-
logsDir,
133-
tempDir,
134-
pidFile,
135121
suppressFailureLogClasses
136122
);
137123
exportInitializationToAgent();
138124
loadAgent(findAgentJar());
139125
}
140126

127+
private static Path getUserHome() {
128+
String userHome = System.getProperty("user.home");
129+
if (userHome == null) {
130+
throw new IllegalStateException("user.home system property is required");
131+
}
132+
return PathUtils.get(userHome);
133+
}
134+
141135
@SuppressForbidden(reason = "The VirtualMachine API is the only way to attach a java agent dynamically")
142136
private static void loadAgent(String agentPath) {
143137
try {

Diff for: libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java

+34-59
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@
5858
import java.nio.file.attribute.FileAttribute;
5959
import java.nio.file.spi.FileSystemProvider;
6060
import java.util.ArrayList;
61-
import java.util.Arrays;
6261
import java.util.Collections;
6362
import java.util.HashMap;
63+
import java.util.HashSet;
6464
import java.util.List;
6565
import java.util.Map;
6666
import java.util.Set;
@@ -70,10 +70,14 @@
7070
import java.util.stream.Stream;
7171
import java.util.stream.StreamSupport;
7272

73+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.CONFIG;
74+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.DATA;
75+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.LIB;
76+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.LOGS;
77+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.MODULES;
78+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.PLUGINS;
79+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.SHARED_REPO;
7380
import static org.elasticsearch.entitlement.runtime.policy.Platform.LINUX;
74-
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.BaseDir.CONFIG;
75-
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.BaseDir.DATA;
76-
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.BaseDir.SHARED_REPO;
7781
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ;
7882
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ_WRITE;
7983

@@ -200,27 +204,20 @@ private static Class<?>[] findClassesToRetransform(Class<?>[] loadedClasses, Set
200204
private static PolicyManager createPolicyManager() {
201205
EntitlementBootstrap.BootstrapArgs bootstrapArgs = EntitlementBootstrap.bootstrapArgs();
202206
Map<String, Policy> pluginPolicies = bootstrapArgs.pluginPolicies();
203-
var pathLookup = new PathLookup(
204-
getUserHome(),
205-
bootstrapArgs.configDir(),
206-
bootstrapArgs.dataDirs(),
207-
bootstrapArgs.sharedRepoDirs(),
208-
bootstrapArgs.tempDir(),
209-
bootstrapArgs.settingResolver()
210-
);
207+
PathLookup pathLookup = bootstrapArgs.pathLookup();
211208

212209
List<Scope> serverScopes = new ArrayList<>();
213210
List<FileData> serverModuleFileDatas = new ArrayList<>();
214211
Collections.addAll(
215212
serverModuleFileDatas,
216213
// Base ES directories
217-
FileData.ofPath(bootstrapArgs.pluginsDir(), READ),
218-
FileData.ofPath(bootstrapArgs.modulesDir(), READ),
219-
FileData.ofPath(bootstrapArgs.configDir(), READ),
220-
FileData.ofPath(bootstrapArgs.logsDir(), READ_WRITE),
221-
FileData.ofPath(bootstrapArgs.libDir(), READ),
222-
FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE),
223-
FileData.ofRelativePath(Path.of(""), SHARED_REPO, READ_WRITE),
214+
FileData.ofBaseDirPath(PLUGINS, READ),
215+
FileData.ofBaseDirPath(MODULES, READ),
216+
FileData.ofBaseDirPath(CONFIG, READ),
217+
FileData.ofBaseDirPath(LOGS, READ_WRITE),
218+
FileData.ofBaseDirPath(LIB, READ),
219+
FileData.ofBaseDirPath(DATA, READ_WRITE),
220+
FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
224221
// exclusive settings file
225222
FileData.ofRelativePath(Path.of("operator/settings.json"), CONFIG, READ_WRITE).withExclusive(true),
226223

@@ -242,8 +239,8 @@ private static PolicyManager createPolicyManager() {
242239
FileData.ofPath(Path.of("/proc/self/mountinfo"), READ).withPlatform(LINUX),
243240
FileData.ofPath(Path.of("/proc/diskstats"), READ).withPlatform(LINUX)
244241
);
245-
if (bootstrapArgs.pidFile() != null) {
246-
serverModuleFileDatas.add(FileData.ofPath(bootstrapArgs.pidFile(), READ_WRITE));
242+
if (pathLookup.pidFile() != null) {
243+
serverModuleFileDatas.add(FileData.ofPath(pathLookup.pidFile(), READ_WRITE));
247244
}
248245

249246
Collections.addAll(
@@ -255,8 +252,8 @@ private static PolicyManager createPolicyManager() {
255252
new FilesEntitlement(
256253
List.of(
257254
// TODO: what in es.base is accessing shared repo?
258-
FileData.ofRelativePath(Path.of(""), SHARED_REPO, READ_WRITE),
259-
FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE)
255+
FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
256+
FileData.ofBaseDirPath(DATA, READ_WRITE)
260257
)
261258
)
262259
)
@@ -281,25 +278,17 @@ private static PolicyManager createPolicyManager() {
281278
List.of(
282279
new LoadNativeLibrariesEntitlement(),
283280
new ManageThreadsEntitlement(),
284-
new FilesEntitlement(
285-
List.of(FileData.ofPath(bootstrapArgs.configDir(), READ), FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE))
286-
)
281+
new FilesEntitlement(List.of(FileData.ofBaseDirPath(CONFIG, READ), FileData.ofBaseDirPath(DATA, READ_WRITE)))
287282
)
288283
),
289-
new Scope(
290-
"org.apache.lucene.misc",
291-
List.of(new FilesEntitlement(List.of(FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE))))
292-
),
284+
new Scope("org.apache.lucene.misc", List.of(new FilesEntitlement(List.of(FileData.ofBaseDirPath(DATA, READ_WRITE))))),
293285
new Scope(
294286
"org.apache.logging.log4j.core",
295-
List.of(new ManageThreadsEntitlement(), new FilesEntitlement(List.of(FileData.ofPath(bootstrapArgs.logsDir(), READ_WRITE))))
287+
List.of(new ManageThreadsEntitlement(), new FilesEntitlement(List.of(FileData.ofBaseDirPath(LOGS, READ_WRITE))))
296288
),
297289
new Scope(
298290
"org.elasticsearch.nativeaccess",
299-
List.of(
300-
new LoadNativeLibrariesEntitlement(),
301-
new FilesEntitlement(List.of(FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE)))
302-
)
291+
List.of(new LoadNativeLibrariesEntitlement(), new FilesEntitlement(List.of(FileData.ofBaseDirPath(DATA, READ_WRITE))))
303292
)
304293
);
305294

@@ -324,7 +313,7 @@ private static PolicyManager createPolicyManager() {
324313
new Scope(
325314
"org.bouncycastle.fips.core",
326315
// read to lib dir is required for checksum validation
327-
List.of(new FilesEntitlement(List.of(FileData.ofPath(bootstrapArgs.libDir(), READ))), new ManageThreadsEntitlement())
316+
List.of(new FilesEntitlement(List.of(FileData.ofBaseDirPath(LIB, READ))), new ManageThreadsEntitlement())
328317
)
329318
);
330319
}
@@ -348,21 +337,14 @@ private static PolicyManager createPolicyManager() {
348337
new LoadNativeLibrariesEntitlement(),
349338
new FilesEntitlement(
350339
List.of(
351-
FileData.ofPath(bootstrapArgs.logsDir(), READ_WRITE),
340+
FileData.ofBaseDirPath(LOGS, READ_WRITE),
352341
FileData.ofPath(Path.of("/proc/meminfo"), READ),
353342
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ)
354343
)
355344
)
356345
);
357346

358-
validateFilesEntitlements(
359-
pluginPolicies,
360-
pathLookup,
361-
bootstrapArgs.configDir(),
362-
bootstrapArgs.pluginsDir(),
363-
bootstrapArgs.modulesDir(),
364-
bootstrapArgs.libDir()
365-
);
347+
validateFilesEntitlements(pluginPolicies, pathLookup);
366348

367349
return new PolicyManager(
368350
serverPolicy,
@@ -377,21 +359,14 @@ private static PolicyManager createPolicyManager() {
377359
);
378360
}
379361

380-
private static Set<Path> pathSet(Path... paths) {
381-
return Arrays.stream(paths).map(x -> x.toAbsolutePath().normalize()).collect(Collectors.toUnmodifiableSet());
382-
}
383-
384362
// package visible for tests
385-
static void validateFilesEntitlements(
386-
Map<String, Policy> pluginPolicies,
387-
PathLookup pathLookup,
388-
Path configDir,
389-
Path pluginsDir,
390-
Path modulesDir,
391-
Path libDir
392-
) {
393-
var readAccessForbidden = pathSet(pluginsDir, modulesDir, libDir);
394-
var writeAccessForbidden = pathSet(configDir);
363+
static void validateFilesEntitlements(Map<String, Policy> pluginPolicies, PathLookup pathLookup) {
364+
Set<Path> readAccessForbidden = new HashSet<>();
365+
pathLookup.getBaseDirPaths(PLUGINS).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
366+
pathLookup.getBaseDirPaths(MODULES).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
367+
pathLookup.getBaseDirPaths(LIB).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
368+
Set<Path> writeAccessForbidden = new HashSet<>();
369+
pathLookup.getBaseDirPaths(CONFIG).forEach(p -> writeAccessForbidden.add(p.toAbsolutePath().normalize()));
395370
for (var pluginPolicy : pluginPolicies.entrySet()) {
396371
for (var scope : pluginPolicy.getValue().scopes()) {
397372
var filesEntitlement = scope.entitlements()

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import static java.util.Comparator.comparing;
3535
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
3636
import static org.elasticsearch.entitlement.runtime.policy.FileUtils.PATH_ORDER;
37+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.CONFIG;
38+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.TEMP;
3739
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ_WRITE;
3840

3941
/**
@@ -239,9 +241,9 @@ private FileAccessTree(FilesEntitlement filesEntitlement, PathLookup pathLookup,
239241
}
240242

241243
// everything has access to the temp dir, config dir, to their own dir (their own jar files) and the jdk
242-
addPathAndMaybeLink.accept(pathLookup.tempDir(), READ_WRITE);
244+
pathLookup.getBaseDirPaths(TEMP).forEach(tempPath -> addPathAndMaybeLink.accept(tempPath, READ_WRITE));
243245
// TODO: this grants read access to the config dir for all modules until explicit read entitlements can be added
244-
addPathAndMaybeLink.accept(pathLookup.configDir(), Mode.READ);
246+
pathLookup.getBaseDirPaths(CONFIG).forEach(configPath -> addPathAndMaybeLink.accept(configPath, Mode.READ));
245247
if (componentPath != null) {
246248
addPathAndMaybeLink.accept(componentPath, Mode.READ);
247249
}

Diff for: libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java

+24-9
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,29 @@
1010
package org.elasticsearch.entitlement.runtime.policy;
1111

1212
import java.nio.file.Path;
13-
import java.util.function.Function;
1413
import java.util.stream.Stream;
1514

16-
public record PathLookup(
17-
Path homeDir,
18-
Path configDir,
19-
Path[] dataDirs,
20-
Path[] sharedRepoDirs,
21-
Path tempDir,
22-
Function<String, Stream<String>> settingResolver
23-
) {}
15+
/**
16+
* Resolves paths for known directories checked by entitlements.
17+
*/
18+
public interface PathLookup {
19+
enum BaseDir {
20+
USER_HOME,
21+
CONFIG,
22+
DATA,
23+
SHARED_REPO,
24+
LIB,
25+
MODULES,
26+
PLUGINS,
27+
LOGS,
28+
TEMP
29+
}
30+
31+
Path pidFile();
32+
33+
Stream<Path> getBaseDirPaths(BaseDir baseDir);
34+
35+
Stream<Path> resolveRelativePaths(BaseDir baseDir, Path relativePath);
36+
37+
Stream<Path> resolveSettingPaths(BaseDir baseDir, String settingName);
38+
}

0 commit comments

Comments
 (0)