Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -67,6 +67,7 @@
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.BaseDir.SHARED_REPO;
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ;
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ_WRITE;
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Platform.LINUX;

/**
* Called by the agent during {@code agentmain} to configure the entitlement system,
Expand Down Expand Up @@ -182,22 +183,22 @@ private static PolicyManager createPolicyManager() {
FileData.ofRelativePath(Path.of(""), SHARED_REPO, READ_WRITE),

// OS release on Linux
FileData.ofPath(Path.of("/etc/os-release"), READ),
FileData.ofPath(Path.of("/etc/system-release"), READ),
FileData.ofPath(Path.of("/usr/lib/os-release"), READ),
FileData.ofPath(Path.of("/etc/os-release"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/etc/system-release"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/usr/lib/os-release"), READ).withPlatform(LINUX),
// read max virtual memory areas
FileData.ofPath(Path.of("/proc/sys/vm/max_map_count"), READ),
FileData.ofPath(Path.of("/proc/meminfo"), READ),
FileData.ofPath(Path.of("/proc/sys/vm/max_map_count"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/proc/meminfo"), READ).withPlatform(LINUX),
// load averages on Linux
FileData.ofPath(Path.of("/proc/loadavg"), READ),
FileData.ofPath(Path.of("/proc/loadavg"), READ).withPlatform(LINUX),
// control group stats on Linux. cgroup v2 stats are in an unpredicable
// location under `/sys/fs/cgroup`, so unfortunately we have to allow
// read access to the entire directory hierarchy.
FileData.ofPath(Path.of("/proc/self/cgroup"), READ),
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ),
FileData.ofPath(Path.of("/proc/self/cgroup"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ).withPlatform(LINUX),
// // io stats on Linux
FileData.ofPath(Path.of("/proc/self/mountinfo"), READ),
FileData.ofPath(Path.of("/proc/diskstats"), READ)
FileData.ofPath(Path.of("/proc/self/mountinfo"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/proc/diskstats"), READ).withPlatform(LINUX)
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ private FileAccessTree(FilesEntitlement filesEntitlement, PathLookup pathLookup)
List<String> readPaths = new ArrayList<>();
List<String> writePaths = new ArrayList<>();
for (FilesEntitlement.FileData fileData : filesEntitlement.filesData()) {
var platform = fileData.platform();
if (platform != null && platform.isCurrent() == false) {
continue;
}
var mode = fileData.mode();
var paths = fileData.resolvePaths(pathLookup);
paths.forEach(path -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,55 @@ public enum BaseDir {
HOME
}

public enum Platform {
LINUX,
MACOS,
WINDOWS;

private static final Platform current = findCurrent();

private static Platform findCurrent() {
String os = System.getProperty("os.name");
if (os.startsWith("Linux")) {
return LINUX;
} else if (os.startsWith("Mac OS")) {
return MACOS;
} else if (os.startsWith("Windows")) {
return WINDOWS;
} else {
throw new AssertionError("Unsupported platform [" + os + "]");
}
}

public boolean isCurrent() {
return this == current;
}
}

public sealed interface FileData {

Stream<Path> resolvePaths(PathLookup pathLookup);

Mode mode();

Platform platform();

FileData withPlatform(Platform platform);

static FileData ofPath(Path path, Mode mode) {
return new AbsolutePathFileData(path, mode);
return new AbsolutePathFileData(path, mode, null);
}

static FileData ofRelativePath(Path relativePath, BaseDir baseDir, Mode mode) {
return new RelativePathFileData(relativePath, baseDir, mode);
return new RelativePathFileData(relativePath, baseDir, mode, null);
}

static FileData ofPathSetting(String setting, Mode mode) {
return new PathSettingFileData(setting, mode);
return new PathSettingFileData(setting, mode, null);
}

static FileData ofRelativePathSetting(String setting, BaseDir baseDir, Mode mode) {
return new RelativePathSettingFileData(setting, baseDir, mode);
return new RelativePathSettingFileData(setting, baseDir, mode, null);
}

/**
Expand Down Expand Up @@ -145,32 +174,70 @@ private static Stream<Path> relativePathsCombination(Path[] baseDirs, Stream<Pat
return paths.stream();
}

private record AbsolutePathFileData(Path path, Mode mode) implements FileData {
private record AbsolutePathFileData(Path path, Mode mode, Platform platform) implements FileData {
@Override
public Stream<Path> resolvePaths(PathLookup pathLookup) {
return Stream.of(path);
}

@Override
public FileData withPlatform(Platform platform) {
if (platform == platform()) {
return this;
}
return new AbsolutePathFileData(path, mode, platform);
}
}

private record RelativePathFileData(Path relativePath, BaseDir baseDir, Mode mode) implements FileData, RelativeFileData {
private record RelativePathFileData(Path relativePath, BaseDir baseDir, Mode mode, Platform platform)
implements
FileData,
RelativeFileData {
@Override
public Stream<Path> resolveRelativePaths(PathLookup pathLookup) {
return Stream.of(relativePath);
}

@Override
public FileData withPlatform(Platform platform) {
if (platform == platform()) {
return this;
}
return new RelativePathFileData(relativePath, baseDir, mode, platform);
}
}

private record PathSettingFileData(String setting, Mode mode) implements FileData {
private record PathSettingFileData(String setting, Mode mode, Platform platform) implements FileData {
@Override
public Stream<Path> resolvePaths(PathLookup pathLookup) {
return resolvePathSettings(pathLookup, setting);
}

@Override
public FileData withPlatform(Platform platform) {
if (platform == platform()) {
return this;
}
return new PathSettingFileData(setting, mode, platform);
}
}

private record RelativePathSettingFileData(String setting, BaseDir baseDir, Mode mode) implements FileData, RelativeFileData {
private record RelativePathSettingFileData(String setting, BaseDir baseDir, Mode mode, Platform platform)
implements
FileData,
RelativeFileData {
@Override
public Stream<Path> resolveRelativePaths(PathLookup pathLookup) {
return resolvePathSettings(pathLookup, setting);
}

@Override
public FileData withPlatform(Platform platform) {
if (platform == platform()) {
return this;
}
return new RelativePathSettingFileData(setting, baseDir, mode, platform);
}
}

private static Stream<Path> resolvePathSettings(PathLookup pathLookup, String setting) {
Expand All @@ -191,6 +258,18 @@ private static Mode parseMode(String mode) {
}
}

private static Platform parsePlatform(String platform) {
if (platform.equals("linux")) {
return Platform.LINUX;
} else if (platform.equals("macos")) {
return Platform.MACOS;
} else if (platform.equals("windows")) {
return Platform.WINDOWS;
} else {
throw new PolicyValidationException("invalid platform: " + platform + ", valid values: [linux, macos, windows]");
}
}

private static BaseDir parseBaseDir(String baseDir) {
return switch (baseDir) {
case "config" -> BaseDir.CONFIG;
Expand Down Expand Up @@ -218,6 +297,7 @@ public static FilesEntitlement build(List<Object> paths) {
String pathSetting = file.remove("path_setting");
String relativePathSetting = file.remove("relative_path_setting");
String modeAsString = file.remove("mode");
String platformAsString = file.remove("platform");

if (file.isEmpty() == false) {
throw new PolicyValidationException("unknown key(s) [" + file + "] in a listed file for files entitlement");
Expand All @@ -234,36 +314,45 @@ public static FilesEntitlement build(List<Object> paths) {
throw new PolicyValidationException("files entitlement must contain 'mode' for every listed file");
}
Mode mode = parseMode(modeAsString);
Platform platform = null;
if (platformAsString != null) {
platform = parsePlatform(platformAsString);
}

BaseDir baseDir = null;
if (relativeTo != null) {
baseDir = parseBaseDir(relativeTo);
}

final FileData fileData;
if (relativePathAsString != null) {
if (baseDir == null) {
throw new PolicyValidationException("files entitlement with a 'relative_path' must specify 'relative_to'");
}

Path relativePath = Path.of(relativePathAsString);
if (FileData.isAbsolutePath(relativePathAsString)) {
throw new PolicyValidationException("'relative_path' [" + relativePathAsString + "] must be relative");
}
filesData.add(FileData.ofRelativePath(Path.of(relativePathAsString), baseDir, mode));
fileData = FileData.ofRelativePath(relativePath, baseDir, mode);
} else if (pathAsString != null) {
Path path = Path.of(pathAsString);
if (FileData.isAbsolutePath(pathAsString) == false) {
throw new PolicyValidationException("'path' [" + pathAsString + "] must be absolute");
}
filesData.add(FileData.ofPath(Path.of(pathAsString), mode));
fileData = FileData.ofPath(path, mode);
} else if (pathSetting != null) {
filesData.add(FileData.ofPathSetting(pathSetting, mode));
fileData = FileData.ofPathSetting(pathSetting, mode);
} else if (relativePathSetting != null) {
if (baseDir == null) {
throw new PolicyValidationException("files entitlement with a 'relative_path_setting' must specify 'relative_to'");
}
filesData.add(FileData.ofRelativePathSetting(relativePathSetting, baseDir, mode));
fileData = FileData.ofRelativePathSetting(relativePathSetting, baseDir, mode);
} else {
throw new AssertionError("File entry validation error");
}

filesData.add(fileData.withPlatform(platform));
}
return new FilesEntitlement(filesData);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ org.elasticsearch.ml:
- relative_path: "ml-local-data/"
relative_to: data
mode: read_write
- path: \\.\pipe\
mode: read_write
platform: windows