Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

removal of --enable-all-security-services adds 10 mb extra classes #3422

Closed
maxandersen opened this issue May 20, 2021 · 8 comments
Closed
Assignees

Comments

@maxandersen
Copy link

maxandersen commented May 20, 2021

Describe the issue
in #3258 --enable-all-security-services was removed and now a whole slew of additional security classes and ciphers are added that was not added before. This causes the image size for a Quarkus app to have at least 10 mb of additional content which is not necessary.

Here are the diff between helloworlds with zero changes, only diff is using graalvm 21.0 vs 21.1:

29517440 May 18 14:54 helloworld-21.0-java11
40909752 May 18 14:45 helloworld-21.1-java11 

I believe in Graalvm 21.1 was added some mecahnics to try and detct if security was being used and if yes add all security services. That is a nice feature but we find that it is adding more than it need to.

Opening this issue to discuss options on avoiding this.

other info:
21.0 gives 5768 classes vs. 7488 classes in 21.1 so its quite an increase with no functional gain.

@maxandersen
Copy link
Author

if we could at all have a way to disable the now default "--enable-all-security-services", i.e. "--no-enable-all-security-services" would be great.

@thomaswue
Copy link
Member

@vjovanov @christianwimmer Can we assess in collaboration with the Quarkus team why the automatic detection is adding those security services for the Quarkus "hello world"?

@christianwimmer christianwimmer assigned cstancu and unassigned vjovanov May 20, 2021
@christianwimmer
Copy link

@cstancu please have a look if there is anything obvious that should not be included. Also would be good to have a tracing flag that prints why a certain security service is included.

@christianwimmer
Copy link

@maxandersen also one thing that Quarkus can try: The image generator uses the security services configured at image build time and puts the reachable ones into the image. But if you know that you do not need a security provider at all, you can already remove that provider for the image generator. Then it is guaranteed that this provider is not included into the image.

@jaikiran
Copy link
Contributor

Although not the same helloworld app as what Max used, here's a github repo https://github.com/jaikiran/graal-3422-reproducer which has a simple Quarkus app (which just uses JAXRS RestEasy extension). The README[1] explains how to generate the native image as well as the native image reports (like call tree and used classes).

I ran it against 21.0.0 and 21.1.0 and just like Max, I see a difference of around 2K classes, used in 21.1.0. These generated reports are already available in the reports.tar.gz[2]. I had to tar those reports because of the size of those text files. The tar has the reports for both 21.0.0 and 21.1.0 and a simple diff command against the used_classes_... files in both those versions will show the difference.

I see a lot of additional classes added for reflection and bunch of crypto classes marked as used.

[1] https://github.com/jaikiran/graal-3422-reproducer/blob/master/README.md
[2] https://github.com/jaikiran/graal-3422-reproducer/blob/master/reports.tar.gz

@borkdude
Copy link

I see a 3MB increase when upgrading babashka to 21.1.0.

The diff shows that classes from sun.security.pkcs11, javax.security.auth, sun.security.util are being pulled in extra.

used_classes_bb_20210522_140854_21.0.0.txt

used_methods_bb_20210522_141515_21.1.0.txt

diff.txt

@maxandersen
Copy link
Author

Our assumption is that graalvm notices classes in vertx that refer to security but we know from quarkus build time is not needed.

@cstancu
Copy link
Member

cstancu commented May 30, 2021

a38cba8 refactors the automatic registration of security services. Using -H:-EnableSecurityServicesFeature will disable the automatic registration of all security services, however the re-run class initializer rules previosuly guarded by this option are now always on by default; these rules have no effect if the corresponding classes are not reachable, but are essential for correctness if the classes they affect are included in the image.

Disabling the automatic registration of security services means that a custom reflection registration must be provided, depending on which security services the application uses. See the updated JCASecurityServices.md.

Looking at the Quarkus getting-started example the automatic registration of many of the security services is triggered by code in the HTTP proxy authentication, e.g., via sun.net.www.protocol.http.HttpURLConnection.getHttpProxyAuthentication(). Even if you disable HTTP, just for a quick and dirty test, SSL code gets reachable via JBoss remote logging code, e.g., org.jboss.logmanager.handlers.SyslogHandler.getClientSocketFactory() which calls SSLSocketFactory.getDefault(). Also vert.x makes some security services reachable.

Regarding the increase in size: out of the 10Mb only about 5Mb are due to the security services. The rest can be accounted for by the various improvements in compatibility, e.g., improved suport for MethodHandles. We are looking into ways to reduce the footprint further.

This PR also improves tracing, enabled via -H:+TraceSecurityServices, to show why a certain security service was registered. Note that the tracing is now printed to a file instead of the command line. Here is for example the tracing detailing why KeyStore services are included in the getting-started image:

Service factory method java.security.KeyStore.getInstance(java.lang.String, java.lang.String) is reachable.
    Analysis parsing context: 
        at io.vertx.core.net.impl.KeyStoreHelper.loadKeyStoreOptions(KeyStoreHelper.java:220)
        at io.vertx.core.net.KeyStoreOptionsBase.getHelper(KeyStoreOptionsBase.java:148)
        at io.vertx.core.net.KeyStoreOptionsBase.keyManagerMapper(KeyStoreOptionsBase.java:172)
        at io.vertx.core.net.impl.SSLHelper.getContext(SSLHelper.java:517)
        at io.vertx.core.net.impl.SSLHelper.validate(SSLHelper.java:536)
        at io.vertx.core.http.impl.HttpServerImpl.listen(HttpServerImpl.java:284)
        at io.quarkus.vertx.http.runtime.VertxHttpRecorder$WebDeploymentVerticle.setupUnixDomainSocketHttpServer(VertxHttpRecorder.java:906)
        at io.quarkus.vertx.http.runtime.VertxHttpRecorder$WebDeploymentVerticle.start(VertxHttpRecorder.java:894)
        at io.vertx.core.Verticle.start(Verticle.java:66)
        at io.vertx.core.impl.DeploymentManager.lambda$doDeploy$9(DeploymentManager.java:556)
        at io.vertx.core.impl.DeploymentManager$$Lambda$157/1597924771.handle(Unknown Source)
        at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366)
        at io.vertx.core.impl.EventLoopContext.execute(EventLoopContext.java:43)
        at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:229)
        at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:221)
        at io.vertx.core.net.impl.VertxHandler.exceptionCaught(VertxHandler.java:134)
        at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:302)
        at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:281)
        at io.netty.channel.DefaultChannelPipeline.fireExceptionCaught(DefaultChannelPipeline.java:907)
        at io.netty.channel.VoidChannelPromise.fireException0(VoidChannelPromise.java:236)
        at io.netty.channel.VoidChannelPromise.setFailure(VoidChannelPromise.java:167)
        at io.netty.channel.VoidChannelPromise.setFailure(VoidChannelPromise.java:26)
        at io.netty.channel.AbstractChannel$AbstractUnsafe.shutdownOutput(AbstractChannel.java:668)
        at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:945)
        at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.flush0(AbstractNioChannel.java:354)
        at io.netty.channel.nio.AbstractNioByteChannel$1.run(AbstractNioByteChannel.java:54)
        at java.lang.Shutdown.runHooks(Shutdown.java:123)
        at java.lang.Shutdown.sequence(Shutdown.java:170)
        at java.lang.Shutdown.shutdown(Shutdown.java:238)
        at com.oracle.svm.core.jdk.RuntimeSupport.shutdown(RuntimeSupport.java:132)
        at com.oracle.svm.core.JavaMainWrapper.runCore(JavaMainWrapper.java:171)
        at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:182)
        at com.oracle.svm.core.code.IsolateEnterStub.JavaMainWrapper_run_5087f5482cc9a6abc971913ece43acb471d2631b(generated:0)
    Reachability of KeyStore service type API triggers registration of following services:
        Type: KeyStore, Provider: SUN, Algorithm: JKS, Class: sun.security.provider.JavaKeyStore$DualFormatJKS
            Registered KeyStore.JKS implementation class: sun.security.provider.JavaKeyStore$JKS
        Type: KeyStore, Provider: SUN, Algorithm: DKS, Class: sun.security.provider.DomainKeyStore$DKS
        Type: KeyStore, Provider: SUN, Algorithm: CaseExactJKS, Class: sun.security.provider.JavaKeyStore$CaseExactJKS
        Type: KeyStore, Provider: SunJCE, Algorithm: JCEKS, Class: com.sun.crypto.provider.JceKeyStore
        Type: KeyStore, Provider: SunJSSE, Algorithm: PKCS12, Class: sun.security.pkcs12.PKCS12KeyStore

The Analysis parsing context is just the path that the analysis took in the call graph and it is a potential run time exectution path.

@cstancu cstancu assigned davleopo and unassigned davleopo Jun 3, 2021
@cstancu cstancu closed this as completed Dec 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants