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 @@ -500,6 +500,36 @@ public interface EntitlementChecker {
//

// old io (ie File)
void check$java_io_File$createNewFile(Class<?> callerClass, File file);

void check$java_io_File$$createTempFile(Class<?> callerClass, String prefix, String suffix, File directory);

void check$java_io_File$delete(Class<?> callerClass, File file);

void check$java_io_File$deleteOnExit(Class<?> callerClass, File file);

void check$java_io_File$mkdir(Class<?> callerClass, File file);

void check$java_io_File$mkdirs(Class<?> callerClass, File file);

void check$java_io_File$renameTo(Class<?> callerClass, File file, File dest);

void check$java_io_File$setExecutable(Class<?> callerClass, File file, boolean executable);

void check$java_io_File$setExecutable(Class<?> callerClass, File file, boolean executable, boolean ownerOnly);

void check$java_io_File$setLastModified(Class<?> callerClass, File file, long time);

void check$java_io_File$setReadable(Class<?> callerClass, File file, boolean readable);

void check$java_io_File$setReadable(Class<?> callerClass, File file, boolean readable, boolean ownerOnly);

void check$java_io_File$setReadOnly(Class<?> callerClass, File file);

void check$java_io_File$setWritable(Class<?> callerClass, File file, boolean writable);

void check$java_io_File$setWritable(Class<?> callerClass, File file, boolean writable, boolean ownerOnly);

void check$java_io_FileOutputStream$(Class<?> callerClass, File file);

void check$java_io_FileOutputStream$(Class<?> callerClass, File file, boolean append);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ static void System_clearProperty(String key) {
public static UserPrincipal getFileOwner(Path path) throws IOException {
return Files.getOwner(path);
}

public static void createFile(Path path) throws IOException {
Files.createFile(path);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.elasticsearch.core.SuppressForbidden;
import org.elasticsearch.entitlement.qa.entitled.EntitledActions;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -45,6 +46,91 @@ private static Path readWriteFile() {
return testRootDir.resolve("read_write_file");
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileCreateNewFile() throws IOException {
readWriteDir().resolve("new_file").toFile().createNewFile();
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileCreateTempFile() throws IOException {
File.createTempFile("prefix", "suffix", readWriteDir().toFile());
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileDelete() throws IOException {
Path toDelete = readWriteDir().resolve("to_delete");
EntitledActions.createFile(toDelete);
toDelete.toFile().delete();
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileDeleteOnExit() throws IOException {
Path toDelete = readWriteDir().resolve("to_delete_on_exit");
EntitledActions.createFile(toDelete);
toDelete.toFile().deleteOnExit();
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileMkdir() throws IOException {
Path mkdir = readWriteDir().resolve("mkdir");
mkdir.toFile().mkdir();
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileMkdirs() throws IOException {
Path mkdir = readWriteDir().resolve("mkdirs");
mkdir.toFile().mkdirs();
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileRenameTo() throws IOException {
Path toRename = readWriteDir().resolve("to_rename");
EntitledActions.createFile(toRename);
toRename.toFile().renameTo(readWriteDir().resolve("renamed").toFile());
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileSetExecutable() throws IOException {
readWriteFile().toFile().setExecutable(false);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileSetExecutableOwner() throws IOException {
readWriteFile().toFile().setExecutable(false, false);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileSetLastModified() throws IOException {
readWriteFile().toFile().setLastModified(System.currentTimeMillis());
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileSetReadable() throws IOException {
readWriteFile().toFile().setReadable(true);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileSetReadableOwner() throws IOException {
readWriteFile().toFile().setReadable(true, false);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileSetReadOnly() throws IOException {
Path readOnly = readWriteDir().resolve("read_only");
EntitledActions.createFile(readOnly);
readOnly.toFile().setReadOnly();
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileSetWritable() throws IOException {
readWriteFile().toFile().setWritable(true);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void fileSetWritableOwner() throws IOException {
readWriteFile().toFile().setWritable(true, false);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void createScannerFile() throws FileNotFoundException {
new Scanner(readFile().toFile());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import com.sun.tools.attach.VirtualMachine;

import org.elasticsearch.core.CheckedConsumer;
import org.elasticsearch.core.CheckedSupplier;
import org.elasticsearch.core.SuppressForbidden;
import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
Expand All @@ -27,7 +26,6 @@
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
import java.util.Map;
import java.util.function.Function;

Expand Down Expand Up @@ -149,11 +147,8 @@ private static String findAgentJar() {
*/
private static void selfTest() {
ensureCannotStartProcess(ProcessBuilder::start);
ensureCanCreateTempFile(EntitlementBootstrap::createTempFile);

// Try again with reflection
ensureCannotStartProcess(EntitlementBootstrap::reflectiveStartProcess);
ensureCanCreateTempFile(EntitlementBootstrap::reflectiveCreateTempFile);
}

private static void ensureCannotStartProcess(CheckedConsumer<ProcessBuilder, ?> startProcess) {
Expand All @@ -169,31 +164,6 @@ private static void ensureCannotStartProcess(CheckedConsumer<ProcessBuilder, ?>
throw new IllegalStateException("Entitlement protection self-test was incorrectly permitted");
}

@SuppressForbidden(reason = "accesses jvm default tempdir as a self-test")
private static void ensureCanCreateTempFile(CheckedSupplier<Path, ?> createTempFile) {
try {
Path p = createTempFile.get();
p.toFile().deleteOnExit();

// Make an effort to clean up the file immediately; also, deleteOnExit leaves the file if the JVM exits abnormally.
try {
Files.delete(p);
} catch (IOException ignored) {
// Can be caused by virus scanner
}
} catch (NotEntitledException e) {
throw new IllegalStateException("Entitlement protection self-test was incorrectly forbidden", e);
} catch (Exception e) {
throw new IllegalStateException("Unable to perform entitlement protection self-test", e);
}
logger.debug("Success: Entitlement protection correctly permitted temp file creation");
}

@SuppressForbidden(reason = "accesses jvm default tempdir as a self-test")
private static Path createTempFile() throws Exception {
return Files.createTempFile(null, null);
}

private static void reflectiveStartProcess(ProcessBuilder pb) throws Exception {
try {
var start = ProcessBuilder.class.getMethod("start");
Expand All @@ -203,10 +173,5 @@ private static void reflectiveStartProcess(ProcessBuilder pb) throws Exception {
}
}

private static Path reflectiveCreateTempFile() throws Exception {
return (Path) Files.class.getMethod("createTempFile", String.class, String.class, FileAttribute[].class)
.invoke(null, null, null, new FileAttribute<?>[0]);
}

private static final Logger logger = LogManager.getLogger(EntitlementBootstrap.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.ExitVMEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.FileData;
import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement;
Expand All @@ -37,13 +39,16 @@
import java.nio.file.Path;
import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ_WRITE;

/**
* Called by the agent during {@code agentmain} to configure the entitlement system,
* instantiate and configure an {@link EntitlementChecker},
Expand Down Expand Up @@ -109,6 +114,7 @@ private static Class<?>[] findClassesToRetransform(Class<?>[] loadedClasses, Set

private static PolicyManager createPolicyManager() {
Map<String, Policy> pluginPolicies = EntitlementBootstrap.bootstrapArgs().pluginPolicies();
Path[] dataDirs = EntitlementBootstrap.bootstrapArgs().dataDirs();

// TODO(ES-10031): Decide what goes in the elasticsearch default policy and extend it
var serverPolicy = new Policy(
Expand All @@ -129,7 +135,13 @@ private static PolicyManager createPolicyManager() {
new Scope("org.apache.httpcomponents.httpclient", List.of(new OutboundNetworkEntitlement())),
new Scope("io.netty.transport", List.of(new InboundNetworkEntitlement(), new OutboundNetworkEntitlement())),
new Scope("org.apache.lucene.core", List.of(new LoadNativeLibrariesEntitlement())),
new Scope("org.elasticsearch.nativeaccess", List.of(new LoadNativeLibrariesEntitlement()))
new Scope(
"org.elasticsearch.nativeaccess",
List.of(
new LoadNativeLibrariesEntitlement(),
new FilesEntitlement(Arrays.stream(dataDirs).map(d -> new FileData(d.toString(), READ_WRITE)).toList())
)
)
)
);
// agents run without a module, so this is a special hack for the apm agent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,82 @@ public void checkSelectorProviderInheritedChannel(Class<?> callerClass, Selector

// old io (ie File)

@Override
public void check$java_io_File$createNewFile(Class<?> callerClass, File file) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$$createTempFile(Class<?> callerClass, String prefix, String suffix, File directory) {
policyManager.checkFileWrite(callerClass, directory);
}

@Override
public void check$java_io_File$delete(Class<?> callerClass, File file) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$deleteOnExit(Class<?> callerClass, File file) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$mkdir(Class<?> callerClass, File file) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$mkdirs(Class<?> callerClass, File file) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$renameTo(Class<?> callerClass, File file, File dest) {
policyManager.checkFileRead(callerClass, file);
policyManager.checkFileWrite(callerClass, dest);
}

@Override
public void check$java_io_File$setExecutable(Class<?> callerClass, File file, boolean executable) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$setExecutable(Class<?> callerClass, File file, boolean executable, boolean ownerOnly) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$setLastModified(Class<?> callerClass, File file, long time) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$setReadable(Class<?> callerClass, File file, boolean readable) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$setReadable(Class<?> callerClass, File file, boolean readable, boolean ownerOnly) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$setReadOnly(Class<?> callerClass, File file) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$setWritable(Class<?> callerClass, File file, boolean writable) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_File$setWritable(Class<?> callerClass, File file, boolean writable, boolean ownerOnly) {
policyManager.checkFileWrite(callerClass, file);
}

@Override
public void check$java_io_FileOutputStream$(Class<?> callerClass, String name) {
policyManager.checkFileWrite(callerClass, new File(name));
Expand Down