Bug 65952

Summary: Exception in PrivilegedSetAccessControlContext initialisation with SecurityManager activated and java.lang module not opened
Product: Tomcat 9 Reporter: Sylvain Dusart <sylvain.dusart>
Component: CatalinaAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: normal    
Priority: P2    
Version: 9.0.58   
Target Milestone: -----   
Hardware: PC   
OS: Linux   

Description Sylvain Dusart 2022-03-14 10:34:50 UTC
We use Tomcat 9.0.x in an executable jar produced by SpringBoot (2.6.x) with the SecurityManager activated (JDK 17.0.x).

When upgrading from SpringBoot 2.6.3 (Tomcat 9.0.56) to SpringBoot 2.6.4 (Tomcat 9.0.58), this exception is thrown during startup :

org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:163)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
	at com.alsyontech.thetys.ingestion.Ingestion.main(Ingestion.java:15)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
	at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:142)
	at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104)
	at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:478)
	at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:211)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:182)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:160)
	... 16 common frames omitted
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat]]
	at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
	at org.apache.catalina.core.StandardService.startInternal(StandardService.java:432)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:927)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486)
	at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123)
	... 21 common frames omitted
Caused by: java.lang.ExceptionInInitializerError: null
	at org.apache.tomcat.util.threads.TaskThreadFactory.newThread(TaskThreadFactory.java:63)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor.java:630)
	at java.base/java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:920)
	at java.base/java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1593)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:346)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor.scheduleWithFixedDelay(ScheduledThreadPoolExecutor.java:680)
	at org.apache.tomcat.util.threads.ScheduledThreadPoolExecutor.scheduleWithFixedDelay(ScheduledThreadPoolExecutor.java:138)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:951)
	at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:263)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	... 27 common frames omitted
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.security.AccessControlContext java.lang.Thread.inheritedAccessControlContext accessible: module java.base does not "opens java.lang" to unnamed module @69ea3742
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
	at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
	at org.apache.tomcat.util.security.PrivilegedSetAccessControlContext.<clinit>(PrivilegedSetAccessControlContext.java:41)
	... 37 common frames omitted

I presume this is linked to the changes made for https://bz.apache.org/bugzilla/show_bug.cgi?id=65714 in version 9.0.57.

During the static initialization of  org.apache.tomcat.util.security.PrivilegedSetAccessControlContext, a call is done to java.lang.reflect.AccessibleObject#checkCanSetAccessible(java.lang.Class<?>, java.lang.Class<?>, boolean) with 
* caller = org.apache.tomcat.util.security.PrivilegedSetAccessControlContext => callerModule = unnamed module
* declaringClass = java.lang.Thread => declaringModule = java.base

It seems now mandatory to add "--add-opens=java.base/java.lang=ALL-UNNAMED" when running Tomcat in SpringBoot with SecurityManager.

This "add-opens" is done in catalina.sh to prevent errors on shutdown according to webapps/docs/setup.html : "When running on Java 9 you will need to additionally specify the following when starting jsvc to avoid warnings on shutdown".

Regards.
Comment 1 Mark Thomas 2022-03-15 19:41:35 UTC
Fixed in:
- 10.1.x for 10.1.0-M13 onwards
- 10.0.x for 10.0.19 onwards
- 9.0.x for 9.0.61 onwards
- 8.5.x for 8.5.78 onwards