Bug 64735

Summary: ServletContext.addJspFile() always fails with SecurityManager
Product: Tomcat 10 Reporter: Kyle Stiemann <stiemannkj1>
Component: CatalinaAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: normal    
Priority: P2    
Version: 10.0.0-M7   
Target Milestone: ------   
Hardware: PC   
OS: Mac OS X 10.1   
Attachments: addJspFile-SecurityManager-reproducer.bundle
addJspFile-SecurityManager-reproducer.bundle

Description Kyle Stiemann 2020-09-10 20:44:46 UTC
Created attachment 37453 [details]
addJspFile-SecurityManager-reproducer.bundle

### Environment:

```
$ gradle --version

------------------------------------------------------------
Gradle 5.5.1
------------------------------------------------------------

Build time:   2019-07-10 20:38:12 UTC
Revision:     3245f748c7061472da4dc184991919810f7935a5

Kotlin:       1.3.31
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.14 compiled on March 12 2019
JVM:          1.8.0_242 (AdoptOpenJDK 25.242-b08)
```

It's likely that the reproducer can be built with earlier or later versions of Gradle, but 5.5.1 is the version I am currently using.

This bug appears to affect all versions of Tomcat 9+ including 9.0.x and 10.0.x.


### Steps to reproduce:

1. Download and clone the attached project:

```
git clone $HOME/Downloads/addJspFile-SecurityManager-reproducer.bundle &&
  cd addJspFile-SecurityManager-reproducer
```

2. Build the war:

```
gradle clean build war
```

3. Copy the war to Tomcat 10.x:

```
cp build/lib/reproducer $TOMCAT_HOME/webapps/reproducer.war
```

4. Run Tomcat without the security manager enabled:

```
cd $TOMCAT_HOME/bin && catalina.sh run
```

5. Navigate to http://localhost:8080/reproducer/ and verify that the text appears: "JSP Servlet added via ServletContext.addJspFile()"

6. Kill the server (with [Ctrl] + [C]).

7. Run Tomcat with the security manager enabled:

```
catalina.sh run -security
```

8. Navigate to http://localhost:8080/reproducer/.

If the bug still exists, the page will return a 404 and the following exception will appear in the Tomcat logs at startup:

```
SEVERE: Error deploying web application archive [/private/var/folders/8c/h3gzwksx0hs7pmzvr112h1540000gn/T/cargo/conf/webapps/reproducer.war]
java.lang.IllegalStateException: Error starting child
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:720)
        at org.apache.catalina.core.ContainerBase.access$000(ContainerBase.java:129)
        at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:150)
        at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:140)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:688)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:978)
        at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1848)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
        at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:773)
        at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:427)
        at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1576)
        at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:309)
        at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123)
        at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:423)
        at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:366)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:936)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:841)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
        at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardService.startInternal(StandardService.java:421)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.startup.Catalina.start(Catalina.java:738)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:342)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/reproducer]]
        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.ContainerBase.addChildInternal(ContainerBase.java:717)
        ... 41 more
Caused by: java.lang.RuntimeException: org.apache.catalina.core.ApplicationContext.addJspFile()
        at org.apache.catalina.core.ApplicationContextFacade.doPrivileged(ApplicationContextFacade.java:855)
        at org.apache.catalina.core.ApplicationContextFacade.addJspFile(ApplicationContextFacade.java:544)
        at addjspfile.securitymanager.reproducer.AddJspFileInitializer.onStartup(AddJspFileInitializer.java:14)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5128)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        ... 42 more
Caused by: java.lang.NoSuchMethodException: org.apache.catalina.core.ApplicationContext.addJspFile()
        at java.lang.Class.getMethod(Class.java:1786)
        at org.apache.catalina.core.ApplicationContextFacade.invokeMethod(ApplicationContextFacade.java:877)
        at org.apache.catalina.core.ApplicationContextFacade.doPrivileged(ApplicationContextFacade.java:852)
        ... 46 more
```

If the bug is fixed, no exception will appear and the following text will appear for http://localhost:8080/reproducer/: "JSP Servlet added via ServletContext.addJspFile()"

See also: https://bz.apache.org/bugzilla/show_bug.cgi?id=64734
Comment 1 Remy Maucherat 2020-09-10 20:54:20 UTC
*** Bug 64734 has been marked as a duplicate of this bug. ***
Comment 2 Kyle Stiemann 2020-09-10 20:59:03 UTC
PRs sent for the fix:

master: https://github.com/apache/tomcat/pull/357
9.0.x:  https://github.com/apache/tomcat/pull/358
Comment 3 Kyle Stiemann 2020-09-10 21:01:13 UTC
Created attachment 37454 [details]
addJspFile-SecurityManager-reproducer.bundle
Comment 4 Kyle Stiemann 2020-09-10 21:04:08 UTC
The test app is pretty simple and basically includes one valid JSP called add-jsp-file.jsp and the following ServletContainerInitializer:

```
public final class AddJspFileInitializer implements ServletContainerInitializer {
  @Override
  public final void onStartup(final Set<Class<?>> annotatedClasses, final ServletContext servletContext) {
    servletContext
        .addJspFile("AddJspFile", "/WEB-INF/classes/add-jsp-file.jsp")
        .addMapping("/");
  }
}
```
Comment 5 Kyle Stiemann 2020-09-13 03:50:33 UTC
Updated PRs fixing all the broken methods in ApplicationContextFacade and adding regression tests:

master: https://github.com/apache/tomcat/pull/359
9.0.x:  https://github.com/apache/tomcat/pull/360
Comment 6 Mark Thomas 2020-09-30 17:05:58 UTC
Thanks again for the patch. I back-ported it (with a few changes due to minimum Java versions) all the way back to 7.0.x where there was one method missing.

Fixed in:
- master for 10.0.0-M9 onwards
- 9.0.x for 9.0.39 onwards
- 8.5.x for 8.5.59 onwards
- 7.0.x for 7.0.107 onwards