From 9b863be8bb09877b39a35547008e59968ed87fbe Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Fri, 25 Mar 2022 10:12:03 -0400 Subject: [PATCH 01/12] chore: relocate Netty Native Image configurations from java-core to gax --- dependencies.properties | 2 + gax-grpc/build.gradle | 4 +- .../google/nativeimage/GrpcNettyFeature.java | 136 +++++++++++++ gax/build.gradle | 4 +- .../api/gax/nativeimage/NativeImageUtils.java | 188 ++++++++++++++++++ 5 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java create mode 100644 gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java diff --git a/dependencies.properties b/dependencies.properties index 8a0b0d581..023bc5152 100644 --- a/dependencies.properties +++ b/dependencies.properties @@ -70,6 +70,8 @@ maven.com_google_http_client_google_http_client=com.google.http-client:google-ht maven.com_google_http_client_google_http_client_gson=com.google.http-client:google-http-client-gson:1.41.2 maven.org_codehaus_mojo_animal_sniffer_annotations=org.codehaus.mojo:animal-sniffer-annotations:1.18 maven.javax_annotation_javax_annotation_api=javax.annotation:javax.annotation-api:1.3.2 +maven.org_graalvm_nativeimage_svm=org.graalvm.nativeimage:svm:22.0.0.2 +maven.org_graalvm_sdk=org.graalvm.sdk:graal-sdk:22.0.0.2 # Testing maven artifacts maven.junit_junit=junit:junit:4.13.2 diff --git a/gax-grpc/build.gradle b/gax-grpc/build.gradle index 4886d4efe..984e5eb5c 100644 --- a/gax-grpc/build.gradle +++ b/gax-grpc/build.gradle @@ -22,7 +22,9 @@ dependencies { runtimeOnly libraries['maven.io_grpc_grpc_xds'] - compileOnly libraries['maven.com_google_auto_value_auto_value'] + compileOnly(libraries['maven.com_google_auto_value_auto_value'], + libraries['maven.org_graalvm_sdk'], + libraries['maven.org_graalvm_nativeimage_svm']) testImplementation( project(':gax').sourceSets.test.output, libraries['maven.junit_junit'], diff --git a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java b/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java new file mode 100644 index 000000000..682ca1ec5 --- /dev/null +++ b/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java @@ -0,0 +1,136 @@ +/* + * Copyright 2022 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.nativeimage; + +import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForReflection; +import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassHierarchyForReflection; +import static com.google.api.gax.nativeimage.NativeImageUtils.registerForReflectiveInstantiation; +import static com.google.api.gax.nativeimage.NativeImageUtils.registerForUnsafeFieldAccess; + +import com.oracle.svm.core.annotate.AutomaticFeature; +import org.graalvm.nativeimage.hosted.Feature; + +/** Configures Native Image settings for the grpc-netty-shaded dependency. */ +@AutomaticFeature +final class GrpcNettyFeature implements Feature { + + private static final String GRPC_NETTY_SHADED_CLASS = + "io.grpc.netty.shaded.io.grpc.netty.NettyServer"; + + private static final String GOOGLE_AUTH_CLASS = + "com.google.auth.oauth2.ServiceAccountCredentials"; + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + loadGoogleAuthClasses(access); + loadGrpcNettyClasses(access); + loadMiscClasses(access); + } + + private static void loadGoogleAuthClasses(BeforeAnalysisAccess access) { + // For com.google.auth:google-auth-library-oauth2-http + Class authClass = access.findClassByName(GOOGLE_AUTH_CLASS); + if (authClass != null) { + registerClassHierarchyForReflection( + access, "com.google.auth.oauth2.ServiceAccountCredentials"); + registerClassHierarchyForReflection( + access, "com.google.auth.oauth2.ServiceAccountJwtAccessCredentials"); + } + } + + private static void loadGrpcNettyClasses(BeforeAnalysisAccess access) { + // For io.grpc:grpc-netty-shaded + Class nettyShadedClass = access.findClassByName(GRPC_NETTY_SHADED_CLASS); + if (nettyShadedClass != null) { + // Misc. classes used by grpc-netty-shaded + registerForReflectiveInstantiation( + access, "io.grpc.netty.shaded.io.netty.channel.socket.nio.NioSocketChannel"); + registerClassForReflection( + access, "io.grpc.netty.shaded.io.netty.util.internal.NativeLibraryUtil"); + registerClassForReflection(access, "io.grpc.netty.shaded.io.netty.util.ReferenceCountUtil"); + registerClassForReflection( + access, "io.grpc.netty.shaded.io.netty.buffer.AbstractByteBufAllocator"); + + // Epoll Libraries + registerClassForReflection(access, "io.grpc.netty.shaded.io.netty.channel.epoll.Epoll"); + registerClassForReflection( + access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollChannelOption"); + registerClassForReflection( + access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup"); + registerForReflectiveInstantiation( + access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerSocketChannel"); + registerForReflectiveInstantiation( + access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollSocketChannel"); + + // Unsafe field accesses + registerForUnsafeFieldAccess( + access, + "io.grpc.netty.shaded.io.netty.util.internal.shaded." + + "org.jctools.queues.MpscArrayQueueProducerIndexField", + "producerIndex"); + registerForUnsafeFieldAccess( + access, + "io.grpc.netty.shaded.io.netty.util.internal.shaded." + + "org.jctools.queues.MpscArrayQueueProducerLimitField", + "producerLimit"); + registerForUnsafeFieldAccess( + access, + "io.grpc.netty.shaded.io.netty.util.internal.shaded." + + "org.jctools.queues.MpscArrayQueueConsumerIndexField", + "consumerIndex"); + registerForUnsafeFieldAccess( + access, + "io.grpc.netty.shaded.io.netty.util.internal.shaded." + + "org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields", + "producerIndex"); + registerForUnsafeFieldAccess( + access, + "io.grpc.netty.shaded.io.netty.util.internal.shaded." + + "org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields", + "producerLimit"); + registerForUnsafeFieldAccess( + access, + "io.grpc.netty.shaded.io.netty.util.internal.shaded." + + "org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields", + "consumerIndex"); + } + } + + /** Miscellaneous classes that need to be registered coming from various JARs. */ + private static void loadMiscClasses(BeforeAnalysisAccess access) { + registerClassHierarchyForReflection(access, "com.google.protobuf.DescriptorProtos"); + registerClassForReflection(access, "com.google.api.FieldBehavior"); + + registerForUnsafeFieldAccess(access, "javax.net.ssl.SSLContext", "contextSpi"); + registerClassForReflection(access, "java.lang.management.ManagementFactory"); + registerClassForReflection(access, "java.lang.management.RuntimeMXBean"); + } +} diff --git a/gax/build.gradle b/gax/build.gradle index f85810a6f..cbcaffdb3 100644 --- a/gax/build.gradle +++ b/gax/build.gradle @@ -13,7 +13,9 @@ dependencies { libraries['maven.com_google_guava_guava'], libraries['maven.io_opencensus_opencensus_api']) - compileOnly libraries['maven.com_google_auto_value_auto_value'] + compileOnly(libraries['maven.com_google_auto_value_auto_value'], + libraries['maven.org_graalvm_sdk'], + libraries['maven.org_graalvm_nativeimage_svm']) testImplementation(libraries['maven.junit_junit'], libraries['maven.org_mockito_mockito_core'], diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java new file mode 100644 index 000000000..c3c96cf4b --- /dev/null +++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -0,0 +1,188 @@ +/* + * Copyright 2022 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.nativeimage; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.JarURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Logger; +import org.graalvm.nativeimage.hosted.Feature.FeatureAccess; +import org.graalvm.nativeimage.hosted.RuntimeReflection; + +/** Internal class offering helper methods for registering methods/classes for reflection. */ +public class NativeImageUtils { + + private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName()); + + /** Returns the method of a class or fails if it is not present. */ + public static Method getMethodOrFail(Class clazz, String methodName, Class... params) { + try { + return clazz.getDeclaredMethod(methodName, params); + } catch (NoSuchMethodException e) { + throw new RuntimeException( + "Failed to find method " + methodName + " for class " + clazz.getName(), e); + } + } + + /** Registers a class for reflective construction via its default constructor. */ + public static void registerForReflectiveInstantiation(FeatureAccess access, String className) { + Class clazz = access.findClassByName(className); + if (clazz != null) { + RuntimeReflection.register(clazz); + RuntimeReflection.registerForReflectiveInstantiation(clazz); + } else { + LOGGER.warning( + "Failed to find " + className + " on the classpath for reflective instantiation."); + } + } + + /** Registers all constructors of a class for reflection. */ + public static void registerConstructorsForReflection(FeatureAccess access, String name) { + Class clazz = access.findClassByName(name); + if (clazz != null) { + RuntimeReflection.register(clazz); + RuntimeReflection.register(clazz.getDeclaredConstructors()); + } else { + LOGGER.warning("Failed to find " + name + " on the classpath for reflection."); + } + } + + /** Registers an entire class for reflection use. */ + public static void registerClassForReflection(FeatureAccess access, String name) { + Class clazz = access.findClassByName(name); + if (clazz != null) { + RuntimeReflection.register(clazz); + RuntimeReflection.register(clazz.getDeclaredConstructors()); + RuntimeReflection.register(clazz.getDeclaredFields()); + RuntimeReflection.register(clazz.getDeclaredMethods()); + } else { + LOGGER.warning("Failed to find " + name + " on the classpath for reflection."); + } + } + + /** + * Registers the transitive class hierarchy of the provided {@code className} for reflection. + * + *

The transitive class hierarchy contains the class itself and its transitive set of + * *non-private* nested subclasses. + */ + public static void registerClassHierarchyForReflection(FeatureAccess access, String className) { + Class clazz = access.findClassByName(className); + if (clazz != null) { + registerClassForReflection(access, className); + for (Class nestedClass : clazz.getDeclaredClasses()) { + if (!Modifier.isPrivate(nestedClass.getModifiers())) { + registerClassHierarchyForReflection(access, nestedClass.getName()); + } + } + } else { + LOGGER.warning("Failed to find " + className + " on the classpath for reflection."); + } + } + + /** Registers a class for unsafe reflective field access. */ + public static void registerForUnsafeFieldAccess( + FeatureAccess access, String className, String... fields) { + Class clazz = access.findClassByName(className); + if (clazz != null) { + RuntimeReflection.register(clazz); + for (String fieldName : fields) { + try { + RuntimeReflection.register(clazz.getDeclaredField(fieldName)); + } catch (NoSuchFieldException ex) { + LOGGER.warning("Failed to register field " + fieldName + " for class " + className); + LOGGER.warning(ex.getMessage()); + } + } + } else { + LOGGER.warning( + "Failed to find " + + className + + " on the classpath for unsafe fields access registration."); + } + } + + /** Registers all the classes under the specified package for reflection. */ + public static void registerPackageForReflection(FeatureAccess access, String packageName) { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + try { + String path = packageName.replace('.', '/'); + + Enumeration resources = classLoader.getResources(path); + while (resources.hasMoreElements()) { + URL url = resources.nextElement(); + + URLConnection connection = url.openConnection(); + if (connection instanceof JarURLConnection) { + List classes = findClassesInJar((JarURLConnection) connection, packageName); + for (String className : classes) { + registerClassHierarchyForReflection(access, className); + } + } + } + } catch (IOException e) { + throw new RuntimeException("Failed to load classes under package name.", e); + } + } + + private static List findClassesInJar(JarURLConnection urlConnection, String packageName) + throws IOException { + + List result = new ArrayList<>(); + + final JarFile jarFile = urlConnection.getJarFile(); + final Enumeration entries = jarFile.entries(); + + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + + if (entryName.endsWith(".class")) { + String javaClassName = entryName.replace(".class", "").replace('/', '.'); + + if (javaClassName.startsWith(packageName)) { + result.add(javaClassName); + } + } + } + + return result; + } +} From 4a148fea9f1b2d97d9da1e415613fe5a0f401b16 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Fri, 25 Mar 2022 13:53:14 -0400 Subject: [PATCH 02/12] address sonar suggestions --- .../google/nativeimage/GrpcNettyFeature.java | 16 ++++++------ .../api/gax/nativeimage/NativeImageUtils.java | 25 ++++++++++--------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java b/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java index 682ca1ec5..58e730c55 100644 --- a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java +++ b/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java @@ -48,6 +48,8 @@ final class GrpcNettyFeature implements Feature { private static final String GOOGLE_AUTH_CLASS = "com.google.auth.oauth2.ServiceAccountCredentials"; + private static final String NETTY_SHADED_PACKAGE = "io.grpc.netty.shaded.io.netty.util.internal.shaded."; + @Override public void beforeAnalysis(BeforeAnalysisAccess access) { loadGoogleAuthClasses(access); @@ -60,7 +62,7 @@ private static void loadGoogleAuthClasses(BeforeAnalysisAccess access) { Class authClass = access.findClassByName(GOOGLE_AUTH_CLASS); if (authClass != null) { registerClassHierarchyForReflection( - access, "com.google.auth.oauth2.ServiceAccountCredentials"); + access, GOOGLE_AUTH_CLASS); registerClassHierarchyForReflection( access, "com.google.auth.oauth2.ServiceAccountJwtAccessCredentials"); } @@ -93,32 +95,32 @@ private static void loadGrpcNettyClasses(BeforeAnalysisAccess access) { // Unsafe field accesses registerForUnsafeFieldAccess( access, - "io.grpc.netty.shaded.io.netty.util.internal.shaded." + NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueProducerIndexField", "producerIndex"); registerForUnsafeFieldAccess( access, - "io.grpc.netty.shaded.io.netty.util.internal.shaded." + NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueProducerLimitField", "producerLimit"); registerForUnsafeFieldAccess( access, - "io.grpc.netty.shaded.io.netty.util.internal.shaded." + NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueConsumerIndexField", "consumerIndex"); registerForUnsafeFieldAccess( access, - "io.grpc.netty.shaded.io.netty.util.internal.shaded." + NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields", "producerIndex"); registerForUnsafeFieldAccess( access, - "io.grpc.netty.shaded.io.netty.util.internal.shaded." + NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields", "producerLimit"); registerForUnsafeFieldAccess( access, - "io.grpc.netty.shaded.io.netty.util.internal.shaded." + NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields", "consumerIndex"); } diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index c3c96cf4b..d23eaebd1 100644 --- a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -41,6 +41,7 @@ import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.logging.Level; import java.util.logging.Logger; import org.graalvm.nativeimage.hosted.Feature.FeatureAccess; import org.graalvm.nativeimage.hosted.RuntimeReflection; @@ -48,15 +49,18 @@ /** Internal class offering helper methods for registering methods/classes for reflection. */ public class NativeImageUtils { + private NativeImageUtils(){} + private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName()); + private static final String CLASS_REFLECTION_ERROR_MESSAGE = "Failed to find {0} on the classpath for reflection."; /** Returns the method of a class or fails if it is not present. */ public static Method getMethodOrFail(Class clazz, String methodName, Class... params) { try { return clazz.getDeclaredMethod(methodName, params); } catch (NoSuchMethodException e) { - throw new RuntimeException( - "Failed to find method " + methodName + " for class " + clazz.getName(), e); + throw new IllegalStateException( + String.format("Failed to find method %s for class %s", methodName, clazz.getName()), e); } } @@ -67,8 +71,7 @@ public static void registerForReflectiveInstantiation(FeatureAccess access, Stri RuntimeReflection.register(clazz); RuntimeReflection.registerForReflectiveInstantiation(clazz); } else { - LOGGER.warning( - "Failed to find " + className + " on the classpath for reflective instantiation."); + LOGGER.log(Level.WARNING, "Failed to find {0} on the classpath for reflective instantiation.",className); } } @@ -79,7 +82,7 @@ public static void registerConstructorsForReflection(FeatureAccess access, Strin RuntimeReflection.register(clazz); RuntimeReflection.register(clazz.getDeclaredConstructors()); } else { - LOGGER.warning("Failed to find " + name + " on the classpath for reflection."); + LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name); } } @@ -92,7 +95,7 @@ public static void registerClassForReflection(FeatureAccess access, String name) RuntimeReflection.register(clazz.getDeclaredFields()); RuntimeReflection.register(clazz.getDeclaredMethods()); } else { - LOGGER.warning("Failed to find " + name + " on the classpath for reflection."); + LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name); } } @@ -112,7 +115,7 @@ public static void registerClassHierarchyForReflection(FeatureAccess access, Str } } } else { - LOGGER.warning("Failed to find " + className + " on the classpath for reflection."); + LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, className); } } @@ -131,10 +134,8 @@ public static void registerForUnsafeFieldAccess( } } } else { - LOGGER.warning( - "Failed to find " - + className - + " on the classpath for unsafe fields access registration."); + LOGGER.log(Level.WARNING, + "Failed to find {0} on the classpath for unsafe fields access registration.", className); } } @@ -158,7 +159,7 @@ public static void registerPackageForReflection(FeatureAccess access, String pac } } } catch (IOException e) { - throw new RuntimeException("Failed to load classes under package name.", e); + throw new IllegalStateException("Failed to load classes under package name.", e); } } From dd9231b47db758b82f955e6fb40b455ac2878477 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Fri, 25 Mar 2022 17:20:48 -0400 Subject: [PATCH 03/12] add graal dependencies to bazel script; formatting --- gax/BUILD.bazel | 2 + .../api/gax/nativeimage/NativeImageUtils.java | 37 +++++++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/gax/BUILD.bazel b/gax/BUILD.bazel index b9dd9a067..f35f3fc99 100644 --- a/gax/BUILD.bazel +++ b/gax/BUILD.bazel @@ -24,6 +24,8 @@ _COMPILE_DEPS = [ "@com_google_code_gson_gson//jar", "@com_google_guava_failureaccess//jar", "@javax_annotation_javax_annotation_api//jar", + "@org_graalvm_nativeimage_svm//jar", + "@org_graalvm_sdk//jar" ] _TEST_COMPILE_DEPS = [ diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index d23eaebd1..aa3b48f79 100644 --- a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -46,15 +46,19 @@ import org.graalvm.nativeimage.hosted.Feature.FeatureAccess; import org.graalvm.nativeimage.hosted.RuntimeReflection; -/** Internal class offering helper methods for registering methods/classes for reflection. */ +/** + * Internal class offering helper methods for registering methods/classes for reflection. + */ public class NativeImageUtils { - private NativeImageUtils(){} - private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName()); - private static final String CLASS_REFLECTION_ERROR_MESSAGE = "Failed to find {0} on the classpath for reflection."; + private static final String CLASS_REFLECTION_ERROR_MESSAGE = "Failed to find {0} on the classpath for reflection."; + private NativeImageUtils() { + } - /** Returns the method of a class or fails if it is not present. */ + /** + * Returns the method of a class or fails if it is not present. + */ public static Method getMethodOrFail(Class clazz, String methodName, Class... params) { try { return clazz.getDeclaredMethod(methodName, params); @@ -64,18 +68,23 @@ public static Method getMethodOrFail(Class clazz, String methodName, Class } } - /** Registers a class for reflective construction via its default constructor. */ + /** + * Registers a class for reflective construction via its default constructor. + */ public static void registerForReflectiveInstantiation(FeatureAccess access, String className) { Class clazz = access.findClassByName(className); if (clazz != null) { RuntimeReflection.register(clazz); RuntimeReflection.registerForReflectiveInstantiation(clazz); } else { - LOGGER.log(Level.WARNING, "Failed to find {0} on the classpath for reflective instantiation.",className); + LOGGER.log(Level.WARNING, "Failed to find {0} on the classpath for reflective instantiation.", + className); } } - /** Registers all constructors of a class for reflection. */ + /** + * Registers all constructors of a class for reflection. + */ public static void registerConstructorsForReflection(FeatureAccess access, String name) { Class clazz = access.findClassByName(name); if (clazz != null) { @@ -86,7 +95,9 @@ public static void registerConstructorsForReflection(FeatureAccess access, Strin } } - /** Registers an entire class for reflection use. */ + /** + * Registers an entire class for reflection use. + */ public static void registerClassForReflection(FeatureAccess access, String name) { Class clazz = access.findClassByName(name); if (clazz != null) { @@ -119,7 +130,9 @@ public static void registerClassHierarchyForReflection(FeatureAccess access, Str } } - /** Registers a class for unsafe reflective field access. */ + /** + * Registers a class for unsafe reflective field access. + */ public static void registerForUnsafeFieldAccess( FeatureAccess access, String className, String... fields) { Class clazz = access.findClassByName(className); @@ -139,7 +152,9 @@ public static void registerForUnsafeFieldAccess( } } - /** Registers all the classes under the specified package for reflection. */ + /** + * Registers all the classes under the specified package for reflection. + */ public static void registerPackageForReflection(FeatureAccess access, String packageName) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); From d435e788f88452b7d5a60f26f0dfa50a648a9810 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Fri, 25 Mar 2022 17:31:12 -0400 Subject: [PATCH 04/12] fix formatting --- .../api/gax/nativeimage/NativeImageUtils.java | 45 ++++++++----------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index aa3b48f79..97ee8134c 100644 --- a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -46,19 +46,16 @@ import org.graalvm.nativeimage.hosted.Feature.FeatureAccess; import org.graalvm.nativeimage.hosted.RuntimeReflection; -/** - * Internal class offering helper methods for registering methods/classes for reflection. - */ +/** Internal class offering helper methods for registering methods/classes for reflection. */ public class NativeImageUtils { private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName()); - private static final String CLASS_REFLECTION_ERROR_MESSAGE = "Failed to find {0} on the classpath for reflection."; - private NativeImageUtils() { - } + private static final String CLASS_REFLECTION_ERROR_MESSAGE = + "Failed to find {0} on the classpath for reflection."; - /** - * Returns the method of a class or fails if it is not present. - */ + private NativeImageUtils() {} + + /** Returns the method of a class or fails if it is not present. */ public static Method getMethodOrFail(Class clazz, String methodName, Class... params) { try { return clazz.getDeclaredMethod(methodName, params); @@ -68,23 +65,21 @@ public static Method getMethodOrFail(Class clazz, String methodName, Class } } - /** - * Registers a class for reflective construction via its default constructor. - */ + /** Registers a class for reflective construction via its default constructor. */ public static void registerForReflectiveInstantiation(FeatureAccess access, String className) { Class clazz = access.findClassByName(className); if (clazz != null) { RuntimeReflection.register(clazz); RuntimeReflection.registerForReflectiveInstantiation(clazz); } else { - LOGGER.log(Level.WARNING, "Failed to find {0} on the classpath for reflective instantiation.", + LOGGER.log( + Level.WARNING, + "Failed to find {0} on the classpath for reflective instantiation.", className); } } - /** - * Registers all constructors of a class for reflection. - */ + /** Registers all constructors of a class for reflection. */ public static void registerConstructorsForReflection(FeatureAccess access, String name) { Class clazz = access.findClassByName(name); if (clazz != null) { @@ -95,9 +90,7 @@ public static void registerConstructorsForReflection(FeatureAccess access, Strin } } - /** - * Registers an entire class for reflection use. - */ + /** Registers an entire class for reflection use. */ public static void registerClassForReflection(FeatureAccess access, String name) { Class clazz = access.findClassByName(name); if (clazz != null) { @@ -130,9 +123,7 @@ public static void registerClassHierarchyForReflection(FeatureAccess access, Str } } - /** - * Registers a class for unsafe reflective field access. - */ + /** Registers a class for unsafe reflective field access. */ public static void registerForUnsafeFieldAccess( FeatureAccess access, String className, String... fields) { Class clazz = access.findClassByName(className); @@ -147,14 +138,14 @@ public static void registerForUnsafeFieldAccess( } } } else { - LOGGER.log(Level.WARNING, - "Failed to find {0} on the classpath for unsafe fields access registration.", className); + LOGGER.log( + Level.WARNING, + "Failed to find {0} on the classpath for unsafe fields access registration.", + className); } } - /** - * Registers all the classes under the specified package for reflection. - */ + /** Registers all the classes under the specified package for reflection. */ public static void registerPackageForReflection(FeatureAccess access, String packageName) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); From 07dec6b93499d3a9816b316e03d99fcb7cf220f0 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Fri, 25 Mar 2022 17:37:05 -0400 Subject: [PATCH 05/12] fix formatting for GrpcNettyFeature --- .../google/nativeimage/GrpcNettyFeature.java | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java b/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java index 58e730c55..9e15e9637 100644 --- a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java +++ b/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java @@ -48,21 +48,14 @@ final class GrpcNettyFeature implements Feature { private static final String GOOGLE_AUTH_CLASS = "com.google.auth.oauth2.ServiceAccountCredentials"; - private static final String NETTY_SHADED_PACKAGE = "io.grpc.netty.shaded.io.netty.util.internal.shaded."; - - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - loadGoogleAuthClasses(access); - loadGrpcNettyClasses(access); - loadMiscClasses(access); - } + private static final String NETTY_SHADED_PACKAGE = + "io.grpc.netty.shaded.io.netty.util.internal.shaded."; private static void loadGoogleAuthClasses(BeforeAnalysisAccess access) { // For com.google.auth:google-auth-library-oauth2-http Class authClass = access.findClassByName(GOOGLE_AUTH_CLASS); if (authClass != null) { - registerClassHierarchyForReflection( - access, GOOGLE_AUTH_CLASS); + registerClassHierarchyForReflection(access, GOOGLE_AUTH_CLASS); registerClassHierarchyForReflection( access, "com.google.auth.oauth2.ServiceAccountJwtAccessCredentials"); } @@ -95,33 +88,27 @@ private static void loadGrpcNettyClasses(BeforeAnalysisAccess access) { // Unsafe field accesses registerForUnsafeFieldAccess( access, - NETTY_SHADED_PACKAGE - + "org.jctools.queues.MpscArrayQueueProducerIndexField", + NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueProducerIndexField", "producerIndex"); registerForUnsafeFieldAccess( access, - NETTY_SHADED_PACKAGE - + "org.jctools.queues.MpscArrayQueueProducerLimitField", + NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueProducerLimitField", "producerLimit"); registerForUnsafeFieldAccess( access, - NETTY_SHADED_PACKAGE - + "org.jctools.queues.MpscArrayQueueConsumerIndexField", + NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueConsumerIndexField", "consumerIndex"); registerForUnsafeFieldAccess( access, - NETTY_SHADED_PACKAGE - + "org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields", + NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields", "producerIndex"); registerForUnsafeFieldAccess( access, - NETTY_SHADED_PACKAGE - + "org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields", + NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields", "producerLimit"); registerForUnsafeFieldAccess( access, - NETTY_SHADED_PACKAGE - + "org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields", + NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields", "consumerIndex"); } } @@ -135,4 +122,11 @@ private static void loadMiscClasses(BeforeAnalysisAccess access) { registerClassForReflection(access, "java.lang.management.ManagementFactory"); registerClassForReflection(access, "java.lang.management.RuntimeMXBean"); } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + loadGoogleAuthClasses(access); + loadGrpcNettyClasses(access); + loadMiscClasses(access); + } } From af024f2b7032b893251b50f76a9c5cbe3ba1faca Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Fri, 25 Mar 2022 17:39:48 -0400 Subject: [PATCH 06/12] keep public method at the top --- .../com/google/nativeimage/GrpcNettyFeature.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java b/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java index 9e15e9637..415e90f18 100644 --- a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java +++ b/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java @@ -51,6 +51,13 @@ final class GrpcNettyFeature implements Feature { private static final String NETTY_SHADED_PACKAGE = "io.grpc.netty.shaded.io.netty.util.internal.shaded."; + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + loadGoogleAuthClasses(access); + loadGrpcNettyClasses(access); + loadMiscClasses(access); + } + private static void loadGoogleAuthClasses(BeforeAnalysisAccess access) { // For com.google.auth:google-auth-library-oauth2-http Class authClass = access.findClassByName(GOOGLE_AUTH_CLASS); @@ -122,11 +129,4 @@ private static void loadMiscClasses(BeforeAnalysisAccess access) { registerClassForReflection(access, "java.lang.management.ManagementFactory"); registerClassForReflection(access, "java.lang.management.RuntimeMXBean"); } - - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - loadGoogleAuthClasses(access); - loadGrpcNettyClasses(access); - loadMiscClasses(access); - } } From bc7aa7e56b5f6d98e70da08f11f20f9c6d692cb6 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Fri, 25 Mar 2022 17:50:40 -0400 Subject: [PATCH 07/12] add graal deps to bazel gax-grpc --- gax-grpc/BUILD.bazel | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gax-grpc/BUILD.bazel b/gax-grpc/BUILD.bazel index 3a177f4ab..5ae856c4f 100644 --- a/gax-grpc/BUILD.bazel +++ b/gax-grpc/BUILD.bazel @@ -31,6 +31,8 @@ _COMPILE_DEPS = [ "@io_netty_netty_tcnative_boringssl_static//jar", "@javax_annotation_javax_annotation_api//jar", "//gax:gax", + "@org_graalvm_nativeimage_svm//jar", + "@org_graalvm_sdk//jar" ] _TEST_COMPILE_DEPS = [ From 88dac1b1790b976d789bd04a577fa08cf9d2c1b4 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Wed, 30 Mar 2022 16:56:33 -0400 Subject: [PATCH 08/12] address security suggestion by sonar --- .../google/api/gax/nativeimage/NativeImageUtils.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index 97ee8134c..f1dc8f413 100644 --- a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -52,6 +52,8 @@ public class NativeImageUtils { private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName()); private static final String CLASS_REFLECTION_ERROR_MESSAGE = "Failed to find {0} on the classpath for reflection."; + + private static final int THRESHOLD_ENTRIES = 10000; private NativeImageUtils() {} @@ -173,12 +175,19 @@ private static List findClassesInJar(JarURLConnection urlConnection, Str throws IOException { List result = new ArrayList<>(); + int totalEntries = 0; final JarFile jarFile = urlConnection.getJarFile(); final Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); + + totalEntries++; + if (totalEntries > THRESHOLD_ENTRIES) { + throw new IllegalStateException("Zip file contains too many files: " + totalEntries); + } + String entryName = entry.getName(); if (entryName.endsWith(".class")) { @@ -189,7 +198,6 @@ private static List findClassesInJar(JarURLConnection urlConnection, Str } } } - return result; } } From 646cc5475ca9fd6bcb47baedb508cede81f904e9 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Wed, 30 Mar 2022 17:04:25 -0400 Subject: [PATCH 09/12] formatting --- .../java/com/google/api/gax/nativeimage/NativeImageUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index f1dc8f413..970685b19 100644 --- a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -52,7 +52,7 @@ public class NativeImageUtils { private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName()); private static final String CLASS_REFLECTION_ERROR_MESSAGE = "Failed to find {0} on the classpath for reflection."; - + private static final int THRESHOLD_ENTRIES = 10000; private NativeImageUtils() {} From 21ed79a97abd21404db4cc2c8438a2f2070e7b82 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Wed, 30 Mar 2022 20:06:02 -0400 Subject: [PATCH 10/12] add more checks to verify JAR integrity --- .../api/gax/nativeimage/NativeImageUtils.java | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index 970685b19..f4bd37fd6 100644 --- a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -30,7 +30,9 @@ package com.google.api.gax.nativeimage; +import java.io.BufferedInputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.JarURLConnection; @@ -53,7 +55,11 @@ public class NativeImageUtils { private static final String CLASS_REFLECTION_ERROR_MESSAGE = "Failed to find {0} on the classpath for reflection."; - private static final int THRESHOLD_ENTRIES = 10000; + // 1 GB + private static final int MAX_JAR_SIZE = 1000000000; + + private static final int MAX_ENTRIES = 10000; + private static final int MAX_RATIO = 10; private NativeImageUtils() {} @@ -175,21 +181,18 @@ private static List findClassesInJar(JarURLConnection urlConnection, Str throws IOException { List result = new ArrayList<>(); - int totalEntries = 0; - final JarFile jarFile = urlConnection.getJarFile(); - final Enumeration entries = jarFile.entries(); + int totalEntries = 0; + int totalArchiveSize = 0; + final Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); - + InputStream inputStream = new BufferedInputStream(jarFile.getInputStream(entry)); totalEntries++; - if (totalEntries > THRESHOLD_ENTRIES) { - throw new IllegalStateException("Zip file contains too many files: " + totalEntries); - } + verifyJarIntegrity(totalEntries, totalArchiveSize, inputStream, entry); String entryName = entry.getName(); - if (entryName.endsWith(".class")) { String javaClassName = entryName.replace(".class", "").replace('/', '.'); @@ -200,4 +203,31 @@ private static List findClassesInJar(JarURLConnection urlConnection, Str } return result; } + + private static void verifyJarIntegrity( + int totalEntries, int totalArchiveSize, InputStream inputStream, JarEntry entry) + throws IOException { + // Compare compressed and uncompressed size of the Jar entry file. If the + // ratio is high (>10) then there is a possibility of a zip bomb attack. + byte[] buffer = new byte[2048]; + int totalEntrySize = 0; + int bytesRead = inputStream.read(buffer); + if (bytesRead > 0) { + totalEntrySize += bytesRead; + totalArchiveSize += bytesRead; + double compressionRatio = (double) totalEntrySize / entry.getCompressedSize(); + if (compressionRatio > MAX_RATIO) { + throw new IllegalStateException( + "Ratio of uncompressed and compressed of JAR entry is too big."); + } + } + + if (totalArchiveSize > MAX_JAR_SIZE) { + throw new IllegalStateException( + "The total uncompressed size (in bytes) of the JAR file is too big: " + totalArchiveSize); + } + if (totalEntries > MAX_ENTRIES) { + throw new IllegalStateException("Zip file contains too many files: " + totalEntries); + } + } } From c15a5c4c724b4cea9daa25959c3ab3caa787c583 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Thu, 31 Mar 2022 12:23:56 -0400 Subject: [PATCH 11/12] remove unused method; add InternalApi annotation --- .../api/gax/nativeimage/NativeImageUtils.java | 97 +------------------ 1 file changed, 2 insertions(+), 95 deletions(-) diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index f4bd37fd6..603d26e3c 100644 --- a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -30,37 +30,22 @@ package com.google.api.gax.nativeimage; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; +import com.google.api.core.InternalApi; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.net.JarURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import java.util.logging.Level; import java.util.logging.Logger; import org.graalvm.nativeimage.hosted.Feature.FeatureAccess; import org.graalvm.nativeimage.hosted.RuntimeReflection; /** Internal class offering helper methods for registering methods/classes for reflection. */ +@InternalApi public class NativeImageUtils { private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName()); private static final String CLASS_REFLECTION_ERROR_MESSAGE = "Failed to find {0} on the classpath for reflection."; - // 1 GB - private static final int MAX_JAR_SIZE = 1000000000; - - private static final int MAX_ENTRIES = 10000; - private static final int MAX_RATIO = 10; - private NativeImageUtils() {} /** Returns the method of a class or fails if it is not present. */ @@ -152,82 +137,4 @@ public static void registerForUnsafeFieldAccess( className); } } - - /** Registers all the classes under the specified package for reflection. */ - public static void registerPackageForReflection(FeatureAccess access, String packageName) { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - - try { - String path = packageName.replace('.', '/'); - - Enumeration resources = classLoader.getResources(path); - while (resources.hasMoreElements()) { - URL url = resources.nextElement(); - - URLConnection connection = url.openConnection(); - if (connection instanceof JarURLConnection) { - List classes = findClassesInJar((JarURLConnection) connection, packageName); - for (String className : classes) { - registerClassHierarchyForReflection(access, className); - } - } - } - } catch (IOException e) { - throw new IllegalStateException("Failed to load classes under package name.", e); - } - } - - private static List findClassesInJar(JarURLConnection urlConnection, String packageName) - throws IOException { - - List result = new ArrayList<>(); - final JarFile jarFile = urlConnection.getJarFile(); - - int totalEntries = 0; - int totalArchiveSize = 0; - final Enumeration entries = jarFile.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - InputStream inputStream = new BufferedInputStream(jarFile.getInputStream(entry)); - totalEntries++; - verifyJarIntegrity(totalEntries, totalArchiveSize, inputStream, entry); - - String entryName = entry.getName(); - if (entryName.endsWith(".class")) { - String javaClassName = entryName.replace(".class", "").replace('/', '.'); - - if (javaClassName.startsWith(packageName)) { - result.add(javaClassName); - } - } - } - return result; - } - - private static void verifyJarIntegrity( - int totalEntries, int totalArchiveSize, InputStream inputStream, JarEntry entry) - throws IOException { - // Compare compressed and uncompressed size of the Jar entry file. If the - // ratio is high (>10) then there is a possibility of a zip bomb attack. - byte[] buffer = new byte[2048]; - int totalEntrySize = 0; - int bytesRead = inputStream.read(buffer); - if (bytesRead > 0) { - totalEntrySize += bytesRead; - totalArchiveSize += bytesRead; - double compressionRatio = (double) totalEntrySize / entry.getCompressedSize(); - if (compressionRatio > MAX_RATIO) { - throw new IllegalStateException( - "Ratio of uncompressed and compressed of JAR entry is too big."); - } - } - - if (totalArchiveSize > MAX_JAR_SIZE) { - throw new IllegalStateException( - "The total uncompressed size (in bytes) of the JAR file is too big: " + totalArchiveSize); - } - if (totalEntries > MAX_ENTRIES) { - throw new IllegalStateException("Zip file contains too many files: " + totalEntries); - } - } } From 10786c181a905a1f612a286e415833d904d80906 Mon Sep 17 00:00:00 2001 From: Mridula Peddada Date: Thu, 31 Mar 2022 14:02:13 -0400 Subject: [PATCH 12/12] move file to com.google.api.gax.grpc.nativeimage --- .../google/{ => api/gax/grpc}/nativeimage/GrpcNettyFeature.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename gax-grpc/src/main/java/com/google/{ => api/gax/grpc}/nativeimage/GrpcNettyFeature.java (99%) diff --git a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java similarity index 99% rename from gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java rename to gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java index 415e90f18..1e1167e09 100644 --- a/gax-grpc/src/main/java/com/google/nativeimage/GrpcNettyFeature.java +++ b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java @@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.google.nativeimage; +package com.google.api.gax.grpc.nativeimage; import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForReflection; import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassHierarchyForReflection;