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 @@ -66,6 +66,19 @@ public static Path createTempSymbolicLink() throws IOException {
return Files.createSymbolicLink(readDir().resolve("entitlements-link-" + random.nextLong()), readWriteDir());
}

public static Path createK8sLikeMount() throws IOException {
Path baseDir = readDir().resolve("k8s");
var versionedDir = Files.createDirectories(baseDir.resolve("..version"));
var actualFileMount = Files.createFile(versionedDir.resolve("mount-" + random.nextLong() + ".tmp"));

var dataDir = Files.createSymbolicLink(baseDir.resolve("..data"), versionedDir.getFileName());
// mount-0.tmp -> ..data/mount-0.tmp -> ..version/mount-0.tmp
return Files.createSymbolicLink(
baseDir.resolve(actualFileMount.getFileName()),
dataDir.getFileName().resolve(actualFileMount.getFileName())
);
}

public static URLConnection createHttpURLConnection() throws IOException {
return URI.create("http://127.0.0.1:12345/").toURL().openConnection();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,16 @@ static void checkFilesCreateSymbolicLink() throws IOException {
}
}

@EntitlementTest(expectedAccess = PLUGINS)
static void checkFilesCreateRelativeSymbolicLink() throws IOException {
var directory = EntitledActions.createTempDirectoryForWrite();
try {
Files.createSymbolicLink(directory.resolve("link"), Path.of("target"));
} catch (UnsupportedOperationException | FileSystemException e) {
// OK not to implement symbolic link in the filesystem
}
}

@EntitlementTest(expectedAccess = PLUGINS)
static void checkFilesCreateLink() throws IOException {
var directory = EntitledActions.createTempDirectoryForWrite();
Expand All @@ -150,6 +160,17 @@ static void checkFilesCreateLink() throws IOException {
}
}

@EntitlementTest(expectedAccess = PLUGINS)
static void checkFilesCreateRelativeLink() throws IOException {
var directory = EntitledActions.createTempDirectoryForWrite();
var target = directory.resolve("target");
try {
Files.createLink(directory.resolve("link"), Path.of("target"));
} catch (UnsupportedOperationException | FileSystemException e) {
// OK not to implement symbolic link in the filesystem
}
}

@EntitlementTest(expectedAccess = PLUGINS)
static void checkFilesDelete() throws IOException {
var file = EntitledActions.createTempFileForWrite();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

package org.elasticsearch.entitlement.qa.test;

import org.elasticsearch.entitlement.qa.entitled.EntitledActions;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.LinkOption;
Expand All @@ -24,6 +26,11 @@ static void checkToRealPath() throws IOException {
FileCheckActions.readFile().toRealPath();
}

@EntitlementTest(expectedAccess = PLUGINS)
static void checkToRealPathWithK8sLikeMount() throws IOException, Exception {
EntitledActions.createK8sLikeMount().toRealPath();
}

@EntitlementTest(expectedAccess = PLUGINS)
static void checkToRealPathNoFollow() throws IOException {
FileCheckActions.readFile().toRealPath(LinkOption.NOFOLLOW_LINKS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class EntitlementsTestRule implements TestRule {
"files",
List.of(
Map.of("path", tempDir.resolve("read_dir"), "mode", "read_write"),
Map.of("path", tempDir.resolve("read_dir").resolve("k8s").resolve("..data"), "mode", "read", "exclusive", true),
Map.of("path", tempDir.resolve("read_write_dir"), "mode", "read_write"),
Map.of("path", tempDir.resolve("read_file"), "mode", "read"),
Map.of("path", tempDir.resolve("read_write_file"), "mode", "read_write")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.io.FileDescriptor;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
Expand Down Expand Up @@ -74,7 +73,6 @@
import java.nio.file.FileStore;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
Expand Down Expand Up @@ -2050,16 +2048,21 @@ public void checkSelectorProviderInheritedChannel(Class<?> callerClass, Selector
policyManager.checkCreateTempFile(callerClass);
}

private static Path resolveLinkTarget(Path path, Path target) {
var parent = path.getParent();
return parent == null ? target : parent.resolve(target);
}

@Override
public void check$java_nio_file_Files$$createSymbolicLink(Class<?> callerClass, Path link, Path target, FileAttribute<?>... attrs) {
policyManager.checkFileRead(callerClass, target);
policyManager.checkFileWrite(callerClass, link);
policyManager.checkFileRead(callerClass, resolveLinkTarget(link, target));
}

@Override
public void check$java_nio_file_Files$$createLink(Class<?> callerClass, Path link, Path existing) {
policyManager.checkFileRead(callerClass, existing);
policyManager.checkFileWrite(callerClass, link);
policyManager.checkFileRead(callerClass, resolveLinkTarget(link, existing));
}

@Override
Expand Down Expand Up @@ -2548,13 +2551,13 @@ public void checkCreateDirectory(Class<?> callerClass, FileSystemProvider that,
@Override
public void checkCreateSymbolicLink(Class<?> callerClass, FileSystemProvider that, Path link, Path target, FileAttribute<?>... attrs) {
policyManager.checkFileWrite(callerClass, link);
policyManager.checkFileRead(callerClass, target);
policyManager.checkFileRead(callerClass, resolveLinkTarget(link, target));
}

@Override
public void checkCreateLink(Class<?> callerClass, FileSystemProvider that, Path link, Path existing) {
policyManager.checkFileWrite(callerClass, link);
policyManager.checkFileRead(callerClass, existing);
policyManager.checkFileRead(callerClass, resolveLinkTarget(link, existing));
}

@Override
Expand Down Expand Up @@ -2748,14 +2751,7 @@ public void checkPathToRealPath(Class<?> callerClass, Path that, LinkOption... o
followLinks = false;
}
}
if (followLinks) {
try {
policyManager.checkFileRead(callerClass, Files.readSymbolicLink(that));
} catch (IOException | UnsupportedOperationException e) {
// that is not a link, or unrelated IOException or unsupported
}
}
policyManager.checkFileRead(callerClass, that);
policyManager.checkFileRead(callerClass, that, followLinks);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.elasticsearch.logging.Logger;

import java.io.File;
import java.io.IOException;
import java.lang.StackWalker.StackFrame;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
Expand Down Expand Up @@ -325,6 +326,10 @@ private static boolean isPathOnDefaultFilesystem(Path path) {
}

public void checkFileRead(Class<?> callerClass, Path path) {
checkFileRead(callerClass, path, false);
}

public void checkFileRead(Class<?> callerClass, Path path, boolean followLinks) {
if (isPathOnDefaultFilesystem(path) == false) {
return;
}
Expand All @@ -334,14 +339,28 @@ public void checkFileRead(Class<?> callerClass, Path path) {
}

ModuleEntitlements entitlements = getEntitlements(requestingClass);
if (entitlements.fileAccess().canRead(path) == false) {

Path realPath = null;
boolean canRead = entitlements.fileAccess().canRead(path);
if (canRead && followLinks) {
try {
realPath = path.toRealPath();
} catch (IOException e) {
// target not found or other IO error
}
if (realPath != null && realPath.equals(path) == false) {
canRead = entitlements.fileAccess().canRead(realPath);
}
}

if (canRead == false) {
notEntitled(
Strings.format(
"Not entitled: component [%s], module [%s], class [%s], entitlement [file], operation [read], path [%s]",
entitlements.componentName(),
requestingClass.getModule().getName(),
requestingClass,
path
realPath == null ? path : Strings.format("%s -> %s", path, realPath)
),
callerClass
);
Expand Down