quarkus icon indicating copy to clipboard operation
quarkus copied to clipboard

Native executable cannot be built with signed Jars containing beans

Open sithmein opened this issue 1 year ago • 2 comments

Describe the bug

Consider a Maven dependency which contains bean classes (e.g. @ApplicationScoped) and which is signed. Then use this dependency and one of its beans in a Quarkus project. Quarkus will create proxy classes for this bean at compile time and put them into target/quarkus-app/quarkus/generated-bytecode.jar. The package of these generated classes is the same as the package of the signed bean. Now if you want to create a native executable this fails because the classloader during native compilation sees classes from the same package which are both signed (the original bean) and unsigned (the generated proxy classes). This result in a SecurityException and hence compilation fails.

Expected behavior

The native executable can be compiled.

Actual behavior

An error during native compilation such as

Error: Class initialization of io.quarkus.runner.ApplicationImpl failed. Use the option 

    '--initialize-at-run-time=io.quarkus.runner.ApplicationImpl'

 to explicitly request initialization of this class at run time.
com.oracle.svm.core.util.UserError$UserException: Class initialization of io.quarkus.runner.ApplicationImpl failed. Use the option 

    '--initialize-at-run-time=io.quarkus.runner.ApplicationImpl'

 to explicitly request initialization of this class at run time.
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.UserError.abort(UserError.java:85)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ClassInitializationSupport.ensureClassInitialized(ClassInitializationSupport.java:195)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.AllowAllHostedUsagesClassInitializationSupport.computeInitKindAndMaybeInitializeClass(AllowAllHostedUsagesClassInitializationSupport.java:191)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.AllowAllHostedUsagesClassInitializationSupport.computeInitKindAndMaybeInitializeClass(AllowAllHostedUsagesClassInitializationSupport.java:129)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ClassInitializationSupport.maybeInitializeAtBuildTime(ClassInitializationSupport.java:161)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ClassInitializationSupport.maybeInitializeAtBuildTime(ClassInitializationSupport.java:150)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.SVMHost.onTypeReachable(SVMHost.java:310)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisUniverse.onTypeReachable(AnalysisUniverse.java:699)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.lambda$new$0(AnalysisType.java:310)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.AnalysisFuture.ensureDone(AnalysisFuture.java:63)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.ensureOnTypeReachableTaskDone(AnalysisType.java:696)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.onReachable(AnalysisType.java:590)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.AtomicUtils.atomicSetAndRun(AtomicUtils.java:49)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.lambda$registerAsReachable$8(AnalysisType.java:562)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.forAllSuperTypes(AnalysisType.java:676)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.forAllSuperTypes(AnalysisType.java:659)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.forAllSuperTypes(AnalysisType.java:655)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.registerAsReachable(AnalysisType.java:562)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerClass(ReflectionDataBuilder.java:204)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.lambda$register$2(ReflectionDataBuilder.java:173)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.executeCommand(CompletionExecutor.java:187)
        at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.lambda$executeService$0(CompletionExecutor.java:171)
        at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)
Caused by: java.lang.ExceptionInInitializerError
        at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized0(Native Method)
        at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1160)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ClassInitializationSupport.ensureClassInitialized(ClassInitializationSupport.java:177)
        ... 28 more
Caused by: java.lang.RuntimeException: Failed to start quarkus
        at io.quarkus.runner.ApplicationImpl.<clinit>(Unknown Source)
        ... 31 more
Caused by: java.lang.SecurityException: class "org.foo.SomeBean_Bean"'s signer information does not match signer information of other classes in the same package
        at java.base/java.lang.ClassLoader.checkCerts(ClassLoader.java:1173)
        at java.base/java.lang.ClassLoader.preDefineClass(ClassLoader.java:917)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1025)
        at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageClassLoader.defineClass(NativeImageClassLoader.java:490)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageClassLoader.findClassViaClassPath(NativeImageClassLoader.java:442)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageClassLoader.loadClass(NativeImageClassLoader.java:629)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
        at io.quarkus.arc.setup.Default_ComponentsProvider.addBeans1(Unknown Source)
        at io.quarkus.arc.setup.Default_ComponentsProvider.getComponents(Unknown Source)
        at io.quarkus.arc.impl.ArcContainerImpl.<init>(ArcContainerImpl.java:128)
        at io.quarkus.arc.Arc.initialize(Arc.java:38)
        at io.quarkus.arc.runtime.ArcRecorder.initContainer(ArcRecorder.java:49)
        at io.quarkus.deployment.steps.ArcProcessor$initializeContainer1770303700.deploy_0(Unknown Source)
        at io.quarkus.deployment.steps.ArcProcessor$initializeContainer1770303700.deploy(Unknown Source)
        ... 32 more

How to Reproduce?

See https://github.com/sithmein/signature-issue-native-build and the instructions in the README.

Output of uname -a or ver

Linux crest 6.13.11-200.fc41.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Apr 10 19:02:09 UTC 2025 x86_64 GNU/Linux

Output of java -version

openjdk version "21.0.6" 2025-01-21

Mandrel or GraalVM version (if different from Java)

Mandrel-23.1.6.0-Final

Quarkus version or git rev

3.15.4

Build tool (ie. output of mvnw --version or gradlew --version)

Maven 3.9.8

Additional information

One way to solve this could be signing the generated Jars before passing them to the native build. However this only works if the library is "yours" i.e. the signing key is the same. It doesn't work for 3rd party libraries with beans. In such cases the signature information from all libs could be removed prior to starting the native build.

sithmein avatar Apr 23 '25 09:04 sithmein

/cc @Karm (native-image), @galderz (native-image), @zakkak (native-image)

quarkus-bot[bot] avatar Apr 23 '25 09:04 quarkus-bot[bot]

I have reproduced the issue locally. Looking into it

galderz avatar Apr 28 '25 08:04 galderz

We have a similar problem on referencing signed classes of azure sdk in a library. It was fixed in #40000 but stopped working again. : java.lang.SecurityException: class "com.azure.core.credential.CdiProducers_ProducerMethod_azureIdentity_RA0tqDmJjVLmlv8MJMyD4KvhkIE_ClientProxy"'s signer information does not match signer information of other classes in the same package at java.base/java.lang.ClassLoader.checkCerts(ClassLoader.java:1173) at java.base/java.lang.ClassLoader.preDefineClass(ClassLoader.java:917) at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1025) at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:524) at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:427) at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:421) at java.base/java.security.AccessController.doPrivileged(AccessController.java:714) at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:420) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)

The exception is thrown by Quarkus versions that previously worked too.

OoHenryoO avatar May 05 '25 06:05 OoHenryoO

Thanks @gastaldi for the fix!

galderz avatar May 14 '25 04:05 galderz