From 65ed69d96a101dfa99eea2cfe17e9e87b310084c Mon Sep 17 00:00:00 2001 From: Mark Thomas Date: Mon, 17 Mar 2014 21:43:58 +0000 Subject: [PATCH] Redefine globalXsltFile as relative to CATALINA_BASE/conf or CATALINA_HOME/conf This is part 1 of 2 of the fix for CVE-2014-0096 git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1578610 13f79535-47bb-0310-9956-ffa450edef68 --- conf/web.xml | 8 +-- java/org/apache/catalina/Container.java | 8 ++- .../apache/catalina/core/ContainerBase.java | 11 ++++ .../apache/catalina/core/StandardEngine.java | 16 ++++++ .../catalina/servlets/DefaultServlet.java | 52 +++++++++++++++---- .../catalina/startup/FailedContext.java | 3 ++ .../apache/catalina/core/TesterContext.java | 5 ++ webapps/docs/default-servlet.xml | 11 ++-- 8 files changed, 94 insertions(+), 20 deletions(-) diff --git a/conf/web.xml b/conf/web.xml index 3940ccbf4..631b06edb 100644 --- a/conf/web.xml +++ b/conf/web.xml @@ -88,10 +88,10 @@ - - - - + + + + default diff --git a/java/org/apache/catalina/Container.java b/java/org/apache/catalina/Container.java index 6df3aaec3..5b0a84c57 100644 --- a/java/org/apache/catalina/Container.java +++ b/java/org/apache/catalina/Container.java @@ -414,7 +414,13 @@ public void logAccess(Request request, Response response, long time, /** - * + * Obtain the location of CATALINA_BASE. */ public File getCatalinaBase(); + + + /** + * Obtain the location of CATALINA_HOME. + */ + public File getCatalinaHome(); } diff --git a/java/org/apache/catalina/core/ContainerBase.java b/java/org/apache/catalina/core/ContainerBase.java index bdbeef38c..3f5a85594 100644 --- a/java/org/apache/catalina/core/ContainerBase.java +++ b/java/org/apache/catalina/core/ContainerBase.java @@ -1155,6 +1155,17 @@ public File getCatalinaBase() { } + @Override + public File getCatalinaHome() { + + if (parent == null) { + return null; + } + + return parent.getCatalinaHome(); + } + + // ------------------------------------------------------ Protected Methods /** diff --git a/java/org/apache/catalina/core/StandardEngine.java b/java/org/apache/catalina/core/StandardEngine.java index a17f900a3..2e01a41b1 100644 --- a/java/org/apache/catalina/core/StandardEngine.java +++ b/java/org/apache/catalina/core/StandardEngine.java @@ -374,6 +374,22 @@ public File getCatalinaBase() { } + @Override + public File getCatalinaHome() { + if (service != null) { + Server s = service.getServer(); + if (s != null) { + File base = s.getCatalinaHome(); + if (base != null) { + return base; + } + } + } + // Fall-back + return super.getCatalinaHome(); + } + + // -------------------- JMX registration -------------------- @Override diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java b/java/org/apache/catalina/servlets/DefaultServlet.java index 3fc244790..e30f3836d 100644 --- a/java/org/apache/catalina/servlets/DefaultServlet.java +++ b/java/org/apache/catalina/servlets/DefaultServlet.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; +import java.util.Locale; import java.util.StringTokenizer; import javax.servlet.RequestDispatcher; @@ -53,6 +54,7 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.WebResource; import org.apache.catalina.WebResourceRoot; @@ -1526,20 +1528,14 @@ protected InputStream findXsltInputStream(WebResource directory) /* Open and read in file in one fell swoop to reduce chance * chance of leaving handle open. */ - if (globalXsltFile!=null) { - FileInputStream fis = null; - - try { - File f = new File(globalXsltFile); - if (f.exists()){ - fis =new FileInputStream(f); + if (globalXsltFile != null) { + File f = validateGlobalXsltFile(); + if (f != null && f.exists()){ + try (FileInputStream fis = new FileInputStream(f)){ byte b[] = new byte[(int)f.length()]; /* danger! */ fis.read(b); return new ByteArrayInputStream(b); } - } finally { - if (fis!=null) - fis.close(); } } @@ -1547,6 +1543,42 @@ protected InputStream findXsltInputStream(WebResource directory) } + private File validateGlobalXsltFile() { + Context context = resources.getContext(); + + File baseConf = new File(context.getCatalinaBase(), "conf"); + File result = validateGlobalXsltFile(baseConf); + if (result == null) { + File homeConf = new File(context.getCatalinaHome(), "conf"); + result = validateGlobalXsltFile(homeConf); + } + + return result; + } + + + private File validateGlobalXsltFile(File base) { + File candidate = new File(base, globalXsltFile); + + // First check that the resulting path is under the provided base + try { + if (!candidate.getCanonicalPath().startsWith(base.getCanonicalPath())) { + return null; + } + } catch (IOException ioe) { + return null; + } + + // Next check that an .xlt or .xslt file has been specified + String nameLower = candidate.getName().toLowerCase(Locale.ENGLISH); + if (!nameLower.endsWith(".xslt") && !nameLower.endsWith(".xlt")) { + return null; + } + + return candidate; + } + + // -------------------------------------------------------- protected Methods diff --git a/java/org/apache/catalina/startup/FailedContext.java b/java/org/apache/catalina/startup/FailedContext.java index c5d12b136..6472074c1 100644 --- a/java/org/apache/catalina/startup/FailedContext.java +++ b/java/org/apache/catalina/startup/FailedContext.java @@ -689,6 +689,9 @@ public synchronized void addValve(Valve valve) { /* NO-OP */ } @Override public File getCatalinaBase() { return null; } + @Override + public File getCatalinaHome() { return null; } + @Override public void setAddWebinfClassesResources(boolean addWebinfClassesResources) { // NO-OP diff --git a/test/org/apache/catalina/core/TesterContext.java b/test/org/apache/catalina/core/TesterContext.java index dac2f975b..ad46e1aeb 100644 --- a/test/org/apache/catalina/core/TesterContext.java +++ b/test/org/apache/catalina/core/TesterContext.java @@ -276,6 +276,11 @@ public File getCatalinaBase() { return null; } + @Override + public File getCatalinaHome() { + return null; + } + @Override public void addLifecycleListener(LifecycleListener listener) { // NO-OP diff --git a/webapps/docs/default-servlet.xml b/webapps/docs/default-servlet.xml index 426d71b60..f04571af4 100644 --- a/webapps/docs/default-servlet.xml +++ b/webapps/docs/default-servlet.xml @@ -111,11 +111,12 @@ directory listings are disabled and debugging is turned off. If you wish to customize your directory listing, you - can use an XSL transformation. This value is an absolute - file name which be used for all directory listings. - This can be overridden per context and/or per directory. See - contextXsltFile and localXsltFile - below. The format of the xml is shown below. + can use an XSL transformation. This value is a relative file name (to + either $CATALINA_BASE/conf/ or $CATALINA_HOME/conf/) which will be used + for all directory listings. This can be overridden per context and/or + per directory. See contextXsltFile and + localXsltFile below. The format of the xml is shown + below. You may also customize your directory listing by context by