From e400940da5fac72938095b73b1a9456786cea75d Mon Sep 17 00:00:00 2001 From: Patrick Doyle Date: Tue, 18 Feb 2025 17:28:24 -0500 Subject: [PATCH 1/7] java.base entitlements --- libs/entitlement/asm-provider/build.gradle | 1 + .../src/main/java/module-info.java | 1 + .../impl/InstrumenterImpl.java | 7 +- .../bridge/EntitlementChecker.java | 40 +++++ .../entitlement/qa/test/FileCheckActions.java | 18 +- .../qa/test/JavaBaseFileActions.java | 165 ++++++++++++++++++ .../qa/test/RestEntitlementsCheckAction.java | 1 + .../api/ElasticsearchEntitlementChecker.java | 92 ++++++++++ .../runtime/policy/PolicyManager.java | 13 ++ 9 files changed, 319 insertions(+), 19 deletions(-) create mode 100644 libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java diff --git a/libs/entitlement/asm-provider/build.gradle b/libs/entitlement/asm-provider/build.gradle index c6b51b7da3dff..7bfd3e1f1f553 100644 --- a/libs/entitlement/asm-provider/build.gradle +++ b/libs/entitlement/asm-provider/build.gradle @@ -12,6 +12,7 @@ apply plugin: 'elasticsearch.build' dependencies { compileOnly project(':libs:entitlement') compileOnly project(':libs:core') + compileOnly project(':libs:logging') implementation 'org.ow2.asm:asm:9.7.1' testImplementation project(":test:framework") testImplementation project(":libs:entitlement:bridge") diff --git a/libs/entitlement/asm-provider/src/main/java/module-info.java b/libs/entitlement/asm-provider/src/main/java/module-info.java index f953454f93b91..eebf0c81ca2b0 100644 --- a/libs/entitlement/asm-provider/src/main/java/module-info.java +++ b/libs/entitlement/asm-provider/src/main/java/module-info.java @@ -15,6 +15,7 @@ requires org.elasticsearch.entitlement; requires static org.elasticsearch.base; // for SuppressForbidden + requires static org.elasticsearch.logging; provides InstrumentationService with InstrumentationServiceImpl; } diff --git a/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java b/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java index b10c58afacb1e..4d8f0bce655b1 100644 --- a/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java +++ b/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java @@ -12,6 +12,8 @@ import org.elasticsearch.entitlement.instrumentation.CheckMethod; import org.elasticsearch.entitlement.instrumentation.Instrumenter; import org.elasticsearch.entitlement.instrumentation.MethodKey; +import org.elasticsearch.logging.LogManager; +import org.elasticsearch.logging.Logger; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -36,6 +38,7 @@ import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; public class InstrumenterImpl implements Instrumenter { + private static final Logger logger = LogManager.getLogger(InstrumenterImpl.class); private final String getCheckerClassMethodDescriptor; private final String handleClass; @@ -155,10 +158,10 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str var key = new MethodKey(className, name, Stream.of(Type.getArgumentTypes(descriptor)).map(Type::getInternalName).toList()); var instrumentationMethod = checkMethods.get(key); if (instrumentationMethod != null) { - // System.out.println("Will instrument method " + key); + logger.debug("Will instrument {}", key); return new EntitlementMethodVisitor(Opcodes.ASM9, mv, isStatic, isCtor, descriptor, instrumentationMethod); } else { - // System.out.println("Will not instrument method " + key); + logger.trace("Will not instrument {}", key); } } return mv; diff --git a/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java b/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java index f113960be9275..b50880494a4c6 100644 --- a/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java +++ b/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java @@ -66,6 +66,8 @@ import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.UserPrincipal; import java.nio.file.spi.FileSystemProvider; +import java.security.KeyStore; +import java.security.Provider; import java.security.cert.CertStoreParameters; import java.util.List; import java.util.Locale; @@ -621,12 +623,50 @@ public interface EntitlementChecker { void check$java_io_RandomAccessFile$(Class callerClass, File file, String mode); + void check$java_security_KeyStore$$getInstance(Class callerClass, File file, char[] password); + + void check$java_security_KeyStore$$getInstance(Class callerClass, File file, KeyStore.LoadStoreParameter param); + + void check$java_security_KeyStore$Builder$$newInstance(Class callerClass, File file, KeyStore.ProtectionParameter protection); + + void check$java_security_KeyStore$Builder$$newInstance( + Class callerClass, + String type, + Provider provider, + File file, + KeyStore.ProtectionParameter protection + ); + void check$java_util_Scanner$(Class callerClass, File source); void check$java_util_Scanner$(Class callerClass, File source, String charsetName); void check$java_util_Scanner$(Class callerClass, File source, Charset charset); + void check$java_util_jar_JarFile$(Class callerClass, String name); + + void check$java_util_jar_JarFile$(Class callerClass, String name, boolean verify); + + void check$java_util_jar_JarFile$(Class callerClass, File file); + + void check$java_util_jar_JarFile$(Class callerClass, File file, boolean verify); + + void check$java_util_jar_JarFile$(Class callerClass, File file, boolean verify, int mode); + + void check$java_util_jar_JarFile$(Class callerClass, File file, boolean verify, int mode, Runtime.Version version); + + void check$java_util_zip_ZipFile$(Class callerClass, String name); + + void check$java_util_zip_ZipFile$(Class callerClass, String name, Charset charset); + + void check$java_util_zip_ZipFile$(Class callerClass, File file); + + void check$java_util_zip_ZipFile$(Class callerClass, File file, int mode); + + void check$java_util_zip_ZipFile$(Class callerClass, File file, Charset charset); + + void check$java_util_zip_ZipFile$(Class callerClass, File file, int mode, Charset charset); + // nio void check$java_nio_file_Files$$getOwner(Class callerClass, Path path, LinkOption... options); diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java index bedb8790c1ad8..331f29f8c662b 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java @@ -15,7 +15,6 @@ import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; @@ -26,12 +25,12 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.UserPrincipal; -import java.util.Scanner; import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_DENIED; import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS; @SuppressForbidden(reason = "Explicitly checking APIs that are forbidden") +@SuppressWarnings("unused") // Called via reflection class FileCheckActions { static Path testRootDir = Paths.get(System.getProperty("es.entitlements.testdir")); @@ -207,21 +206,6 @@ static void fileSetWritableOwner() throws IOException { readWriteFile().toFile().setWritable(true, false); } - @EntitlementTest(expectedAccess = PLUGINS) - static void createScannerFile() throws FileNotFoundException { - new Scanner(readFile().toFile()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void createScannerFileWithCharset() throws IOException { - new Scanner(readFile().toFile(), StandardCharsets.UTF_8); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void createScannerFileWithCharsetName() throws FileNotFoundException { - new Scanner(readFile().toFile(), "UTF-8"); - } - @EntitlementTest(expectedAccess = PLUGINS) static void createFileInputStreamFile() throws IOException { new FileInputStream(readFile().toFile()).close(); diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java new file mode 100644 index 0000000000000..7b7ec908c2f44 --- /dev/null +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.entitlement.qa.test; + +import org.elasticsearch.core.CheckedRunnable; +import org.elasticsearch.core.SuppressForbidden; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.util.Scanner; +import java.util.jar.JarFile; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import static java.nio.charset.Charset.defaultCharset; +import static java.util.zip.ZipFile.OPEN_DELETE; +import static java.util.zip.ZipFile.OPEN_READ; +import static org.elasticsearch.entitlement.qa.entitled.EntitledActions.createTempFileForWrite; +import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS; +import static org.elasticsearch.entitlement.qa.test.FileCheckActions.readFile; + +@SuppressForbidden(reason = "Explicitly checking APIs that are forbidden") +@SuppressWarnings("unused") // Called via reflection +public class JavaBaseFileActions { + @EntitlementTest(expectedAccess = PLUGINS) + static void keystore_getInstance_1() throws IOException { + try { + KeyStore.getInstance(readFile().toFile(), new char[0]); + } catch (GeneralSecurityException expected) { + return; + } + throw new AssertionError("Expected an exception"); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void keystore_getInstance_2() throws IOException { + try { + KeyStore.LoadStoreParameter loadStoreParameter = () -> null; + KeyStore.getInstance(readFile().toFile(), loadStoreParameter); + } catch (GeneralSecurityException expected) { + return; + } + throw new AssertionError("Expected an exception"); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void keystoreBuilder_newInstance() { + try { + KeyStore.Builder.newInstance("", null, readFile().toFile(), null); + } catch (NullPointerException expected) { + return; + } + throw new AssertionError("Expected an exception"); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_1() throws IOException { + expectZipException(() -> new ZipFile(readFile().toString()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_2() throws IOException { + expectZipException(() -> new ZipFile(readFile().toString(), defaultCharset()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_3() throws IOException { + expectZipException(() -> new ZipFile(readFile().toFile()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_4() throws IOException { + expectZipException(() -> new ZipFile(readFile().toFile(), defaultCharset()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_5_readOnly() throws IOException { + expectZipException(() -> new ZipFile(readFile().toFile(), OPEN_READ).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_5_readAndDelete() throws IOException { + expectZipException(() -> new ZipFile(createTempFileForWrite().toFile(), OPEN_READ | OPEN_DELETE).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_6_readOnly() throws IOException { + expectZipException(() -> new ZipFile(readFile().toFile(), OPEN_READ, defaultCharset()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_1() throws IOException { + expectZipException(() -> new JarFile(readFile().toString()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_2() throws IOException { + expectZipException(() -> new JarFile(readFile().toString(), false).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_3_readOnly() throws IOException { + expectZipException(() -> new JarFile(readFile().toFile(), false, OPEN_READ).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_3_readAndDelete() throws IOException { + expectZipException(() -> new JarFile(createTempFileForWrite().toFile(), false, OPEN_READ | OPEN_DELETE).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_4_readOnly() throws IOException { + expectZipException(() -> new JarFile(readFile().toFile(), false, OPEN_READ, Runtime.version()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_4_readAndDelete() throws IOException { + expectZipException(() -> new JarFile(createTempFileForWrite().toFile(), false, OPEN_READ | OPEN_DELETE, Runtime.version()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_5() throws IOException { + expectZipException(() -> new JarFile(readFile().toFile()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_6() throws IOException { + expectZipException(() -> new JarFile(readFile().toFile(), false).close()); + } + + private static void expectZipException(CheckedRunnable action) throws IOException { + try { + action.run(); + } catch (ZipException expected) { + return; + } + throw new AssertionError("Expected an exception"); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void createScannerFile() throws FileNotFoundException { + new Scanner(readFile().toFile()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void createScannerFileWithCharset() throws IOException { + new Scanner(readFile().toFile(), StandardCharsets.UTF_8); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void createScannerFileWithCharsetName() throws FileNotFoundException { + new Scanner(readFile().toFile(), "UTF-8"); + } + +} diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java index 8c0b8d18612f2..950508a16ff4b 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java @@ -187,6 +187,7 @@ static CheckAction alwaysDenied(CheckedRunnable action) { ), getTestEntries(FileCheckActions.class), getTestEntries(FileStoreActions.class), + getTestEntries(JavaBaseFileActions.class), getTestEntries(ManageThreadsActions.class), getTestEntries(NativeActions.class), getTestEntries(NioFileSystemActions.class), diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java index 1e2a88f82f7dd..4109151ddc496 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java @@ -74,6 +74,8 @@ import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.UserPrincipal; import java.nio.file.spi.FileSystemProvider; +import java.security.KeyStore; +import java.security.Provider; import java.security.cert.CertStoreParameters; import java.util.List; import java.util.Locale; @@ -1232,6 +1234,36 @@ public void checkSelectorProviderInheritedChannel(Class callerClass, Selector } } + @Override + public void check$java_security_KeyStore$$getInstance(Class callerClass, File file, char[] password) { + policyManager.checkFileRead(callerClass, file); + } + + @Override + public void check$java_security_KeyStore$$getInstance(Class callerClass, File file, KeyStore.LoadStoreParameter param) { + policyManager.checkFileRead(callerClass, file); + } + + @Override + public void check$java_security_KeyStore$Builder$$newInstance( + Class callerClass, + File file, + KeyStore.ProtectionParameter protection + ) { + policyManager.checkFileRead(callerClass, file); + } + + @Override + public void check$java_security_KeyStore$Builder$$newInstance( + Class callerClass, + String type, + Provider provider, + File file, + KeyStore.ProtectionParameter protection + ) { + policyManager.checkFileRead(callerClass, file); + } + @Override public void check$java_util_Scanner$(Class callerClass, File source) { policyManager.checkFileRead(callerClass, source); @@ -1247,6 +1279,66 @@ public void checkSelectorProviderInheritedChannel(Class callerClass, Selector policyManager.checkFileRead(callerClass, source); } + @Override + public void check$java_util_jar_JarFile$(Class callerClass, String name) { + policyManager.checkFileRead(callerClass, new File(name)); + } + + @Override + public void check$java_util_jar_JarFile$(Class callerClass, String name, boolean verify) { + policyManager.checkFileRead(callerClass, new File(name)); + } + + @Override + public void check$java_util_jar_JarFile$(Class callerClass, File file) { + policyManager.checkFileRead(callerClass, file); + } + + @Override + public void check$java_util_jar_JarFile$(Class callerClass, File file, boolean verify) { + policyManager.checkFileRead(callerClass, file); + } + + @Override + public void check$java_util_jar_JarFile$(Class callerClass, File file, boolean verify, int mode) { + policyManager.checkFileWithZipMode(callerClass, file, mode); + } + + @Override + public void check$java_util_jar_JarFile$(Class callerClass, File file, boolean verify, int mode, Runtime.Version version) { + policyManager.checkFileWithZipMode(callerClass, file, mode); + } + + @Override + public void check$java_util_zip_ZipFile$(Class callerClass, String name) { + policyManager.checkFileRead(callerClass, new File(name)); + } + + @Override + public void check$java_util_zip_ZipFile$(Class callerClass, String name, Charset charset) { + policyManager.checkFileRead(callerClass, new File(name)); + } + + @Override + public void check$java_util_zip_ZipFile$(Class callerClass, File file) { + policyManager.checkFileRead(callerClass, file); + } + + @Override + public void check$java_util_zip_ZipFile$(Class callerClass, File file, int mode) { + policyManager.checkFileWithZipMode(callerClass, file, mode); + } + + @Override + public void check$java_util_zip_ZipFile$(Class callerClass, File file, Charset charset) { + policyManager.checkFileRead(callerClass, file); + } + + @Override + public void check$java_util_zip_ZipFile$(Class callerClass, File file, int mode, Charset charset) { + policyManager.checkFileWithZipMode(callerClass, file, mode); + } + // nio @Override diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java index d607a5e25b410..f470e2c485183 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java @@ -48,6 +48,8 @@ import static java.util.function.Predicate.not; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toUnmodifiableMap; +import static java.util.zip.ZipFile.OPEN_DELETE; +import static java.util.zip.ZipFile.OPEN_READ; public class PolicyManager { private static final Logger logger = LogManager.getLogger(PolicyManager.class); @@ -304,6 +306,17 @@ public void checkFileWrite(Class callerClass, Path path) { } } + public void checkFileWithZipMode(Class callerClass, File file, int zipMode) { + assert zipMode == OPEN_READ || zipMode == (OPEN_READ | OPEN_DELETE); + if ((zipMode & OPEN_DELETE) == OPEN_DELETE) { + // This needs both read and write, but we happen to know that checkFileWrite + // actually checks both. + checkFileWrite(callerClass, file); + } else { + checkFileRead(callerClass, file); + } + } + public void checkFileDescriptorRead(Class callerClass) { neverEntitled(callerClass, () -> "read file descriptor"); } From a095b3a5e82aa7e7d5ed843294b8fc671b455b4e Mon Sep 17 00:00:00 2001 From: Patrick Doyle Date: Tue, 18 Feb 2025 18:30:11 -0500 Subject: [PATCH 2/7] SuppressForbidden, and add a missing test --- .../entitlement/qa/test/JavaBaseFileActions.java | 5 +++++ .../entitlement/runtime/policy/PolicyManager.java | 1 + 2 files changed, 6 insertions(+) diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java index 7b7ec908c2f44..5a3386628370e 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java @@ -98,6 +98,11 @@ static void zipFile_6_readOnly() throws IOException { expectZipException(() -> new ZipFile(readFile().toFile(), OPEN_READ, defaultCharset()).close()); } + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_6_readAndDelete() throws IOException { + expectZipException(() -> new ZipFile(createTempFileForWrite().toFile(), OPEN_READ | OPEN_DELETE, defaultCharset()).close()); + } + @EntitlementTest(expectedAccess = PLUGINS) static void jarFile_1() throws IOException { expectZipException(() -> new JarFile(readFile().toString()).close()); diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java index f470e2c485183..bbff4eed539aa 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java @@ -306,6 +306,7 @@ public void checkFileWrite(Class callerClass, Path path) { } } + @SuppressForbidden(reason = "Explicitly checking File apis") public void checkFileWithZipMode(Class callerClass, File file, int zipMode) { assert zipMode == OPEN_READ || zipMode == (OPEN_READ | OPEN_DELETE); if ((zipMode & OPEN_DELETE) == OPEN_DELETE) { From ea6159cf5ed6d7f9e4712f00a43c249b0f809a7e Mon Sep 17 00:00:00 2001 From: Patrick Doyle Date: Wed, 19 Feb 2025 07:33:04 -0500 Subject: [PATCH 3/7] Revert logging back to commented-out printlns --- .../entitlement/instrumentation/impl/InstrumenterImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java b/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java index 4d8f0bce655b1..45f972705eaa6 100644 --- a/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java +++ b/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java @@ -158,10 +158,10 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str var key = new MethodKey(className, name, Stream.of(Type.getArgumentTypes(descriptor)).map(Type::getInternalName).toList()); var instrumentationMethod = checkMethods.get(key); if (instrumentationMethod != null) { - logger.debug("Will instrument {}", key); + // System.out.println("Will instrument method " + key); return new EntitlementMethodVisitor(Opcodes.ASM9, mv, isStatic, isCtor, descriptor, instrumentationMethod); } else { - logger.trace("Will not instrument {}", key); + // System.out.println("Will not instrument method " + key); } } return mv; From 64060e040713aa6d36215a8b2ba0fe75f912a83a Mon Sep 17 00:00:00 2001 From: Patrick Doyle Date: Wed, 19 Feb 2025 07:33:20 -0500 Subject: [PATCH 4/7] Merge FileCheckActions and rename for overloads --- .../entitlement/qa/test/FileCheckActions.java | 149 ++++++++++++++- .../qa/test/JavaBaseFileActions.java | 170 ------------------ .../qa/test/RestEntitlementsCheckAction.java | 1 - 3 files changed, 148 insertions(+), 172 deletions(-) delete mode 100644 libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java index 331f29f8c662b..05fbc716e5723 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java @@ -9,12 +9,14 @@ package org.elasticsearch.entitlement.qa.test; +import org.elasticsearch.core.CheckedRunnable; import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.entitlement.qa.entitled.EntitledActions; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; @@ -25,7 +27,17 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.UserPrincipal; - +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.util.Scanner; +import java.util.jar.JarFile; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import static java.nio.charset.Charset.defaultCharset; +import static java.util.zip.ZipFile.OPEN_DELETE; +import static java.util.zip.ZipFile.OPEN_READ; +import static org.elasticsearch.entitlement.qa.entitled.EntitledActions.createTempFileForWrite; import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_DENIED; import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS; @@ -347,5 +359,140 @@ static void filesSetOwner() throws IOException { Files.setOwner(readWriteFile(), owner); // set to existing owner, just trying to execute the method } + @EntitlementTest(expectedAccess = PLUGINS) + static void keystoreGetInstance_FileCharArray() throws IOException { + try { + KeyStore.getInstance(readFile().toFile(), new char[0]); + } catch (GeneralSecurityException expected) { + return; + } + throw new AssertionError("Expected an exception"); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void keystoreGetInstance_FileLoadStoreParameter() throws IOException { + try { + KeyStore.LoadStoreParameter loadStoreParameter = () -> null; + KeyStore.getInstance(readFile().toFile(), loadStoreParameter); + } catch (GeneralSecurityException expected) { + return; + } + throw new AssertionError("Expected an exception"); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void keystoreBuilderNewInstance() { + try { + KeyStore.Builder.newInstance("", null, readFile().toFile(), null); + } catch (NullPointerException expected) { + return; + } + throw new AssertionError("Expected an exception"); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_String() throws IOException { + expectZipException(() -> new ZipFile(readFile().toString()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_StringCharset() throws IOException { + expectZipException(() -> new ZipFile(readFile().toString(), defaultCharset()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_File() throws IOException { + expectZipException(() -> new ZipFile(readFile().toFile()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_FileCharset() throws IOException { + expectZipException(() -> new ZipFile(readFile().toFile(), defaultCharset()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_FileReadOnly() throws IOException { + expectZipException(() -> new ZipFile(readFile().toFile(), OPEN_READ).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_FileReadAndDelete() throws IOException { + expectZipException(() -> new ZipFile(createTempFileForWrite().toFile(), OPEN_READ | OPEN_DELETE).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_ReadOnlyCharset() throws IOException { + expectZipException(() -> new ZipFile(readFile().toFile(), OPEN_READ, defaultCharset()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void zipFile_ReadAndDeleteCharset() throws IOException { + expectZipException(() -> new ZipFile(createTempFileForWrite().toFile(), OPEN_READ | OPEN_DELETE, defaultCharset()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_String() throws IOException { + expectZipException(() -> new JarFile(readFile().toString()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_StringBoolean() throws IOException { + expectZipException(() -> new JarFile(readFile().toString(), false).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_FileReadOnly() throws IOException { + expectZipException(() -> new JarFile(readFile().toFile(), false, OPEN_READ).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_FileReadAndDelete() throws IOException { + expectZipException(() -> new JarFile(createTempFileForWrite().toFile(), false, OPEN_READ | OPEN_DELETE).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_FileBooleanReadOnlyVersion() throws IOException { + expectZipException(() -> new JarFile(readFile().toFile(), false, OPEN_READ, Runtime.version()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_FileBooleanReadAndDeleteOnlyVersion() throws IOException { + expectZipException(() -> new JarFile(createTempFileForWrite().toFile(), false, OPEN_READ | OPEN_DELETE, Runtime.version()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFile_File() throws IOException { + expectZipException(() -> new JarFile(readFile().toFile()).close()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void jarFileFileBoolean() throws IOException { + expectZipException(() -> new JarFile(readFile().toFile(), false).close()); + } + + private static void expectZipException(CheckedRunnable action) throws IOException { + try { + action.run(); + } catch (ZipException expected) { + return; + } + throw new AssertionError("Expected an exception"); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void createScannerFile() throws FileNotFoundException { + new Scanner(readFile().toFile()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void createScannerFileWithCharset() throws IOException { + new Scanner(readFile().toFile(), StandardCharsets.UTF_8); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void createScannerFileWithCharsetName() throws FileNotFoundException { + new Scanner(readFile().toFile(), "UTF-8"); + } + private FileCheckActions() {} } diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java deleted file mode 100644 index 5a3386628370e..0000000000000 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JavaBaseFileActions.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -package org.elasticsearch.entitlement.qa.test; - -import org.elasticsearch.core.CheckedRunnable; -import org.elasticsearch.core.SuppressForbidden; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.util.Scanner; -import java.util.jar.JarFile; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; - -import static java.nio.charset.Charset.defaultCharset; -import static java.util.zip.ZipFile.OPEN_DELETE; -import static java.util.zip.ZipFile.OPEN_READ; -import static org.elasticsearch.entitlement.qa.entitled.EntitledActions.createTempFileForWrite; -import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS; -import static org.elasticsearch.entitlement.qa.test.FileCheckActions.readFile; - -@SuppressForbidden(reason = "Explicitly checking APIs that are forbidden") -@SuppressWarnings("unused") // Called via reflection -public class JavaBaseFileActions { - @EntitlementTest(expectedAccess = PLUGINS) - static void keystore_getInstance_1() throws IOException { - try { - KeyStore.getInstance(readFile().toFile(), new char[0]); - } catch (GeneralSecurityException expected) { - return; - } - throw new AssertionError("Expected an exception"); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void keystore_getInstance_2() throws IOException { - try { - KeyStore.LoadStoreParameter loadStoreParameter = () -> null; - KeyStore.getInstance(readFile().toFile(), loadStoreParameter); - } catch (GeneralSecurityException expected) { - return; - } - throw new AssertionError("Expected an exception"); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void keystoreBuilder_newInstance() { - try { - KeyStore.Builder.newInstance("", null, readFile().toFile(), null); - } catch (NullPointerException expected) { - return; - } - throw new AssertionError("Expected an exception"); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void zipFile_1() throws IOException { - expectZipException(() -> new ZipFile(readFile().toString()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void zipFile_2() throws IOException { - expectZipException(() -> new ZipFile(readFile().toString(), defaultCharset()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void zipFile_3() throws IOException { - expectZipException(() -> new ZipFile(readFile().toFile()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void zipFile_4() throws IOException { - expectZipException(() -> new ZipFile(readFile().toFile(), defaultCharset()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void zipFile_5_readOnly() throws IOException { - expectZipException(() -> new ZipFile(readFile().toFile(), OPEN_READ).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void zipFile_5_readAndDelete() throws IOException { - expectZipException(() -> new ZipFile(createTempFileForWrite().toFile(), OPEN_READ | OPEN_DELETE).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void zipFile_6_readOnly() throws IOException { - expectZipException(() -> new ZipFile(readFile().toFile(), OPEN_READ, defaultCharset()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void zipFile_6_readAndDelete() throws IOException { - expectZipException(() -> new ZipFile(createTempFileForWrite().toFile(), OPEN_READ | OPEN_DELETE, defaultCharset()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void jarFile_1() throws IOException { - expectZipException(() -> new JarFile(readFile().toString()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void jarFile_2() throws IOException { - expectZipException(() -> new JarFile(readFile().toString(), false).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void jarFile_3_readOnly() throws IOException { - expectZipException(() -> new JarFile(readFile().toFile(), false, OPEN_READ).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void jarFile_3_readAndDelete() throws IOException { - expectZipException(() -> new JarFile(createTempFileForWrite().toFile(), false, OPEN_READ | OPEN_DELETE).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void jarFile_4_readOnly() throws IOException { - expectZipException(() -> new JarFile(readFile().toFile(), false, OPEN_READ, Runtime.version()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void jarFile_4_readAndDelete() throws IOException { - expectZipException(() -> new JarFile(createTempFileForWrite().toFile(), false, OPEN_READ | OPEN_DELETE, Runtime.version()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void jarFile_5() throws IOException { - expectZipException(() -> new JarFile(readFile().toFile()).close()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void jarFile_6() throws IOException { - expectZipException(() -> new JarFile(readFile().toFile(), false).close()); - } - - private static void expectZipException(CheckedRunnable action) throws IOException { - try { - action.run(); - } catch (ZipException expected) { - return; - } - throw new AssertionError("Expected an exception"); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void createScannerFile() throws FileNotFoundException { - new Scanner(readFile().toFile()); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void createScannerFileWithCharset() throws IOException { - new Scanner(readFile().toFile(), StandardCharsets.UTF_8); - } - - @EntitlementTest(expectedAccess = PLUGINS) - static void createScannerFileWithCharsetName() throws FileNotFoundException { - new Scanner(readFile().toFile(), "UTF-8"); - } - -} diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java index 950508a16ff4b..8c0b8d18612f2 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java @@ -187,7 +187,6 @@ static CheckAction alwaysDenied(CheckedRunnable action) { ), getTestEntries(FileCheckActions.class), getTestEntries(FileStoreActions.class), - getTestEntries(JavaBaseFileActions.class), getTestEntries(ManageThreadsActions.class), getTestEntries(NativeActions.class), getTestEntries(NioFileSystemActions.class), From 9d151ef67cf4bd055a1ce0d7daf501200e3553db Mon Sep 17 00:00:00 2001 From: Patrick Doyle Date: Wed, 19 Feb 2025 07:46:18 -0500 Subject: [PATCH 5/7] Remove stray logger --- .../entitlement/instrumentation/impl/InstrumenterImpl.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java b/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java index 45f972705eaa6..9f89f46c8bd5b 100644 --- a/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java +++ b/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumenterImpl.java @@ -12,8 +12,6 @@ import org.elasticsearch.entitlement.instrumentation.CheckMethod; import org.elasticsearch.entitlement.instrumentation.Instrumenter; import org.elasticsearch.entitlement.instrumentation.MethodKey; -import org.elasticsearch.logging.LogManager; -import org.elasticsearch.logging.Logger; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -38,8 +36,6 @@ import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; public class InstrumenterImpl implements Instrumenter { - private static final Logger logger = LogManager.getLogger(InstrumenterImpl.class); - private final String getCheckerClassMethodDescriptor; private final String handleClass; From 089bdac5627b381a0fabc6a80cac1cc4b2a1729a Mon Sep 17 00:00:00 2001 From: Patrick Doyle Date: Wed, 19 Feb 2025 07:50:03 -0500 Subject: [PATCH 6/7] Remove more traces of logging change --- libs/entitlement/asm-provider/src/main/java/module-info.java | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/entitlement/asm-provider/src/main/java/module-info.java b/libs/entitlement/asm-provider/src/main/java/module-info.java index eebf0c81ca2b0..f953454f93b91 100644 --- a/libs/entitlement/asm-provider/src/main/java/module-info.java +++ b/libs/entitlement/asm-provider/src/main/java/module-info.java @@ -15,7 +15,6 @@ requires org.elasticsearch.entitlement; requires static org.elasticsearch.base; // for SuppressForbidden - requires static org.elasticsearch.logging; provides InstrumentationService with InstrumentationServiceImpl; } From e02ae80448676be34d5ddc008cfe52ef34ddde16 Mon Sep 17 00:00:00 2001 From: Patrick Doyle Date: Wed, 19 Feb 2025 07:56:13 -0500 Subject: [PATCH 7/7] Remove more traces of logging --- libs/entitlement/asm-provider/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/entitlement/asm-provider/build.gradle b/libs/entitlement/asm-provider/build.gradle index 7bfd3e1f1f553..c6b51b7da3dff 100644 --- a/libs/entitlement/asm-provider/build.gradle +++ b/libs/entitlement/asm-provider/build.gradle @@ -12,7 +12,6 @@ apply plugin: 'elasticsearch.build' dependencies { compileOnly project(':libs:entitlement') compileOnly project(':libs:core') - compileOnly project(':libs:logging') implementation 'org.ow2.asm:asm:9.7.1' testImplementation project(":test:framework") testImplementation project(":libs:entitlement:bridge")