Skip to content

Webapp does not start with Tomcat 9.0.118 (with analysis) #117

@vdeconinck

Description

@vdeconinck

Hi,
We're happily using Stripes in several apps, and one of them stopped working once we upgraded Tomcat from 9.0.116 to 9.0.118 (same war, confirmed on both Linux and Windows). Tomcat logs indicated:

java.lang.IllegalArgumentException: The resource path [/WEB-INF/classes/be/betv/wimoos/ui/action/api/ApiArticleListActionBean.class/Êþº¾\u0000\u0000\u00007\u0001/] has been normalized to [null] which is not valid
		at org.apache.catalina.webresources.StandardRoot.validate(StandardRoot.java:259)
		at org.apache.catalina.webresources.StandardRoot.getResources(StandardRoot.java:303)
		at org.apache.catalina.webresources.StandardRoot.getClassLoaderResources(StandardRoot.java:227)
		at org.apache.catalina.loader.WebappClassLoaderBase.findResources(WebappClassLoaderBase.java:952)
		at org.apache.catalina.loader.WebappClassLoaderBase.getResources(WebappClassLoaderBase.java:1047)
		at net.sourceforge.stripes.vfs.VFS.getResources(VFS.java:171)
		at net.sourceforge.stripes.vfs.DefaultVFS.list(DefaultVFS.java:93)
		at net.sourceforge.stripes.vfs.DefaultVFS.list(DefaultVFS.java:135)
		at net.sourceforge.stripes.vfs.DefaultVFS.list(DefaultVFS.java:135)
		at net.sourceforge.stripes.vfs.VFS.list(VFS.java:200)
		at net.sourceforge.stripes.util.ResolverUtil.find(ResolverUtil.java:202)
		at net.sourceforge.stripes.util.ResolverUtil.findImplementations(ResolverUtil.java:164)
		at net.sourceforge.stripes.controller.AnnotatedClassActionResolver.findClasses(AnnotatedClassActionResolver.java:683)
		at net.sourceforge.stripes.controller.AnnotatedClassActionResolver.init(AnnotatedClassActionResolver.java:118)
		at net.sourceforge.stripes.controller.NameBasedActionResolver.init(NameBasedActionResolver.java:125)
		at net.sourceforge.stripes.config.DefaultConfiguration.init(DefaultConfiguration.java:121)

After digging through the Tomcat changes for v9.0.118, it appears that a new test was added to org.apache.tomcat.util.http.RequestUtil.normalize(String path, boolean replaceBackSlash), which reads:

        // Reject paths containing null bytes
        if (path.indexOf(0) > -1) {
            return null;
        }

That seemingly innocuous change causes org.apache.catalina.webresources.StandardRoot.validate() to now throw an IllegalArgumentException when the path contains null bytes, which leads to the stacktrace above.

So we searched where the offending path /WEB-INF/classes/be/betv/wimoos/ui/action/api/ApiArticleListActionBean.class/Êþº¾\u0000\u0000\u00007\u0001/ came from.
The reason is this code in Stripes' net.sourceforge.stripes.vfs.DefaultVFS.java:

	/*
	 * Some servlet containers allow reading from directory resources like a
	 * text file, listing the child resources one per line. However, there is no
	 * way to differentiate between directory and file resources just by reading
	 * them. To work around that, as each line is read, try to look it up via
	 * the class loader as a child of the current resource. If any line fails
	 * then we assume the current resource is not a directory.
	 */
	is = url.openStream();
	BufferedReader reader = new BufferedReader(new InputStreamReader(is));
	List<String> lines = new ArrayList<String>();
	for (String line; (line = reader.readLine()) != null;) {
		log.trace("Reader entry: ", line);
		lines.add(line);
		if (getResources(path + "/" + line).isEmpty()) {
			lines.clear();
			break;
		}
	}

When url is a class file, attempting a read as a text file returns binary garbage.
Concatenating that garbage after the path and passing it to getResources() causes that invalid "path" to be evaluated by the classloader. This evaluation fails, now throwing an Exception (instead of returning an empty Enumeration<URL>), which crashes the whole webapp startup.

We fixed the issue in our local Stripes fork by replacing:

if (getResources(path + "/" + line).isEmpty()) {

with:

if (line.indexOf(0) > -1 || getResources(path + "/" + line).isEmpty()) 

to catch "lines" with null bytes earlier, but probably that is not the most universal way to solve the issue.

Keep on the good work !

Vincent

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions