Skip to content

Commit

Permalink
Various related (un)deploy improvements including:
Browse files Browse the repository at this point in the history
 - better handling of failed (un)deployment
 - adding checking for valid zip file entries that don't make sense in a WAR file
 - improved validation of WAR file names
 - make sure error messages match the action
 - the return from File.getCanonicalPath() may or may not return a final separator for directories

This fixes CVE-2009-2693, CVE-2009-2901 & CVE-2009-2902

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@892795 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
markt-asf committed Dec 21, 2009
1 parent bb09002 commit 3e1010b
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 30 deletions.
2 changes: 2 additions & 0 deletions java/org/apache/catalina/loader/LocalStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ standardLoader.reloading=Reloading checks are enabled for this Context
standardLoader.removeRepository=Removing repository {0}
standardLoader.starting=Starting this Loader
standardLoader.stopping=Stopping this Loader
webappClassLoader.illegalJarPath=Illegal JAR entry detected with name {0}
webappClassLoader.jdbcRemoveFailed=JDBC driver de-registration failed
webappClassLoader.jdbcRemoveStreamError=Exception closing input stream during JDBC driver de-registration
webappClassLoader.stopped=Illegal access: this web application instance has been stopped already. Could not load {0}. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
Expand All @@ -39,6 +40,7 @@ webappClassLoader.clearRmiFail=Failed to clear context class loader referenced f
webappClassLoader.clearThreadLocal=A web application created a ThreadLocal with key of type [{0}] (value [{1}]) and a value of type [{2}] (value [{3}]) but failed to remove it when the web application was stopped. To prevent a memory leak, the ThreadLocal has been forcibly removed.
webappClassLoader.clearThreadLocalFail=Failed to clear ThreadLocal references
webappClassLoader.stopThreadFail=Failed to terminate thread named [{0}]
webappClassLoader.validationErrorJarPath=Unable to validate JAR entry with name {0}
webappClassLoader.warnThread=A web application appears to have started a thread named [{0}] but has failed to stop it. This is very likely to create a memory leak.
webappClassLoader.wrongVersion=(unable to load class {0})
webappLoader.addRepository=Adding repository {0}
Expand Down
26 changes: 25 additions & 1 deletion java/org/apache/catalina/loader/WebappClassLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ protected boolean removeEldestEntry(
* Path where resources loaded from JARs will be extracted.
*/
protected File loaderDir = null;

protected String canonicalLoaderDir = null;

/**
* The PermissionCollection for each CodeSource for a web
Expand Down Expand Up @@ -577,6 +577,18 @@ public void setJarPath(String jarPath) {
*/
public void setWorkDir(File workDir) {
this.loaderDir = new File(workDir, "loader");
if (loaderDir == null) {
canonicalLoaderDir = null;
} else {
try {
canonicalLoaderDir = loaderDir.getCanonicalPath();
if (!canonicalLoaderDir.endsWith(File.separator)) {
canonicalLoaderDir += File.separator;
}
} catch (IOException ioe) {
canonicalLoaderDir = null;
}
}
}

/**
Expand Down Expand Up @@ -2514,6 +2526,18 @@ protected ResourceEntry findResourceInternal(String name, String path) {
(".class"))) {
resourceFile = new File
(loaderDir, jarEntry2.getName());
try {
if (!resourceFile.getCanonicalPath().startsWith(
canonicalLoaderDir)) {
throw new IllegalArgumentException(
sm.getString("webappClassLoader.illegalJarPath",
jarEntry2.getName()));
}
} catch (IOException ioe) {
throw new IllegalArgumentException(
sm.getString("webappClassLoader.validationErrorJarPath",
jarEntry2.getName()), ioe);
}
resourceFile.getParentFile().mkdirs();
FileOutputStream os = null;
InputStream is = null;
Expand Down
28 changes: 17 additions & 11 deletions java/org/apache/catalina/startup/ContextConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -733,35 +733,40 @@ protected void fixDocBase()
file = new File(docBase);
String origDocBase = docBase;

String contextPath = context.getPath();
if (contextPath.equals("")) {
contextPath = "ROOT";
String pathName = context.getPath();
if (pathName.equals("")) {
pathName = "ROOT";
} else {
if (contextPath.lastIndexOf('/') > 0) {
contextPath = "/" + contextPath.substring(1).replace('/','#');
}
// Context path must start with '/'
pathName = pathName.substring(1).replace('/', '#');
}
if (docBase.toLowerCase().endsWith(".war") && !file.isDirectory() && unpackWARs) {
URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
docBase = ExpandWar.expand(host, war, contextPath);
docBase = ExpandWar.expand(host, war, pathName);
file = new File(docBase);
docBase = file.getCanonicalPath();
if (context instanceof StandardContext) {
((StandardContext) context).setOriginalDocBase(origDocBase);
}
} else if (docBase.toLowerCase().endsWith(".war") &&
!file.isDirectory() && !unpackWARs) {
URL war =
new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/");
ExpandWar.validate(host, war, pathName);
} else {
File docDir = new File(docBase);
if (!docDir.exists()) {
File warFile = new File(docBase + ".war");
if (warFile.exists()) {
URL war =
new URL("jar:" + warFile.toURI().toURL() + "!/");
if (unpackWARs) {
URL war =
new URL("jar:" + warFile.toURI().toURL() + "!/");
docBase = ExpandWar.expand(host, war, contextPath);
docBase = ExpandWar.expand(host, war, pathName);
file = new File(docBase);
docBase = file.getCanonicalPath();
} else {
docBase = warFile.getCanonicalPath();
ExpandWar.validate(host, war, pathName);
}
}
if (context instanceof StandardContext) {
Expand Down Expand Up @@ -1122,7 +1127,8 @@ protected synchronized void stop() {
if (!docBaseFile.isAbsolute()) {
docBaseFile = new File(appBase, docBase);
}
ExpandWar.delete(docBaseFile);
// No need to log failure - it is expected in this case
ExpandWar.delete(docBaseFile, false);
}

ok = true;
Expand Down
Loading

0 comments on commit 3e1010b

Please sign in to comment.