From 348ae182a216c26c13f2ee196c0a7ed87c65b44a Mon Sep 17 00:00:00 2001 From: Lorenzo Dematte Date: Mon, 5 May 2025 10:30:18 +0200 Subject: [PATCH 1/2] Extract instrumentation initialization to a separate class --- .../DynamicInstrumentation.java | 270 ++++++++++++++++++ .../EntitlementInitialization.java | 235 +-------------- 2 files changed, 274 insertions(+), 231 deletions(-) create mode 100644 libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/DynamicInstrumentation.java diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/DynamicInstrumentation.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/DynamicInstrumentation.java new file mode 100644 index 0000000000000..2db3b0e7d3433 --- /dev/null +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/DynamicInstrumentation.java @@ -0,0 +1,270 @@ +/* + * 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.initialization; + +import org.elasticsearch.core.internal.provider.ProviderLocator; +import org.elasticsearch.entitlement.bridge.EntitlementChecker; +import org.elasticsearch.entitlement.instrumentation.CheckMethod; +import org.elasticsearch.entitlement.instrumentation.InstrumentationService; +import org.elasticsearch.entitlement.instrumentation.Instrumenter; +import org.elasticsearch.entitlement.instrumentation.MethodKey; +import org.elasticsearch.entitlement.instrumentation.Transformer; +import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement; + +import java.lang.instrument.Instrumentation; +import java.lang.instrument.UnmodifiableClassException; +import java.net.URI; +import java.nio.channels.spi.SelectorProvider; +import java.nio.file.AccessMode; +import java.nio.file.CopyOption; +import java.nio.file.DirectoryStream; +import java.nio.file.FileStore; +import java.nio.file.FileSystems; +import java.nio.file.LinkOption; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.WatchEvent; +import java.nio.file.WatchService; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.spi.FileSystemProvider; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +class DynamicInstrumentation { + + interface InstrumentationInfoFactory { + InstrumentationService.InstrumentationInfo of(String methodName, Class... parameterTypes) throws ClassNotFoundException, + NoSuchMethodException; + } + + private static final InstrumentationService INSTRUMENTATION_SERVICE = new ProviderLocator<>( + "entitlement", + InstrumentationService.class, + "org.elasticsearch.entitlement.instrumentation", + Set.of() + ).get(); + + /** + * Initializes the dynamic (agent-based) instrumentation: + *
    + *
  1. + * Finds the version-specific subclass of {@link EntitlementChecker} to use + *
  2. + *
  3. + * Builds the set of methods to instrument using {@link InstrumentationService#lookupMethods} + *
  4. + *
  5. + * Augment this set “dynamically” using {@link InstrumentationService#lookupImplementationMethod} + *
  6. + *
  7. + * Creates an {@link Instrumenter} via {@link InstrumentationService#newInstrumenter}, and adds a new {@link Transformer} (derived from + * {@link java.lang.instrument.ClassFileTransformer}) that uses it. Transformers are invoked when a class is about to load, after its + * bytes have been deserialized to memory but before the class is initialized. + *
  8. + *
  9. + * Re-transforms all already loaded classes: we force the {@link Instrumenter} to run on classes that might have been already loaded + * before entitlement initialization by calling the {@link java.lang.instrument.Instrumentation#retransformClasses} method on all + * classes that were already loaded. + *
  10. + *
+ *

+ * The third step is needed as the JDK exposes some API through interfaces that have different (internal) implementations + * depending on the JVM host platform. As we cannot instrument an interfaces, we find its concrete implementation. + * A prime example is {@link FileSystemProvider}, which has different implementations (e.g. {@code UnixFileSystemProvider} or + * {@code WindowsFileSystemProvider}). At runtime, we find the implementation class which is currently used by the JVM, and add + * its methods to the set of methods to instrument. See e.g. {@link DynamicInstrumentation#fileSystemProviderChecks}. + *

+ * + * @param inst the JVM instrumentation class instance + * @param checkerInterface the interface to use to find methods to instrument and to use in the injected instrumentation code + * @param verifyBytecode whether we should perform bytecode verification before and after instrumenting each method + */ + static void initialize(Instrumentation inst, Class checkerInterface, boolean verifyBytecode) + throws ClassNotFoundException, NoSuchMethodException, UnmodifiableClassException { + + var checkMethods = getMethodsToInstrument(checkerInterface); + var classesToTransform = checkMethods.keySet().stream().map(MethodKey::className).collect(Collectors.toSet()); + + Instrumenter instrumenter = INSTRUMENTATION_SERVICE.newInstrumenter(checkerInterface, checkMethods); + var transformer = new Transformer(instrumenter, classesToTransform, verifyBytecode); + inst.addTransformer(transformer, true); + + var classesToRetransform = findClassesToRetransform(inst.getAllLoadedClasses(), classesToTransform); + try { + inst.retransformClasses(classesToRetransform); + } catch (VerifyError e) { + // Turn on verification and try to retransform one class at the time to get detailed diagnostic + transformer.enableClassVerification(); + + for (var classToRetransform : classesToRetransform) { + inst.retransformClasses(classToRetransform); + } + + // We should have failed already in the loop above, but just in case we did not, rethrow. + throw e; + } + } + + private static Map getMethodsToInstrument(Class checkerInterface) + throws ClassNotFoundException, NoSuchMethodException { + Map checkMethods = new HashMap<>(INSTRUMENTATION_SERVICE.lookupMethods(checkerInterface)); + Stream.of( + fileSystemProviderChecks(), + fileStoreChecks(), + pathChecks(), + Stream.of( + INSTRUMENTATION_SERVICE.lookupImplementationMethod( + SelectorProvider.class, + "inheritedChannel", + SelectorProvider.provider().getClass(), + EntitlementChecker.class, + "checkSelectorProviderInheritedChannel" + ) + ) + ) + .flatMap(Function.identity()) + .forEach(instrumentation -> checkMethods.put(instrumentation.targetMethod(), instrumentation.checkMethod())); + + return checkMethods; + } + + private static Stream fileSystemProviderChecks() throws ClassNotFoundException, + NoSuchMethodException { + var fileSystemProviderClass = FileSystems.getDefault().provider().getClass(); + + var instrumentation = new InstrumentationInfoFactory() { + @Override + public InstrumentationService.InstrumentationInfo of(String methodName, Class... parameterTypes) + throws ClassNotFoundException, NoSuchMethodException { + return INSTRUMENTATION_SERVICE.lookupImplementationMethod( + FileSystemProvider.class, + methodName, + fileSystemProviderClass, + EntitlementChecker.class, + "check" + Character.toUpperCase(methodName.charAt(0)) + methodName.substring(1), + parameterTypes + ); + } + }; + + return Stream.of( + instrumentation.of("newFileSystem", URI.class, Map.class), + instrumentation.of("newFileSystem", Path.class, Map.class), + instrumentation.of("newInputStream", Path.class, OpenOption[].class), + instrumentation.of("newOutputStream", Path.class, OpenOption[].class), + instrumentation.of("newFileChannel", Path.class, Set.class, FileAttribute[].class), + instrumentation.of("newAsynchronousFileChannel", Path.class, Set.class, ExecutorService.class, FileAttribute[].class), + instrumentation.of("newByteChannel", Path.class, Set.class, FileAttribute[].class), + instrumentation.of("newDirectoryStream", Path.class, DirectoryStream.Filter.class), + instrumentation.of("createDirectory", Path.class, FileAttribute[].class), + instrumentation.of("createSymbolicLink", Path.class, Path.class, FileAttribute[].class), + instrumentation.of("createLink", Path.class, Path.class), + instrumentation.of("delete", Path.class), + instrumentation.of("deleteIfExists", Path.class), + instrumentation.of("readSymbolicLink", Path.class), + instrumentation.of("copy", Path.class, Path.class, CopyOption[].class), + instrumentation.of("move", Path.class, Path.class, CopyOption[].class), + instrumentation.of("isSameFile", Path.class, Path.class), + instrumentation.of("isHidden", Path.class), + instrumentation.of("getFileStore", Path.class), + instrumentation.of("checkAccess", Path.class, AccessMode[].class), + instrumentation.of("getFileAttributeView", Path.class, Class.class, LinkOption[].class), + instrumentation.of("readAttributes", Path.class, Class.class, LinkOption[].class), + instrumentation.of("readAttributes", Path.class, String.class, LinkOption[].class), + instrumentation.of("readAttributesIfExists", Path.class, Class.class, LinkOption[].class), + instrumentation.of("setAttribute", Path.class, String.class, Object.class, LinkOption[].class), + instrumentation.of("exists", Path.class, LinkOption[].class) + ); + } + + private static Stream fileStoreChecks() { + var fileStoreClasses = StreamSupport.stream(FileSystems.getDefault().getFileStores().spliterator(), false) + .map(FileStore::getClass) + .distinct(); + return fileStoreClasses.flatMap(fileStoreClass -> { + var instrumentation = new InstrumentationInfoFactory() { + @Override + public InstrumentationService.InstrumentationInfo of(String methodName, Class... parameterTypes) + throws ClassNotFoundException, NoSuchMethodException { + return INSTRUMENTATION_SERVICE.lookupImplementationMethod( + FileStore.class, + methodName, + fileStoreClass, + EntitlementChecker.class, + "check" + Character.toUpperCase(methodName.charAt(0)) + methodName.substring(1), + parameterTypes + ); + } + }; + + try { + return Stream.of( + instrumentation.of("getFileStoreAttributeView", Class.class), + instrumentation.of("getAttribute", String.class), + instrumentation.of("getBlockSize"), + instrumentation.of("getTotalSpace"), + instrumentation.of("getUnallocatedSpace"), + instrumentation.of("getUsableSpace"), + instrumentation.of("isReadOnly"), + instrumentation.of("name"), + instrumentation.of("type") + + ); + } catch (NoSuchMethodException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + }); + } + + private static Stream pathChecks() { + var pathClasses = StreamSupport.stream(FileSystems.getDefault().getRootDirectories().spliterator(), false) + .map(Path::getClass) + .distinct(); + return pathClasses.flatMap(pathClass -> { + InstrumentationInfoFactory instrumentation = (String methodName, Class... parameterTypes) -> INSTRUMENTATION_SERVICE + .lookupImplementationMethod( + Path.class, + methodName, + pathClass, + EntitlementChecker.class, + "checkPath" + Character.toUpperCase(methodName.charAt(0)) + methodName.substring(1), + parameterTypes + ); + + try { + return Stream.of( + instrumentation.of("toRealPath", LinkOption[].class), + instrumentation.of("register", WatchService.class, WatchEvent.Kind[].class), + instrumentation.of("register", WatchService.class, WatchEvent.Kind[].class, WatchEvent.Modifier[].class) + ); + } catch (NoSuchMethodException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + }); + } + + private static Class[] findClassesToRetransform(Class[] loadedClasses, Set classesToTransform) { + List> retransform = new ArrayList<>(); + for (Class loadedClass : loadedClasses) { + if (classesToTransform.contains(loadedClass.getName().replace(".", "/"))) { + retransform.add(loadedClass); + } + } + return retransform.toArray(new Class[0]); + } +} diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java index 1968dbdd4f204..2e1c6c8f753bc 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java @@ -10,16 +10,9 @@ package org.elasticsearch.entitlement.initialization; import org.elasticsearch.core.Booleans; -import org.elasticsearch.core.PathUtils; import org.elasticsearch.core.Strings; -import org.elasticsearch.core.internal.provider.ProviderLocator; import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap; import org.elasticsearch.entitlement.bridge.EntitlementChecker; -import org.elasticsearch.entitlement.instrumentation.CheckMethod; -import org.elasticsearch.entitlement.instrumentation.InstrumentationService; -import org.elasticsearch.entitlement.instrumentation.Instrumenter; -import org.elasticsearch.entitlement.instrumentation.MethodKey; -import org.elasticsearch.entitlement.instrumentation.Transformer; import org.elasticsearch.entitlement.runtime.api.ElasticsearchEntitlementChecker; import org.elasticsearch.entitlement.runtime.policy.FileAccessTree; import org.elasticsearch.entitlement.runtime.policy.PathLookup; @@ -43,32 +36,13 @@ import java.lang.instrument.Instrumentation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.net.URI; -import java.nio.channels.spi.SelectorProvider; -import java.nio.file.AccessMode; -import java.nio.file.CopyOption; -import java.nio.file.DirectoryStream; -import java.nio.file.FileStore; -import java.nio.file.FileSystems; -import java.nio.file.LinkOption; -import java.nio.file.OpenOption; import java.nio.file.Path; -import java.nio.file.WatchEvent; -import java.nio.file.WatchService; -import java.nio.file.attribute.FileAttribute; -import java.nio.file.spi.FileSystemProvider; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.CONFIG; import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.DATA; @@ -94,11 +68,6 @@ public class EntitlementInitialization { private static ElasticsearchEntitlementChecker manager; - interface InstrumentationInfoFactory { - InstrumentationService.InstrumentationInfo of(String methodName, Class... parameterTypes) throws ClassNotFoundException, - NoSuchMethodException; - } - // Note: referenced by bridge reflectively public static EntitlementChecker checker() { return manager; @@ -108,33 +77,16 @@ public static EntitlementChecker checker() { * Initializes the Entitlement system: *
    *
  1. - * Finds the version-specific subclass of {@link EntitlementChecker} to use - *
  2. - *
  3. - * Builds the set of methods to instrument using {@link InstrumentationService#lookupMethods} - *
  4. - *
  5. - * Augment this set “dynamically” using {@link InstrumentationService#lookupImplementationMethod} + * Initialize dynamic instrumentation via {@link DynamicInstrumentation#initialize} *
  6. *
  7. - * Creates an {@link Instrumenter} via {@link InstrumentationService#newInstrumenter}, and adds a new {@link Transformer} (derived from - * {@link java.lang.instrument.ClassFileTransformer}) that uses it. Transformers are invoked when a class is about to load, after its - * bytes have been deserialized to memory but before the class is initialized. + * Creates the {@link PolicyManager} *
  8. *
  9. - * Re-transforms all already loaded classes: we force the {@link Instrumenter} to run on classes that might have been already loaded - * before entitlement initialization by calling the {@link java.lang.instrument.Instrumentation#retransformClasses} method on all - * classes that were already loaded. + * Creates the {@link ElasticsearchEntitlementChecker} instance referenced by the instrumented methods *
  10. *
*

- * The third step is needed as the JDK exposes some API through interfaces that have different (internal) implementations - * depending on the JVM host platform. As we cannot instrument an interfaces, we find its concrete implementation. - * A prime example is {@link FileSystemProvider}, which has different implementations (e.g. {@code UnixFileSystemProvider} or - * {@code WindowsFileSystemProvider}). At runtime, we find the implementation class which is currently used by the JVM, and add - * its methods to the set of methods to instrument. See e.g. {@link EntitlementInitialization#fileSystemProviderChecks}. - *

- *

* NOTE: this method is referenced by the agent reflectively *

* @@ -143,61 +95,12 @@ public static EntitlementChecker checker() { public static void initialize(Instrumentation inst) throws Exception { manager = initChecker(); - var latestCheckerInterface = getVersionSpecificCheckerClass(EntitlementChecker.class); var verifyBytecode = Booleans.parseBoolean(System.getProperty("es.entitlements.verify_bytecode", "false")); - if (verifyBytecode) { ensureClassesSensitiveToVerificationAreInitialized(); } - Map checkMethods = new HashMap<>(INSTRUMENTATION_SERVICE.lookupMethods(latestCheckerInterface)); - Stream.of( - fileSystemProviderChecks(), - fileStoreChecks(), - pathChecks(), - Stream.of( - INSTRUMENTATION_SERVICE.lookupImplementationMethod( - SelectorProvider.class, - "inheritedChannel", - SelectorProvider.provider().getClass(), - EntitlementChecker.class, - "checkSelectorProviderInheritedChannel" - ) - ) - ) - .flatMap(Function.identity()) - .forEach(instrumentation -> checkMethods.put(instrumentation.targetMethod(), instrumentation.checkMethod())); - - var classesToTransform = checkMethods.keySet().stream().map(MethodKey::className).collect(Collectors.toSet()); - - Instrumenter instrumenter = INSTRUMENTATION_SERVICE.newInstrumenter(latestCheckerInterface, checkMethods); - var transformer = new Transformer(instrumenter, classesToTransform, verifyBytecode); - inst.addTransformer(transformer, true); - - var classesToRetransform = findClassesToRetransform(inst.getAllLoadedClasses(), classesToTransform); - try { - inst.retransformClasses(classesToRetransform); - } catch (VerifyError e) { - // Turn on verification and try to retransform one class at the time to get detailed diagnostic - transformer.enableClassVerification(); - - for (var classToRetransform : classesToRetransform) { - inst.retransformClasses(classToRetransform); - } - - // We should have failed already in the loop above, but just in case we did not, rethrow. - throw e; - } - } - - private static Class[] findClassesToRetransform(Class[] loadedClasses, Set classesToTransform) { - List> retransform = new ArrayList<>(); - for (Class loadedClass : loadedClasses) { - if (classesToTransform.contains(loadedClass.getName().replace(".", "/"))) { - retransform.add(loadedClass); - } - } - return retransform.toArray(new Class[0]); + DynamicInstrumentation.initialize(inst, getVersionSpecificCheckerClass(EntitlementChecker.class), verifyBytecode); } private static PolicyManager createPolicyManager() { @@ -427,129 +330,6 @@ private static void validateWriteFilesEntitlements( } } - private static Path getUserHome() { - String userHome = System.getProperty("user.home"); - if (userHome == null) { - throw new IllegalStateException("user.home system property is required"); - } - return PathUtils.get(userHome); - } - - private static Stream fileSystemProviderChecks() throws ClassNotFoundException, - NoSuchMethodException { - var fileSystemProviderClass = FileSystems.getDefault().provider().getClass(); - - var instrumentation = new InstrumentationInfoFactory() { - @Override - public InstrumentationService.InstrumentationInfo of(String methodName, Class... parameterTypes) - throws ClassNotFoundException, NoSuchMethodException { - return INSTRUMENTATION_SERVICE.lookupImplementationMethod( - FileSystemProvider.class, - methodName, - fileSystemProviderClass, - EntitlementChecker.class, - "check" + Character.toUpperCase(methodName.charAt(0)) + methodName.substring(1), - parameterTypes - ); - } - }; - - return Stream.of( - instrumentation.of("newFileSystem", URI.class, Map.class), - instrumentation.of("newFileSystem", Path.class, Map.class), - instrumentation.of("newInputStream", Path.class, OpenOption[].class), - instrumentation.of("newOutputStream", Path.class, OpenOption[].class), - instrumentation.of("newFileChannel", Path.class, Set.class, FileAttribute[].class), - instrumentation.of("newAsynchronousFileChannel", Path.class, Set.class, ExecutorService.class, FileAttribute[].class), - instrumentation.of("newByteChannel", Path.class, Set.class, FileAttribute[].class), - instrumentation.of("newDirectoryStream", Path.class, DirectoryStream.Filter.class), - instrumentation.of("createDirectory", Path.class, FileAttribute[].class), - instrumentation.of("createSymbolicLink", Path.class, Path.class, FileAttribute[].class), - instrumentation.of("createLink", Path.class, Path.class), - instrumentation.of("delete", Path.class), - instrumentation.of("deleteIfExists", Path.class), - instrumentation.of("readSymbolicLink", Path.class), - instrumentation.of("copy", Path.class, Path.class, CopyOption[].class), - instrumentation.of("move", Path.class, Path.class, CopyOption[].class), - instrumentation.of("isSameFile", Path.class, Path.class), - instrumentation.of("isHidden", Path.class), - instrumentation.of("getFileStore", Path.class), - instrumentation.of("checkAccess", Path.class, AccessMode[].class), - instrumentation.of("getFileAttributeView", Path.class, Class.class, LinkOption[].class), - instrumentation.of("readAttributes", Path.class, Class.class, LinkOption[].class), - instrumentation.of("readAttributes", Path.class, String.class, LinkOption[].class), - instrumentation.of("readAttributesIfExists", Path.class, Class.class, LinkOption[].class), - instrumentation.of("setAttribute", Path.class, String.class, Object.class, LinkOption[].class), - instrumentation.of("exists", Path.class, LinkOption[].class) - ); - } - - private static Stream fileStoreChecks() { - var fileStoreClasses = StreamSupport.stream(FileSystems.getDefault().getFileStores().spliterator(), false) - .map(FileStore::getClass) - .distinct(); - return fileStoreClasses.flatMap(fileStoreClass -> { - var instrumentation = new InstrumentationInfoFactory() { - @Override - public InstrumentationService.InstrumentationInfo of(String methodName, Class... parameterTypes) - throws ClassNotFoundException, NoSuchMethodException { - return INSTRUMENTATION_SERVICE.lookupImplementationMethod( - FileStore.class, - methodName, - fileStoreClass, - EntitlementChecker.class, - "check" + Character.toUpperCase(methodName.charAt(0)) + methodName.substring(1), - parameterTypes - ); - } - }; - - try { - return Stream.of( - instrumentation.of("getFileStoreAttributeView", Class.class), - instrumentation.of("getAttribute", String.class), - instrumentation.of("getBlockSize"), - instrumentation.of("getTotalSpace"), - instrumentation.of("getUnallocatedSpace"), - instrumentation.of("getUsableSpace"), - instrumentation.of("isReadOnly"), - instrumentation.of("name"), - instrumentation.of("type") - - ); - } catch (NoSuchMethodException | ClassNotFoundException e) { - throw new RuntimeException(e); - } - }); - } - - private static Stream pathChecks() { - var pathClasses = StreamSupport.stream(FileSystems.getDefault().getRootDirectories().spliterator(), false) - .map(Path::getClass) - .distinct(); - return pathClasses.flatMap(pathClass -> { - InstrumentationInfoFactory instrumentation = (String methodName, Class... parameterTypes) -> INSTRUMENTATION_SERVICE - .lookupImplementationMethod( - Path.class, - methodName, - pathClass, - EntitlementChecker.class, - "checkPath" + Character.toUpperCase(methodName.charAt(0)) + methodName.substring(1), - parameterTypes - ); - - try { - return Stream.of( - instrumentation.of("toRealPath", LinkOption[].class), - instrumentation.of("register", WatchService.class, WatchEvent.Kind[].class), - instrumentation.of("register", WatchService.class, WatchEvent.Kind[].class, WatchEvent.Modifier[].class) - ); - } catch (NoSuchMethodException | ClassNotFoundException e) { - throw new RuntimeException(e); - } - }); - } - /** * If bytecode verification is enabled, ensure these classes get loaded before transforming/retransforming them. * For these classes, the order in which we transform and verify them matters. Verification during class transformation is at least an @@ -614,11 +394,4 @@ private static ElasticsearchEntitlementChecker initChecker() { throw new AssertionError(e); } } - - private static final InstrumentationService INSTRUMENTATION_SERVICE = new ProviderLocator<>( - "entitlement", - InstrumentationService.class, - "org.elasticsearch.entitlement.instrumentation", - Set.of() - ).get(); } From 4a7e05dae898a61b61cfc90e6dd31fe466288ef1 Mon Sep 17 00:00:00 2001 From: Lorenzo Dematte Date: Mon, 5 May 2025 10:32:32 +0200 Subject: [PATCH 2/2] spotless --- .../DynamicInstrumentation.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/DynamicInstrumentation.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/DynamicInstrumentation.java index 2db3b0e7d3433..b8d7ea6cdd8cc 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/DynamicInstrumentation.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/DynamicInstrumentation.java @@ -16,7 +16,6 @@ import org.elasticsearch.entitlement.instrumentation.Instrumenter; import org.elasticsearch.entitlement.instrumentation.MethodKey; import org.elasticsearch.entitlement.instrumentation.Transformer; -import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement; import java.lang.instrument.Instrumentation; import java.lang.instrument.UnmodifiableClassException; @@ -94,8 +93,8 @@ InstrumentationService.InstrumentationInfo of(String methodName, Class... par * @param checkerInterface the interface to use to find methods to instrument and to use in the injected instrumentation code * @param verifyBytecode whether we should perform bytecode verification before and after instrumenting each method */ - static void initialize(Instrumentation inst, Class checkerInterface, boolean verifyBytecode) - throws ClassNotFoundException, NoSuchMethodException, UnmodifiableClassException { + static void initialize(Instrumentation inst, Class checkerInterface, boolean verifyBytecode) throws ClassNotFoundException, + NoSuchMethodException, UnmodifiableClassException { var checkMethods = getMethodsToInstrument(checkerInterface); var classesToTransform = checkMethods.keySet().stream().map(MethodKey::className).collect(Collectors.toSet()); @@ -120,23 +119,23 @@ static void initialize(Instrumentation inst, Class checkerInterface, boolean } } - private static Map getMethodsToInstrument(Class checkerInterface) - throws ClassNotFoundException, NoSuchMethodException { + private static Map getMethodsToInstrument(Class checkerInterface) throws ClassNotFoundException, + NoSuchMethodException { Map checkMethods = new HashMap<>(INSTRUMENTATION_SERVICE.lookupMethods(checkerInterface)); Stream.of( - fileSystemProviderChecks(), - fileStoreChecks(), - pathChecks(), - Stream.of( - INSTRUMENTATION_SERVICE.lookupImplementationMethod( - SelectorProvider.class, - "inheritedChannel", - SelectorProvider.provider().getClass(), - EntitlementChecker.class, - "checkSelectorProviderInheritedChannel" - ) + fileSystemProviderChecks(), + fileStoreChecks(), + pathChecks(), + Stream.of( + INSTRUMENTATION_SERVICE.lookupImplementationMethod( + SelectorProvider.class, + "inheritedChannel", + SelectorProvider.provider().getClass(), + EntitlementChecker.class, + "checkSelectorProviderInheritedChannel" ) ) + ) .flatMap(Function.identity()) .forEach(instrumentation -> checkMethods.put(instrumentation.targetMethod(), instrumentation.checkMethod()));