https://issues.apache.org/bugzilla/show_bug.cgi?id=52988

             Bug #: 52988
           Summary: ExpandWar::deleteDir() traverses symlinked
                    directories, deleting files outside of appBase
           Product: Tomcat 7
           Version: 7.0.16
          Platform: Other
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Catalina
        AssignedTo: dev@tomcat.apache.org
        ReportedBy: christiw...@gmail.com
                CC: christiw...@gmail.com
    Classification: Unclassified


Overview:
When Tomcat fails to expand a WAR file, it attempts to clean up after itself by
running deleteDir(docBase). This function contains a problematic if-condition
that allows Tomcat to traverse symlinked directories and recursively delete
files behind them, even if those files are outside 'docBase'.

Steps to Reproduce:
1) Explode a WAR successfully into webapps/. 
2) Add a symlink in that WAR's docbase to a directory outside of webapps/. As
far as I can tell, it can be anywhere on the machine (ours traversed a mount,
for example).
3) Redeploy a WAR, but make it fail somehow (I witnessed it while deploying a
corrupted zip archive), thus activating these lines of ExpandWar.java:

158             if (!success) {
159                 // If something went wrong, delete expanded dir to keep
things.
160                 // clean
161                 deleteDir(docBase);
162             }

Actual Results:
deleteDir() traversed the directory symlinks in 'docBase', allowing Tomcat to
incorrectly delete files outside of docBase. It appears the problem is line 374
of ExpandWar.java. Despite internet sources claiming otherwise, I was able to
verify the isDirectory() method returns 'true' for symlinked directories using
my version, build, and platform:

366     public static boolean deleteDir(File dir, boolean logFailure) {
367 
368         String files[] = dir.list();
369         if (files == null) {
370             files = new String[0];
371         }
372         for (int i = 0; i < files.length; i++) {
373             File file = new File(dir, files[i]);
374             if (file.isDirectory()) {
375                 deleteDir(file, logFailure);
376             } else {
377                 file.delete();
378             }

Expected Results:
ExpandWar.java should delete symlinks without following them. One could either
check the absolute vs. canonical path, or use something like the isSymlink()
method already present in Apache Commons:
http://stackoverflow.com/a/813730/877115

Build Date and Platform:
Sun java 1.6.0_20 running on RHEL 6.1. First discovered in 7.0.16, but I
checked trunk and the troubled logic is unchanged there.

Additional information:
We used symlinks to link client assets inside docBase for legacy code purposes.
We've refactored this code out after encountering this bug, as maintaining
symlinks inside exploded WARs is difficult, a bad practice, and this bug makes
them a time bomb. All the same, I can't imagine any conditions under which
Tomcat's WAR logic should be able to delete files outside of 'docBase', even if
the user was foolish like me. Hence this filing.

-- 
Configure bugmail: https://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to