Bug 56785 - (NP_Startup) NullPointer in processAnnotationsFile during Application Startup
(NP_Startup)
NullPointer in processAnnotationsFile during Application Startup
Status: RESOLVED FIXED
Product: Tomcat 8
Classification: Unclassified
Component: Catalina
8.0.8
PC Linux
: P2 normal (vote)
: ----
Assigned To: Tomcat Developers Mailing List
:
Depends on:
Blocks:
  Show dependency tree
 
Reported: 2014-07-29 08:22 UTC by Juergen Sussner
Modified: 2016-01-18 03:34 UTC (History)
1 user (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Juergen Sussner 2014-07-29 08:22:52 UTC
Hello,

we go the following exception in Aplicaiton startup. 

java.lang.NullPointerException
        at org.apache.catalina.startup.ContextConfig.processAnnotationsFile(ContextConfig.java:1966)
        at org.apache.catalina.startup.ContextConfig.processAnnotationsFile(ContextConfig.java:1967)
        at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1920)
        at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1878)
        at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1146)
        at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:768)
        at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:303)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
        at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5069)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        ... 6 more

The reason was that we added -Duser.dir=<customDir> to give Tomcat a uniqe working dir. Within our <customDir> there was a directory which was not accessible for the tomcat user. It belongs to root and no one else has access. So tomcat tries to scan the user.dir and tries to list files within the restricted dir. 

Doing so ths file.listFiles() command retuns null (instead of a list of files) which is not correctly handled and causing this Nullpointer and preventing the Server from startup.

to recrate set -Duser.dir in setenv.sh to /tmp, create a folder /tmp/test, give permission 700 to /tmp/test, chwon root:root /tmp/test and start a tomcat with at least one application and a user other than root.

The fix would be to correctly handle nullpointers or to simply write a meningfull log message. 

Kind regards 
Juergen Sussner
Comment 1 Christopher Schultz 2014-07-30 19:28:47 UTC
So, ultimately, this is a permissions problem: File.isDirectory returns 'true' but then File.list() fails, which returns null. We can't get any information about the error without probing the File object further.

It should be easy to test for this.
Comment 2 Christopher Schultz 2014-07-30 19:41:06 UTC
(In reply to Juergen Sussner from comment #0)
> to recrate set -Duser.dir in setenv.sh to /tmp, create a folder /tmp/test,
> give permission 700 to /tmp/test, chwon root:root /tmp/test and start a
> tomcat with at least one application and a user other than root.

I was unable to reproduce this issue:

CATALINA_OPTS is -Duser.dir=/tmp -Xms63M -Xmx192M -XX:+UseCompressedOops -Djava.awt.headless=true

$ ls -ld /tmp/foo
drwx------  2 root  wheel  68 Jul 30 15:35 /tmp/foo

I'm not running Tomcat as root. I'm using current trunk.

I don't doubt there is a potential bug here, and it's somewhat easily fixed, but I can't reproduce the problem to begin with so I won't be able to verify the fix.

I have set metadata-complete="false" and version="2.5" in my web.xml document element.

Am I missing anything?
Comment 3 Juergen Sussner 2014-07-31 05:38:51 UTC
Hello,

You are right, a standart tomcat did not seem to have this issue, it somehow depends on the applicaitons we had installed. Sorry my fault. i'll try to investigate. 

There has to be some sort of application setup / setting that triggers this ContextConfig.processAnnotations. 

Annyway. i didt a short test programm to show where the nullpointer came from:

import java.io.File;


public class FilePermissionCheck {
	
	public static void main(String[] args) {
		if (args.length != 1) {
			System.out.println("Usage: FilePermissionCheck <fileNameWithPath>");
			System.exit(-1);
		}
		
		String fileName = args[0];
		
		File f = new File(fileName);
		
		System.out.println("isDirectory() = " + f.isDirectory());
		System.out.println("canRead() = " + f.canRead());
		System.out.println("canWrite() = " + f.canWrite());
		System.out.println("canExecute() = " + f.canExecute());
		System.out.println("listFiles() = " + f.listFiles());
	
		
	}

}

doing so on a SLES10 system results in the following:

## /tmp/user.dir> ls -la
total 24
drwxr-xr-x  3 suweb users  4096 Jul 31 07:27 .
drwxrwxrwt 37 root  root  12288 Jul 31 07:35 ..
-rw-r--r--  1 suweb users  1350 Jul 31 07:27 FilePermissionCheck.class
drwx------  2 root  root   4096 Jul 31 06:58 root

## /tmp/user.dir> id
uid=55052(suweb) gid=100(users) groups=100(users),1001(web)

## /tmp/user.dir> java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build pxa6470sr6fp1-20140108_01(SR6 FP1))
IBM J9 VM (build 2.6, JRE 1.7.0 Linux amd64-64 Compressed References 20140106_181350 (JIT enabled, AOT enabled)
J9VM - R26_Java726_SR6_20140106_1601_B181350
JIT  - r11.b05_20131003_47443.02
GC   - R26_Java726_SR6_20140106_1601_B181350_CMPRSS
J9CL - 20140106_181350)
JCL - 20140103_01 based on Oracle 7u51-b11

## /tmp/user.dir> java FilePermissionCheck .
isDirectory() = true
canRead() = true
canWrite() = true
canExecute() = true
listFiles() = [Ljava.io.File;@22cf6604

## /tmp/user.dir> java FilePermissionCheck root
isDirectory() = true
canRead() = false
canWrite() = false
canExecute() = false
listFiles() = null
Comment 4 Christopher Schultz 2014-07-31 17:47:06 UTC
Oh, I can certainly see the possibility for a problem. I was just homing to be able to verify that I had fixed it properly rather than just assuming I had done it properly.

Would you be willing to build Tomcat from source with a patch I provide, or I could provide a replacement .class file for ContextConfig that you could try. I'd like at least /someone/ to verify a fix before I commit one.
Comment 5 Konstantin Kolinko 2014-07-31 23:12:41 UTC
(In reply to Christopher Schultz from comment #2)
(In reply to Juergen Sussner from comment #0)

1) -Duser.dir=/tmp is a wrong way to set that property. The correct way is to perform "cd /tmp" when launching Tomcat.

2) I guess that the issue would happen when some directory in $CATALINA_BASE/webapps/testapp/WEB-INF/classes  is not readable. The "user.dir" property value is irrelevant.

Why would you have an unreadable directory in such a place among your classes? Is there a valid reason for that?

What if skipped directory contains something important, e.g. a @WebFilter?
I think it is OK to fail fatally and refuse to start such a misconfigured application.
Comment 6 Juergen Sussner 2014-08-01 20:43:37 UTC
Sure, it would be great if you could provide a replacement class so i would patch the class in our tomcat having this effect to verrify the fix.

I assume there are no class signature braking changes between 8.0.8 and the current trunk.

Since the affected tomcat is one of my company i cant just give you the applications, but i'll try to annonymize the stuff and send it to you whe i am back in office, hopefully this could help to recreate the issue.

-------------------------------

The other sing is: we migrated the config from a tomcat 6 and the property -Duser.dir was set to /tmp/ within /tmp/ the virus scanner created a only root readable directory. 

It took some time and a strace and a remote debugging session to figure out what prevents the tomcat from starting as non root user, because every application, work dir and tomcat installation files belong to the tomcat user

The debugger clearly pointed out that the tomcat scanns the directory denoted by user.dir and tries to list all files, event files in this unreadable directory created by the virus scanner.

Annyhow. Even if this is a missconfiguration, it would be great if the tomcat issues a meaningfull error message and not just a nullpointer, leving no clue where to look for the issue.

Kind regards 
Juergen Sussner
Comment 7 Christopher Schultz 2014-08-01 22:30:32 UTC
(In reply to Konstantin Kolinko from comment #5)
> (In reply to Christopher Schultz from comment #2)
> (In reply to Juergen Sussner from comment #0)
> 
> 1) -Duser.dir=/tmp is a wrong way to set that property. The correct way is
> to perform "cd /tmp" when launching Tomcat.
> 
> 2) I guess that the issue would happen when some directory in
> $CATALINA_BASE/webapps/testapp/WEB-INF/classes  is not readable. The
> "user.dir" property value is irrelevant.
> 
> Why would you have an unreadable directory in such a place among your
> classes? Is there a valid reason for that?
> 
> What if skipped directory contains something important, e.g. a @WebFilter?
> I think it is OK to fail fatally and refuse to start such a misconfigured
> application.

A fatal exception is okay, but right now it's a NPE. I was going to change it to an IOException with a nice error message. Same behavior: just a nicer error message (and it will actually tell you the problem).
Comment 8 Mark Thomas 2014-08-05 12:27:45 UTC
A non-readable directory in WEB-INF/classes won't trigger this but a non-readable directory elsewhere on the classpath with <JarScanner scanAllDirectories="true" /> will.

Including user.dir on the class path is unusual. You might want to look into why that is necessary.

I'm looking at possible patches for this now.
Comment 9 Mark Thomas 2014-08-05 12:57:00 UTC
For consistency with how this is handled in WEB-INF/classes, unreadable directories will simply be ignored.
Comment 10 Konstantin Kolinko 2016-01-18 03:34:52 UTC
The fix is in Tomcat 8.0.11 onwards.

Fixed in Tomcat 7 (r1725170) and will be in 7.0.68 onwards.