From f90819793e4da6c0cc3e7c19d29b48710e29d05b Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 07 2014 16:38:40 +0000 Subject: import tomcat-7.0.42-8.el7_0 --- diff --git a/SOURCES/tomcat-7.0.42-CVE-2013-4590.patch b/SOURCES/tomcat-7.0.42-CVE-2013-4590.patch new file mode 100644 index 0000000..2382995 --- /dev/null +++ b/SOURCES/tomcat-7.0.42-CVE-2013-4590.patch @@ -0,0 +1,3141 @@ +--- java/org/apache/catalina/Context.java.orig 2014-07-21 17:24:05.516400000 -0400 ++++ java/org/apache/catalina/Context.java 2014-07-21 17:46:59.386109000 -0400 +@@ -40,6 +40,7 @@ + import org.apache.catalina.deploy.NamingResources; + import org.apache.catalina.deploy.SecurityConstraint; + import org.apache.catalina.util.CharsetMapper; ++import org.apache.tomcat.InstanceManager; + import org.apache.tomcat.JarScanner; + import org.apache.tomcat.util.http.mapper.Mapper; + +@@ -61,7 +62,7 @@ + *

+ * + * @author Craig R. McClanahan +- * @version $Id: Context.java 1492415 2013-06-12 20:41:33Z markt $ ++ * @version $Id: Context.java 1552258 2013-12-19 09:25:18Z markt $ + */ + + public interface Context extends Container { +@@ -616,70 +617,99 @@ + + + /** +- * Get the server.xml attribute's xmlNamespaceAware. +- * @return true if namespace awareness is enabled. ++ * Will the parsing of web.xml and web-fragment.xml files for this Context ++ * be performed by a namespace aware parser? + * ++ * @return true if namespace awareness is enabled. + */ + public boolean getXmlNamespaceAware(); + ++ ++ /** ++ * Controls whether the parsing of web.xml and web-fragment.xml files for ++ * this Context will be performed by a namespace aware parser. ++ * ++ * @param xmlNamespaceAware true to enable namespace awareness ++ */ ++ public void setXmlNamespaceAware(boolean xmlNamespaceAware); + ++ + /** +- * Get the server.xml attribute's xmlValidation. +- * @return true if validation is enabled. ++ * Will the parsing of web.xml and web-fragment.xml files for this Context ++ * be performed by a validating parser? + * ++ * @return true if validation is enabled. + */ + public boolean getXmlValidation(); + + + /** +- * Set the validation feature of the XML parser used when +- * parsing xml instances. +- * @param xmlValidation true to enable xml instance validation ++ * Controls whether the parsing of web.xml and web-fragment.xml files ++ * for this Context will be performed by a validating parser. ++ * ++ * @param xmlValidation true to enable xml validation + */ + public void setXmlValidation(boolean xmlValidation); + + +- /** +- * Set the namespace aware feature of the XML parser used when +- * parsing xml instances. +- * @param xmlNamespaceAware true to enable namespace awareness ++ /** ++ * *.tld files are always parsed using a namespace aware parser. ++ * ++ * @return Always true ++ * ++ * @deprecated This option will be removed in 8.0.x. + */ +- public void setXmlNamespaceAware(boolean xmlNamespaceAware); ++ @Deprecated ++ public boolean getTldNamespaceAware(); ++ ++ + /** +- * Get the server.xml attribute's xmlValidation. +- * @return true if validation is enabled. ++ * *.tld files are always parsed using a namespace aware parser. ++ * ++ * @param tldNamespaceAware ignored ++ * ++ * @deprecated This option will be removed in 8.0.x. + */ ++ @Deprecated ++ public void setTldNamespaceAware(boolean tldNamespaceAware); + + + /** +- * Set the validation feature of the XML parser used when +- * parsing tlds files. +- * @param tldValidation true to enable xml instance validation ++ * Will the parsing of web.xml, web-fragment.xml, *.tld, *.jspx, *.tagx and ++ * tagplugin.xml files for this Context block the use of external entities? ++ * ++ * @return true if access to external entities is blocked + */ +- public void setTldValidation(boolean tldValidation); ++ public boolean getXmlBlockExternal(); + + + /** +- * Get the server.xml attribute's webXmlValidation. +- * @return true if validation is enabled. ++ * Controls whether the parsing of web.xml, web-fragment.xml, *.tld, *.jspx, ++ * *.tagx and tagplugin.xml files for this Context will block the use of ++ * external entities. + * ++ * @param xmlBlockExternal true to block external entities + */ +- public boolean getTldValidation(); ++ public void setXmlBlockExternal(boolean xmlBlockExternal); + + + /** +- * Get the server.xml <host> attribute's xmlNamespaceAware. +- * @return true if namespace awareness is enabled. ++ * Will the parsing of *.tld files for this Context be performed by a ++ * validating parser? ++ * ++ * @return true if validation is enabled. + */ +- public boolean getTldNamespaceAware(); ++ public boolean getTldValidation(); + + + /** +- * Set the namespace aware feature of the XML parser used when +- * parsing xml instances. +- * @param tldNamespaceAware true to enable namespace awareness ++ * Controls whether the parsing of *.tld files for this Context will be ++ * performed by a validating parser. ++ * ++ * @param tldValidation true to enable xml validation + */ +- public void setTldNamespaceAware(boolean tldNamespaceAware); ++ public void setTldValidation(boolean tldValidation); ++ + + /** + * Get the Jar Scanner to be used to scan for JAR resources for this +@@ -712,6 +742,16 @@ + */ + public boolean getLogEffectiveWebXml(); + ++ /** ++ * Get the instance manager associated with this context. ++ */ ++ public InstanceManager getInstanceManager(); ++ ++ /** ++ * Set the instance manager associated with this context. ++ */ ++ public void setInstanceManager(InstanceManager instanceManager); ++ + // --------------------------------------------------------- Public Methods + + +--- java/org/apache/catalina/Globals.java.orig 2014-07-21 17:24:05.521402000 -0400 ++++ java/org/apache/catalina/Globals.java 2014-07-21 17:46:59.394034000 -0400 +@@ -14,18 +14,14 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +- +- + package org.apache.catalina; + +- + /** + * Global constants that are applicable to multiple packages within Catalina. + * + * @author Craig R. McClanahan +- * @version $Id: Globals.java 1301255 2012-03-15 22:47:40Z markt $ ++ * @version $Id: Globals.java 1549529 2013-12-09 10:05:56Z markt $ + */ +- + public final class Globals { + + /** +@@ -310,4 +306,25 @@ + * the tomcat instance installation path + */ + public static final String CATALINA_BASE_PROP = "catalina.base"; ++ ++ ++ /** ++ * Name of the ServletContext init-param that determines if the JSP engine ++ * should validate *.tld files when parsing them. ++ *

++ * This must be kept in sync with org.apache.jasper.Constants ++ */ ++ public static final String JASPER_XML_VALIDATION_TLD_INIT_PARAM = ++ "org.apache.jasper.XML_VALIDATE_TLD"; ++ ++ ++ /** ++ * Name of the ServletContext init-param that determines if the JSP engine ++ * will block external entities from being used in *.tld, *.jspx, *.tagx and ++ * tagplugin.xml files. ++ *

++ * This must be kept in sync with org.apache.jasper.Constants ++ */ ++ public static final String JASPER_XML_BLOCK_EXTERNAL_INIT_PARAM = ++ "org.apache.jasper.XML_BLOCK_EXTERNAL"; + } +--- java/org/apache/catalina/ant/ValidatorTask.java.orig 2014-07-21 17:24:05.537406000 -0400 ++++ java/org/apache/catalina/ant/ValidatorTask.java 2014-07-21 17:46:59.401034000 -0400 +@@ -14,18 +14,16 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +- +- + package org.apache.catalina.ant; + +- + import java.io.BufferedInputStream; + import java.io.File; + import java.io.FileInputStream; + import java.io.InputStream; + ++import org.apache.catalina.Globals; + import org.apache.catalina.startup.Constants; +-import org.apache.catalina.startup.DigesterFactory; ++import org.apache.tomcat.util.descriptor.DigesterFactory; + import org.apache.tomcat.util.digester.Digester; + import org.apache.tools.ant.BuildException; + import org.xml.sax.InputSource; +@@ -36,7 +34,7 @@ + * schema validation. + * + * @author Remy Maucherat +- * @version $Id: ValidatorTask.java 1001899 2010-09-27 20:24:18Z markt $ ++ * @version $Id: ValidatorTask.java 1549529 2013-12-09 10:05:56Z markt $ + * @since 5.0 + */ + +@@ -90,7 +88,10 @@ + Thread.currentThread().setContextClassLoader + (ValidatorTask.class.getClassLoader()); + +- Digester digester = DigesterFactory.newDigester(true, true, null); ++ // Called through trusted manager interface. If running under a ++ // SecurityManager assume that untrusted applications may be deployed. ++ Digester digester = DigesterFactory.newDigester( ++ true, true, null, Globals.IS_SECURITY_ENABLED); + try { + file = file.getCanonicalFile(); + InputStream stream = +--- java/org/apache/catalina/core/ApplicationContext.java.orig 2014-07-21 17:24:05.543399000 -0400 ++++ java/org/apache/catalina/core/ApplicationContext.java 2014-07-22 16:07:21.579832000 -0400 +@@ -5,9 +5,9 @@ + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at +- * ++ * + * http://www.apache.org/licenses/LICENSE-2.0 +- * ++ * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@@ -84,7 +84,7 @@ + * + * @author Craig R. McClanahan + * @author Remy Maucherat +- * @version $Id: ApplicationContext.java 1493015 2013-06-14 10:00:57Z markt $ ++ * @version $Id: ApplicationContext.java 1549529 2013-12-09 10:05:56Z markt $ + */ + + public class ApplicationContext +@@ -97,7 +97,7 @@ + + static { + STRICT_SERVLET_COMPLIANCE = Globals.STRICT_SERVLET_COMPLIANCE; +- ++ + String requireSlash = System.getProperty( + "org.apache.catalina.core.ApplicationContext.GET_RESOURCE_REQUIRE_SLASH"); + if (requireSlash == null) { +@@ -302,7 +302,7 @@ + } + } + +- ++ + /** + * Return the main path associated with this context. + */ +@@ -310,7 +310,7 @@ + public String getContextPath() { + return context.getPath(); + } +- ++ + + /** + * Return the value of the specified initialization parameter, or +@@ -320,6 +320,20 @@ + */ + @Override + public String getInitParameter(final String name) { ++ // Special handling for XML settings as the context setting must ++ // always override anything that might have been set by an application. ++ if (Globals.JASPER_XML_VALIDATION_TLD_INIT_PARAM.equals(name) && ++ context.getTldValidation()) { ++ return "true"; ++ } ++ if (Globals.JASPER_XML_BLOCK_EXTERNAL_INIT_PARAM.equals(name)) { ++ if (context.getXmlBlockExternal()) { ++ return "true"; ++ } else if (Globals.IS_SECURITY_ENABLED) { ++ // System admin has explicitly changed the default ++ return "false"; ++ } ++ } + return parameters.get(name); + } + +@@ -330,7 +344,17 @@ + */ + @Override + public Enumeration getInitParameterNames() { +- return Collections.enumeration(parameters.keySet()); ++ Set names = new HashSet(); ++ names.addAll(parameters.keySet()); ++ // Special handling for XML settings as these attributes will always be ++ // available if they have been set on the context ++ if (context.getTldValidation()) { ++ names.add(Globals.JASPER_XML_VALIDATION_TLD_INIT_PARAM); ++ } ++ if (context.getXmlBlockExternal() || Globals.IS_SECURITY_ENABLED) { ++ names.add(Globals.JASPER_XML_BLOCK_EXTERNAL_INIT_PARAM); ++ } ++ return Collections.enumeration(names); + } + + +@@ -395,7 +419,7 @@ + Wrapper wrapper = (Wrapper) context.findChild(name); + if (wrapper == null) + return (null); +- ++ + return new ApplicationDispatcher(wrapper, null, null, null, null, name); + + } +@@ -444,7 +468,7 @@ + if (normalizedPath == null) + return (null); + +- pos = normalizedPath.length(); ++ pos = normalizedPath.length(); + + // Use the thread local URI and mapping data + DispatchData dd = dispatchData.get(); +@@ -495,10 +519,10 @@ + String pathInfo = mappingData.pathInfo.toString(); + + mappingData.recycle(); +- ++ + // Construct a RequestDispatcher to process this request + return new ApplicationDispatcher +- (wrapper, uriCC.toString(), wrapperPath, pathInfo, ++ (wrapper, uriCC.toString(), wrapperPath, pathInfo, + queryString, null); + + } +@@ -523,7 +547,7 @@ + !path.startsWith("/") && GET_RESOURCE_REQUIRE_SLASH) + throw new MalformedURLException(sm.getString( + "applicationContext.requestDispatcher.iae", path)); +- ++ + String normPath = RequestUtil.normalize(path); + if (normPath == null) + return (null); +@@ -724,7 +748,7 @@ + @Override + @Deprecated + public void log(Exception exception, String message) { +- ++ + context.getLogger().error(message, exception); + + } +@@ -738,7 +762,7 @@ + */ + @Override + public void log(String message, Throwable throwable) { +- ++ + context.getLogger().error(message, throwable); + + } +@@ -893,11 +917,11 @@ + @Override + public FilterRegistration.Dynamic addFilter(String filterName, + String filterClass) throws IllegalStateException { +- ++ + return addFilter(filterName, filterClass, null); + } + +- ++ + /** + * Add filter to context. + * @param filterName Name of filter to add +@@ -915,11 +939,11 @@ + @Override + public FilterRegistration.Dynamic addFilter(String filterName, + Filter filter) throws IllegalStateException { +- ++ + return addFilter(filterName, null, filter); + } + +- ++ + /** + * Add filter to context. + * @param filterName Name of filter to add +@@ -937,13 +961,13 @@ + @Override + public FilterRegistration.Dynamic addFilter(String filterName, + Class filterClass) throws IllegalStateException { +- ++ + return addFilter(filterName, filterClass.getName(), null); + } + + private FilterRegistration.Dynamic addFilter(String filterName, + String filterClass, Filter filter) throws IllegalStateException { +- ++ + if (filterName == null || filterName.equals("")) { + throw new IllegalArgumentException(sm.getString( + "applicationContext.invalidFilterName", filterName)); +@@ -957,7 +981,7 @@ + } + + FilterDef filterDef = context.findFilterDef(filterName); +- ++ + // Assume a 'complete' FilterRegistration is one that has a class and + // a name + if (filterDef == null) { +@@ -977,14 +1001,15 @@ + filterDef.setFilterClass(filter.getClass().getName()); + filterDef.setFilter(filter); + } +- ++ + return new ApplicationFilterRegistration(filterDef, context); +- } +- ++ } ++ + @Override + public T createFilter(Class c) + throws ServletException { + try { ++ @SuppressWarnings("unchecked") + T filter = (T) context.getInstanceManager().newInstance(c.getName()); + return filter; + } catch (IllegalAccessException e) { +@@ -1011,7 +1036,7 @@ + return new ApplicationFilterRegistration(filterDef, context); + } + +- ++ + /** + * Add servlet to context. + * @param servletName Name of servlet to add +@@ -1029,7 +1054,7 @@ + @Override + public ServletRegistration.Dynamic addServlet(String servletName, + String servletClass) throws IllegalStateException { +- ++ + return addServlet(servletName, servletClass, null); + } + +@@ -1055,7 +1080,7 @@ + return addServlet(servletName, null, servlet); + } + +- ++ + /** + * Add servlet to context. + * @param servletName Name of servlet to add +@@ -1080,7 +1105,7 @@ + + private ServletRegistration.Dynamic addServlet(String servletName, + String servletClass, Servlet servlet) throws IllegalStateException { +- ++ + if (servletName == null || servletName.equals("")) { + throw new IllegalArgumentException(sm.getString( + "applicationContext.invalidServletName", servletName)); +@@ -1092,9 +1117,9 @@ + sm.getString("applicationContext.addServlet.ise", + getContextPath())); + } +- ++ + Wrapper wrapper = (Wrapper) context.findChild(servletName); +- ++ + // Assume a 'complete' ServletRegistration is one that has a class and + // a name + if (wrapper == null) { +@@ -1127,6 +1152,7 @@ + public T createServlet(Class c) + throws ServletException { + try { ++ @SuppressWarnings("unchecked") + T servlet = (T) context.getInstanceManager().newInstance(c.getName()); + context.dynamicServletCreated(servlet); + return servlet; +@@ -1151,10 +1177,10 @@ + if (wrapper == null) { + return null; + } +- ++ + return new ApplicationServletRegistration(wrapper, context); + } +- ++ + + /** + * By default {@link SessionTrackingMode#URL} is always supported, {@link +@@ -1171,15 +1197,15 @@ + + private void populateSessionTrackingModes() { + // URL re-writing is always enabled by default +- defaultSessionTrackingModes = EnumSet.of(SessionTrackingMode.URL); ++ defaultSessionTrackingModes = EnumSet.of(SessionTrackingMode.URL); + supportedSessionTrackingModes = EnumSet.of(SessionTrackingMode.URL); +- ++ + if (context.getCookies()) { + defaultSessionTrackingModes.add(SessionTrackingMode.COOKIE); + supportedSessionTrackingModes.add(SessionTrackingMode.COOKIE); + } + +- // SSL not enabled by default as it can only used on its own ++ // SSL not enabled by default as it can only used on its own + // Context > Host > Engine > Service + Service s = ((Engine) context.getParent().getParent()).getService(); + Connector[] connectors = s.findConnectors(); +@@ -1189,7 +1215,7 @@ + supportedSessionTrackingModes.add(SessionTrackingMode.SSL); + break; + } +- } ++ } + } + + /** +@@ -1226,7 +1252,7 @@ + sm.getString("applicationContext.setSessionTracking.ise", + getContextPath())); + } +- ++ + // Check that only supported tracking modes have been requested + for (SessionTrackingMode sessionTrackingMode : sessionTrackingModes) { + if (!supportedSessionTrackingModes.contains(sessionTrackingMode)) { +@@ -1244,7 +1270,7 @@ + getContextPath())); + } + } +- ++ + this.sessionTrackingModes = sessionTrackingModes; + } + +@@ -1253,8 +1279,8 @@ + public boolean setInitParameter(String name, String value) { + return parameters.putIfAbsent(name, value) == null; + } +- +- ++ ++ + @Override + public void addListener(Class listenerClass) { + EventListener listener; +@@ -1271,7 +1297,7 @@ + + @Override + public void addListener(String className) { +- ++ + try { + Object obj = context.getInstanceManager().newInstance(className); + +@@ -1305,7 +1331,7 @@ + "applicationContext.addListener.iae.cnfe", className), + e); + } +- ++ + } + + +@@ -1325,7 +1351,7 @@ + context.addApplicationEventListener(t); + match = true; + } +- ++ + if (t instanceof HttpSessionListener + || (t instanceof ServletContextListener && + newServletContextListenerAllowed)) { +@@ -1334,9 +1360,9 @@ + context.addApplicationLifecycleListener(t); + match = true; + } +- ++ + if (match) return; +- ++ + if (t instanceof ServletContextListener) { + throw new IllegalArgumentException(sm.getString( + "applicationContext.addListener.iae.sclNotAllowed", +@@ -1353,8 +1379,9 @@ + public T createListener(Class c) + throws ServletException { + try { ++ @SuppressWarnings("unchecked") + T listener = +- (T) context.getInstanceManager().newInstance(c.getName()); ++ (T) context.getInstanceManager().newInstance(c); + if (listener instanceof ServletContextListener || + listener instanceof ServletContextAttributeListener || + listener instanceof ServletRequestListener || +@@ -1375,27 +1402,26 @@ + throw new ServletException(e); + } catch (InstantiationException e) { + throw new ServletException(e); +- } catch (ClassNotFoundException e) { +- throw new ServletException(e); +- } } ++ } ++ } + + + @Override + public void declareRoles(String... roleNames) { +- ++ + if (!context.getState().equals(LifecycleState.STARTING_PREP)) { + //TODO Spec breaking enhancement to ignore this restriction + throw new IllegalStateException( + sm.getString("applicationContext.addRole.ise", + getContextPath())); + } +- ++ + if (roleNames == null) { + throw new IllegalArgumentException( + sm.getString("applicationContext.roles.iae", + getContextPath())); + } +- ++ + for (String role : roleNames) { + if (role == null || "".equals(role)) { + throw new IllegalArgumentException( +@@ -1424,7 +1450,7 @@ + new RuntimePermission("getClassLoader")); + } + } +- ++ + return result; + } + +@@ -1445,7 +1471,7 @@ + public Map getFilterRegistrations() { + Map result = + new HashMap(); +- ++ + FilterDef[] filterDefs = context.findFilterDefs(); + for (FilterDef filterDef : filterDefs) { + result.put(filterDef.getFilterName(), +@@ -1473,7 +1499,7 @@ + public Map getServletRegistrations() { + Map result = + new HashMap(); +- ++ + Container[] wrappers = context.findChildren(); + for (Container wrapper : wrappers) { + result.put(((Wrapper) wrapper).getName(), +@@ -1484,12 +1510,12 @@ + return result; + } + +- ++ + // -------------------------------------------------------- Package Methods + protected StandardContext getContext() { + return this.context; + } +- ++ + @Deprecated + protected Map getReadonlyAttributes() { + return this.readOnlyAttributes; +@@ -1513,10 +1539,10 @@ + String key = keys.next(); + removeAttribute(key); + } +- ++ + } +- +- ++ ++ + /** + * Return the facade associated with this ApplicationContext. + */ +@@ -1541,7 +1567,7 @@ + protected void setNewServletContextListenerAllowed(boolean allowed) { + this.newServletContextListenerAllowed = allowed; + } +- ++ + /** + * List resource paths (recursively), and store all of them in the given + * Set. +@@ -1572,13 +1598,13 @@ + */ + private static String getJNDIUri(String hostName, String path) { + String result; +- ++ + if (path.startsWith("/")) { + result = "/" + hostName + path; + } else { + result = "/" + hostName + "/" + path; + } +- ++ + return result; + } + +--- java/org/apache/catalina/core/StandardContext.java.orig 2014-07-21 17:24:05.568403000 -0400 ++++ java/org/apache/catalina/core/StandardContext.java 2014-07-22 16:08:44.199113000 -0400 +@@ -126,6 +126,7 @@ + import org.apache.tomcat.InstanceManager; + import org.apache.tomcat.JarScanner; + import org.apache.tomcat.util.ExceptionUtils; ++import org.apache.tomcat.util.descriptor.XmlIdentifiers; + import org.apache.tomcat.util.modeler.Registry; + import org.apache.tomcat.util.scan.StandardJarScanner; + +@@ -136,7 +137,7 @@ + * + * @author Craig R. McClanahan + * @author Remy Maucherat +- * @version $Id: StandardContext.java 1493073 2013-06-14 13:51:13Z markt $ ++ * @version $Id: StandardContext.java 1549529 2013-12-09 10:05:56Z markt $ + */ + + public class StandardContext extends ContainerBase +@@ -524,6 +525,12 @@ + + + /** ++ * Context level override for default {@link StandardHost#isCopyXML()}. ++ */ ++ private boolean copyXML = false; ++ ++ ++ /** + * The default context override flag for this web application. + */ + private boolean override = false; +@@ -691,6 +698,13 @@ + protected int cacheMaxSize = 10240; // 10 MB + + ++ ++ /** ++ * Attribute used to turn on/off the use of external entities. ++ */ ++ private boolean xmlBlockExternal = Globals.IS_SECURITY_ENABLED; ++ ++ + /** + * Cache object max size in KB. + */ +@@ -726,7 +740,8 @@ + + + /** +- * Attribute value used to turn on/off XML validation ++ * Attribute value used to turn on/off XML validation for web.xml and ++ * web-fragment.xml files. + */ + private boolean webXmlValidation = Globals.STRICT_SERVLET_COMPLIANCE; + +@@ -748,12 +763,6 @@ + + + /** +- * Attribute value used to turn on/off TLD XML namespace validation +- */ +- private boolean tldNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE; +- +- +- /** + * Should we save the configuration. + */ + private boolean saveConfig = true; +@@ -1055,11 +1064,13 @@ + } + + ++ @Override + public InstanceManager getInstanceManager() { + return instanceManager; + } + + ++ @Override + public void setInstanceManager(InstanceManager instanceManager) { + this.instanceManager = instanceManager; + } +@@ -2463,6 +2474,17 @@ + + } + ++ ++ public boolean getCopyXML() { ++ return copyXML; ++ } ++ ++ ++ public void setCopyXML(boolean copyXML) { ++ this.copyXML = copyXML; ++ } ++ ++ + /** + * Return the Java class name of the Wrapper implementation used + * for servlets registered in this Context. +@@ -4861,7 +4883,7 @@ + ExceptionUtils.handleThrowable(t); + getLogger().error + (sm.getString("standardContext.applicationListener", +- listeners[i]), t); ++ listeners[i].getClassName()), t); + ok = false; + } + } +@@ -5233,8 +5255,7 @@ + } + if (ok) { + if (!resourcesStart()) { +- log.error( "Error in resourceStart()"); +- ok = false; ++ throw new LifecycleException("Error in resourceStart()"); + } + } + +@@ -5822,17 +5843,10 @@ + */ + @Override + public boolean isServlet22() { +- +- if (this.publicId == null) +- return (false); +- if (this.publicId.equals +- (org.apache.catalina.startup.Constants.WebDtdPublicId_22)) +- return (true); +- else +- return (false); +- ++ return XmlIdentifiers.WEB_22_PUBLIC.equals(publicId); + } + ++ + @Override + public Set addServletSecurity( + ApplicationServletRegistration registration, +@@ -5928,7 +5942,7 @@ + if (getResources() == null) + return oldContextClassLoader; + +- if (getLoader().getClassLoader() != null) { ++ if (getLoader() != null && getLoader().getClassLoader() != null) { + Thread.currentThread().setContextClassLoader + (getLoader().getClassLoader()); + } +@@ -6580,72 +6594,67 @@ + + } + +- /** +- * Set the validation feature of the XML parser used when +- * parsing xml instances. +- * @param webXmlValidation true to enable xml instance validation +- */ ++ ++ @Override ++ public boolean getXmlNamespaceAware(){ ++ return webXmlNamespaceAware; ++ } ++ ++ ++ @Override ++ public void setXmlNamespaceAware(boolean webXmlNamespaceAware){ ++ this.webXmlNamespaceAware = webXmlNamespaceAware; ++ } ++ ++ + @Override + public void setXmlValidation(boolean webXmlValidation){ +- + this.webXmlValidation = webXmlValidation; +- + } + +- /** +- * Get the server.xml attribute's xmlValidation. +- * @return true if validation is enabled. +- * +- */ ++ + @Override + public boolean getXmlValidation(){ + return webXmlValidation; + } + + +- /** +- * Get the server.xml attribute's xmlNamespaceAware. +- * @return true if namespace awarenes is enabled. +- */ + @Override +- public boolean getXmlNamespaceAware(){ +- return webXmlNamespaceAware; ++ public boolean getTldNamespaceAware(){ ++ return true; + } + + +- /** +- * Set the namespace aware feature of the XML parser used when +- * parsing xml instances. +- * @param webXmlNamespaceAware true to enable namespace awareness +- */ + @Override +- public void setXmlNamespaceAware(boolean webXmlNamespaceAware){ +- this.webXmlNamespaceAware= webXmlNamespaceAware; ++ public void setTldNamespaceAware(boolean tldNamespaceAware){ ++ // NO-OP; + } + + +- /** +- * Set the validation feature of the XML parser used when +- * parsing tlds files. +- * @param tldValidation true to enable xml instance validation +- */ ++ @Override ++ public void setXmlBlockExternal(boolean xmlBlockExternal) { ++ this.xmlBlockExternal = xmlBlockExternal; ++ } ++ ++ ++ @Override ++ public boolean getXmlBlockExternal() { ++ return xmlBlockExternal; ++ } ++ ++ + @Override + public void setTldValidation(boolean tldValidation){ +- + this.tldValidation = tldValidation; +- + } + +- /** +- * Get the server.xml attribute's webXmlValidation. +- * @return true if validation is enabled. +- * +- */ ++ + @Override + public boolean getTldValidation(){ + return tldValidation; + } + ++ + /** + * Sets the process TLDs attribute. + * +@@ -6655,6 +6664,7 @@ + processTlds = newProcessTlds; + } + ++ + /** + * Returns the processTlds attribute value. + */ +@@ -6662,26 +6672,6 @@ + return processTlds; + } + +- /** +- * Get the server.xml <host> attribute's xmlNamespaceAware. +- * @return true if namespace awarenes is enabled. +- */ +- @Override +- public boolean getTldNamespaceAware(){ +- return tldNamespaceAware; +- } +- +- +- /** +- * Set the namespace aware feature of the XML parser used when +- * parsing xml instances. +- * @param tldNamespaceAware true to enable namespace awareness +- */ +- @Override +- public void setTldNamespaceAware(boolean tldNamespaceAware){ +- this.tldNamespaceAware= tldNamespaceAware; +- } +- + + /** + * Support for "stateManageable" JSR77 +--- java/org/apache/catalina/startup/ContextConfig.java.orig 2014-07-21 17:24:05.574403000 -0400 ++++ java/org/apache/catalina/startup/ContextConfig.java 2014-07-21 17:46:59.422037000 -0400 +@@ -95,6 +95,8 @@ + import org.apache.tomcat.util.bcel.classfile.ElementValue; + import org.apache.tomcat.util.bcel.classfile.ElementValuePair; + import org.apache.tomcat.util.bcel.classfile.JavaClass; ++import org.apache.tomcat.util.descriptor.DigesterFactory; ++import org.apache.tomcat.util.descriptor.XmlErrorHandler; + import org.apache.tomcat.util.digester.Digester; + import org.apache.tomcat.util.digester.RuleSet; + import org.apache.tomcat.util.res.StringManager; +@@ -109,7 +111,7 @@ + * + * @author Craig R. McClanahan + * @author Jean-Francois Arcand +- * @version $Id: ContextConfig.java 1488152 2013-05-31 11:07:18Z kkolinko $ ++ * @version $Id: ContextConfig.java 1549529 2013-12-09 10:05:56Z markt $ + */ + public class ContextConfig implements LifecycleListener { + +@@ -514,14 +516,16 @@ + public void createWebXmlDigester(boolean namespaceAware, + boolean validation) { + ++ boolean blockExternal = context.getXmlBlockExternal(); ++ + webRuleSet = new WebRuleSet(false); + webDigester = DigesterFactory.newDigester(validation, +- namespaceAware, webRuleSet); ++ namespaceAware, webRuleSet, blockExternal); + webDigester.getParser(); + + webFragmentRuleSet = new WebRuleSet(true); + webFragmentDigester = DigesterFactory.newDigester(validation, +- namespaceAware, webFragmentRuleSet); ++ namespaceAware, webFragmentRuleSet, blockExternal); + webFragmentDigester.getParser(); + } + +@@ -710,11 +714,11 @@ + String pathName = cn.getBaseName(); + + boolean unpackWARs = true; +- if (host instanceof StandardHost && +- context instanceof StandardContext) { +- unpackWARs = ((StandardHost) host).isUnpackWARs() && +- ((StandardContext) context).getUnpackWAR() && +- (docBase.startsWith(canonicalAppBase.getPath())); ++ if (host instanceof StandardHost) { ++ unpackWARs = ((StandardHost) host).isUnpackWARs(); ++ if (unpackWARs && context instanceof StandardContext) { ++ unpackWARs = ((StandardContext) context).getUnpackWAR(); ++ } + } + + if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory() && unpackWARs) { +@@ -838,14 +842,6 @@ + + createWebXmlDigester(context.getXmlNamespaceAware(), + context.getXmlValidation()); +- +- try { +- fixDocBase(); +- } catch (IOException e) { +- log.error(sm.getString( +- "contextConfig.fixDocBase", context.getName()), e); +- } +- + } + + +@@ -854,8 +850,14 @@ + */ + protected synchronized void beforeStart() { + +- antiLocking(); ++ try { ++ fixDocBase(); ++ } catch (IOException e) { ++ log.error(sm.getString( ++ "contextConfig.fixDocBase", context.getName()), e); ++ } + ++ antiLocking(); + } + + +@@ -1131,7 +1133,7 @@ + for (int j = 0; j < roles.length; j++) { + if (!"*".equals(roles[j]) && + !context.findSecurityRole(roles[j])) { +- log.info(sm.getString("contextConfig.role.auth", roles[j])); ++ log.warn(sm.getString("contextConfig.role.auth", roles[j])); + context.addSecurityRole(roles[j]); + } + } +@@ -1143,14 +1145,14 @@ + Wrapper wrapper = (Wrapper) wrappers[i]; + String runAs = wrapper.getRunAs(); + if ((runAs != null) && !context.findSecurityRole(runAs)) { +- log.info(sm.getString("contextConfig.role.runas", runAs)); ++ log.warn(sm.getString("contextConfig.role.runas", runAs)); + context.addSecurityRole(runAs); + } + String names[] = wrapper.findSecurityReferences(); + for (int j = 0; j < names.length; j++) { + String link = wrapper.findSecurityReference(names[j]); + if ((link != null) && !context.findSecurityRole(link)) { +- log.info(sm.getString("contextConfig.role.link", link)); ++ log.warn(sm.getString("contextConfig.role.link", link)); + context.addSecurityRole(link); + } + } +@@ -1258,7 +1260,7 @@ + // Step 1. Identify all the JARs packaged with the application + // If the JARs have a web-fragment.xml it will be parsed at this + // point. +- Map fragments = processJarsForWebFragments(); ++ Map fragments = processJarsForWebFragments(webXml); + + // Step 2. Order the fragments. + Set orderedFragments = null; +@@ -1546,7 +1548,7 @@ + URL url = fragment.getURL(); + Jar jar = null; + InputStream is = null; +- ServletContainerInitializer sci = null; ++ List detectedScis = null; + try { + if ("jar".equals(url.getProtocol())) { + jar = JarFactory.newInstance(url); +@@ -1559,7 +1561,7 @@ + } + } + if (is != null) { +- sci = getServletContainerInitializer(is); ++ detectedScis = getServletContainerInitializers(is); + } + } catch (IOException ioe) { + log.error(sm.getString( +@@ -1580,42 +1582,44 @@ + } + } + +- if (sci == null) { ++ if (detectedScis == null) { + continue; + } + +- initializerClassMap.put(sci, new HashSet>()); ++ for (ServletContainerInitializer sci : detectedScis) { ++ initializerClassMap.put(sci, new HashSet>()); + +- HandlesTypes ht = null; +- try { +- ht = sci.getClass().getAnnotation(HandlesTypes.class); +- } catch (Exception e) { +- if (log.isDebugEnabled()) { +- log.info(sm.getString("contextConfig.sci.debug", url), e); +- } else { +- log.info(sm.getString("contextConfig.sci.info", url)); ++ HandlesTypes ht = null; ++ try { ++ ht = sci.getClass().getAnnotation(HandlesTypes.class); ++ } catch (Exception e) { ++ if (log.isDebugEnabled()) { ++ log.info(sm.getString("contextConfig.sci.debug", url), ++ e); ++ } else { ++ log.info(sm.getString("contextConfig.sci.info", url)); ++ } + } +- } +- if (ht != null) { +- Class[] types = ht.value(); +- if (types != null) { +- for (Class type : types) { +- if (type.isAnnotation()) { +- handlesTypesAnnotations = true; +- } else { +- handlesTypesNonAnnotations = true; +- } +- Set scis = +- typeInitializerMap.get(type); +- if (scis == null) { +- scis = new HashSet(); +- typeInitializerMap.put(type, scis); ++ if (ht != null) { ++ Class[] types = ht.value(); ++ if (types != null) { ++ for (Class type : types) { ++ if (type.isAnnotation()) { ++ handlesTypesAnnotations = true; ++ } else { ++ handlesTypesNonAnnotations = true; ++ } ++ Set scis = typeInitializerMap ++ .get(type); ++ if (scis == null) { ++ scis = new HashSet(); ++ typeInitializerMap.put(type, scis); ++ } ++ scis.add(sci); + } +- scis.add(sci); + } + } + } +- + } + } + +@@ -1627,19 +1631,28 @@ + * @return The class name + * @throws IOException + */ +- protected ServletContainerInitializer getServletContainerInitializer( ++ protected List getServletContainerInitializers( + InputStream is) throws IOException { + +- String className = null; ++ List initializers = new ArrayList(); + + if (is != null) { + String line = null; + try { +- BufferedReader br = +- new BufferedReader(new InputStreamReader(is, "UTF-8")); +- line = br.readLine(); +- if (line != null && line.trim().length() > 0) { +- className = line.trim(); ++ BufferedReader br = new BufferedReader(new InputStreamReader( ++ is, "UTF-8")); ++ while ((line = br.readLine()) != null) { ++ line = line.trim(); ++ if (line.length() > 0) { ++ int i = line.indexOf('#'); ++ if (i > -1) { ++ if (i == 0) { ++ continue; ++ } ++ line = line.substring(0, i).trim(); ++ } ++ initializers.add(getServletContainerInitializer(line)); ++ } + } + } catch (UnsupportedEncodingException e) { + // Should never happen with UTF-8 +@@ -1647,11 +1660,16 @@ + } + } + ++ return initializers; ++ } ++ ++ protected ServletContainerInitializer getServletContainerInitializer( ++ String className) throws IOException { + ServletContainerInitializer sci = null; + try { +- Class clazz = Class.forName(className,true, +- context.getLoader().getClassLoader()); +- sci = (ServletContainerInitializer) clazz.newInstance(); ++ Class clazz = Class.forName(className, true, context.getLoader() ++ .getClassLoader()); ++ sci = (ServletContainerInitializer) clazz.newInstance(); + } catch (ClassNotFoundException e) { + log.error(sm.getString("contextConfig.invalidSci", className), e); + throw new IOException(e); +@@ -1923,10 +1941,21 @@ + * + * @return A map of JAR name to processed web fragment (if any) + */ +- protected Map processJarsForWebFragments() { ++ protected Map processJarsForWebFragments(WebXml application) { + + JarScanner jarScanner = context.getJarScanner(); +- FragmentJarScannerCallback callback = new FragmentJarScannerCallback(); ++ ++ boolean parseRequired = true; ++ Set absoluteOrder = application.getAbsoluteOrdering(); ++ if (absoluteOrder != null && absoluteOrder.isEmpty() && ++ !context.getXmlValidation()) { ++ // Skip parsing when there is an empty absolute ordering and ++ // validation is not enabled ++ parseRequired = false; ++ } ++ ++ FragmentJarScannerCallback callback = ++ new FragmentJarScannerCallback(parseRequired); + + jarScanner.scan(context.getServletContext(), + context.getLoader().getClassLoader(), callback, +@@ -2282,6 +2311,12 @@ + } catch (IOException e) { + log.debug(sm.getString("contextConfig.invalidSciHandlesTypes", + className), e); ++ } finally { ++ try { ++ is.close(); ++ } catch (IOException e) { ++ // ignore ++ } + } + } + } +@@ -2650,7 +2685,12 @@ + private static final String FRAGMENT_LOCATION = + "META-INF/web-fragment.xml"; + private Map fragments = new HashMap(); ++ private final boolean parseRequired; + ++ public FragmentJarScannerCallback(boolean parseRequired) { ++ this.parseRequired = parseRequired; ++ } ++ + @Override + public void scan(JarURLConnection jarConn) throws IOException { + +@@ -2662,15 +2702,18 @@ + + try { + jar = JarFactory.newInstance(url); +- is = jar.getInputStream(FRAGMENT_LOCATION); ++ if (parseRequired || context.getXmlValidation()) { ++ is = jar.getInputStream(FRAGMENT_LOCATION); ++ } + + if (is == null) { +- // If there is no web.xml, normal JAR no impact on +- // distributable ++ // If there is no web-fragment.xml to process there is no ++ // impact on distributable + fragment.setDistributable(true); + } else { + InputSource source = new InputSource( +- resourceURL.toString() + "!/" + FRAGMENT_LOCATION); ++ "jar:" + resourceURL.toString() + "!/" + ++ FRAGMENT_LOCATION); + source.setByteStream(is); + parseWebXml(source, fragment, true); + } +--- java/org/apache/catalina/startup/FailedContext.java.orig 2014-07-21 17:24:05.579400000 -0400 ++++ java/org/apache/catalina/startup/FailedContext.java 2014-07-21 17:46:59.429034000 -0400 +@@ -59,6 +59,7 @@ + import org.apache.catalina.util.CharsetMapper; + import org.apache.catalina.util.LifecycleMBeanBase; + import org.apache.juli.logging.Log; ++import org.apache.tomcat.InstanceManager; + import org.apache.tomcat.JarScanner; + import org.apache.tomcat.util.http.mapper.Mapper; + import org.apache.tomcat.util.res.StringManager; +@@ -427,10 +428,15 @@ + @Override + public void setTldValidation(boolean tldValidation) { /* NO-OP */ } + @Override ++ public boolean getXmlBlockExternal() { return true; } ++ @Override ++ public void setXmlBlockExternal(boolean xmlBlockExternal) { /* NO-OP */ } ++ ++ @Override + public boolean getTldValidation() { return false; } + + @Override +- public boolean getTldNamespaceAware() { return false; } ++ public boolean getTldNamespaceAware() { return true; } + @Override + public void setTldNamespaceAware(boolean tldNamespaceAware) { /* NO-OP */ } + +@@ -685,4 +691,10 @@ + + @Override + public Map findPreDestroyMethods() { return null; } ++ ++ @Override ++ public InstanceManager getInstanceManager() { return null; } ++ ++ @Override ++ public void setInstanceManager(InstanceManager instanceManager) { /* NO-OP */ } + } +\ No newline at end of file +--- java/org/apache/catalina/startup/TldConfig.java.orig 2014-07-21 17:24:05.583404000 -0400 ++++ java/org/apache/catalina/startup/TldConfig.java 2014-07-24 12:20:22.130289000 -0400 +@@ -40,6 +40,8 @@ + import org.apache.tomcat.JarScanner; + import org.apache.tomcat.JarScannerCallback; + import org.apache.tomcat.util.ExceptionUtils; ++import org.apache.tomcat.util.descriptor.DigesterFactory; ++import org.apache.tomcat.util.descriptor.XmlErrorHandler; + import org.apache.tomcat.util.digester.Digester; + import org.apache.tomcat.util.res.StringManager; + import org.apache.tomcat.util.scan.Jar; +@@ -83,38 +85,23 @@ + * Create (if necessary) and return a Digester configured to process the + * tld. + */ +- private static Digester createTldDigester(boolean namespaceAware, +- boolean validation) { +- +- Digester digester = null; +- if (!namespaceAware && !validation) { +- if (tldDigesters[0] == null) { +- tldDigesters[0] = DigesterFactory.newDigester(validation, +- namespaceAware, new TldRuleSet()); +- tldDigesters[0].getParser(); +- } +- digester = tldDigesters[0]; +- } else if (!namespaceAware && validation) { +- if (tldDigesters[1] == null) { +- tldDigesters[1] = DigesterFactory.newDigester(validation, +- namespaceAware, new TldRuleSet()); +- tldDigesters[1].getParser(); +- } +- digester = tldDigesters[1]; +- } else if (namespaceAware && !validation) { +- if (tldDigesters[2] == null) { +- tldDigesters[2] = DigesterFactory.newDigester(validation, +- namespaceAware, new TldRuleSet()); +- tldDigesters[2].getParser(); +- } +- digester = tldDigesters[2]; +- } else { +- if (tldDigesters[3] == null) { +- tldDigesters[3] = DigesterFactory.newDigester(validation, +- namespaceAware, new TldRuleSet()); +- tldDigesters[3].getParser(); +- } +- digester = tldDigesters[3]; ++ private static synchronized Digester createTldDigester(boolean validation, ++ boolean blockExternal) { ++ ++ Digester digester; ++ int cacheIndex = 0; ++ if (validation) { ++ cacheIndex += 1; ++ } ++ if (blockExternal) { ++ cacheIndex += 2; ++ } ++ digester = tldDigesters[cacheIndex]; ++ if (digester == null) { ++ digester = DigesterFactory.newDigester(validation, ++ true, new TldRuleSet(), blockExternal); ++ digester.getParser(); ++ tldDigesters[cacheIndex] = digester; + } + return digester; + } +@@ -155,7 +142,10 @@ + } + StringTokenizer tokenizer = new StringTokenizer(jarNames, ","); + while (tokenizer.hasMoreElements()) { +- noTldJars.add(tokenizer.nextToken()); ++ String token = tokenizer.nextToken().trim(); ++ if (token.length() > 0) { ++ noTldJars.add(token); ++ } + } + } + } +@@ -354,10 +344,15 @@ + try { + stream = context.getServletContext().getResourceAsStream( + resourcePath); +- XmlErrorHandler handler = tldScanStream(stream); +- handler.logFindings(log, resourcePath); +- taglibUris.add(descriptor.getTaglibURI()); +- webxmlTaglibUris.add(descriptor.getTaglibURI()); ++ if (stream != null) { ++ XmlErrorHandler handler = tldScanStream(stream); ++ handler.logFindings(log, resourcePath); ++ taglibUris.add(descriptor.getTaglibURI()); ++ webxmlTaglibUris.add(descriptor.getTaglibURI()); ++ } else { ++ log.warn(sm.getString("tldConfig.webxmlFailPathDoesNotExist", resourcePath, ++ descriptor.getTaglibURI())); ++ } + } catch (IOException ioe) { + log.warn(sm.getString("tldConfig.webxmlFail", resourcePath, + descriptor.getTaglibURI()), ioe); +@@ -580,8 +575,8 @@ + + private void init() { + if (tldDigester == null){ +- tldDigester = createTldDigester(context.getTldNamespaceAware(), +- context.getTldValidation()); ++ tldDigester = createTldDigester(context.getTldValidation(), ++ context.getXmlBlockExternal()); + } + } + +--- java/org/apache/jasper/Constants.java.orig 2014-07-21 17:24:05.588400000 -0400 ++++ java/org/apache/jasper/Constants.java 2014-07-21 17:46:59.443034000 -0400 +@@ -14,14 +14,12 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +- + package org.apache.jasper; + + import java.util.Arrays; + import java.util.Collections; + import java.util.List; + +- + /** + * Some constants and other global data that are used by the compiler and the runtime. + * +@@ -233,4 +231,23 @@ + */ + public static final String TLD_JAR_SKIP_PROP= + "org.apache.catalina.startup.TldConfig.jarsToSkip"; ++ ++ ++ /** ++ * Name of the ServletContext init-param that determines if the XML parsers ++ * used for *.tld files will be validating or not. ++ *

++ * This must be kept in sync with org.apache.catalina.Globals ++ */ ++ public static final String XML_VALIDATION_TLD_INIT_PARAM = ++ "org.apache.jasper.XML_VALIDATE_TLD"; ++ ++ /** ++ * Name of the ServletContext init-param that determines if the XML parsers ++ * will block the resolution of external entities. ++ *

++ * This must be kept in sync with org.apache.catalina.Globals ++ */ ++ public static final String XML_BLOCK_EXTERNAL_INIT_PARAM = ++ "org.apache.jasper.XML_BLOCK_EXTERNAL"; + } +--- java/org/apache/jasper/JspC.java.orig 2014-07-21 17:24:05.593406000 -0400 ++++ java/org/apache/jasper/JspC.java 2014-07-21 17:46:59.450034000 -0400 +@@ -126,6 +126,8 @@ + protected static final String SWITCH_ENCODING = "-javaEncoding"; + protected static final String SWITCH_SMAP = "-smap"; + protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; ++ protected static final String SWITCH_VALIDATE_TLD = "-validateTld"; ++ protected static final String SWITCH_BLOCK_EXTERNAL = "-blockExternal"; + protected static final String SHOW_SUCCESS ="-s"; + protected static final String LIST_ERRORS = "-l"; + protected static final int INC_WEBXML = 10; +@@ -156,6 +158,8 @@ + protected URLClassLoader loader = null; + protected boolean trimSpaces = false; + protected boolean genStringAsCharArray = false; ++ protected boolean validateTld; ++ protected boolean blockExternal; + protected boolean xpoweredBy; + protected boolean mappedFile = false; + protected boolean poolingEnabled = true; +@@ -363,6 +367,10 @@ + smapSuppressed = false; + } else if (tok.equals(SWITCH_DUMP_SMAP)) { + smapDumped = true; ++ } else if (tok.equals(SWITCH_VALIDATE_TLD)) { ++ setValidateTld(true); ++ } else if (tok.equals(SWITCH_BLOCK_EXTERNAL)) { ++ setBlockExternal(true); + } else { + if (tok.startsWith("-")) { + throw new JasperException("Unrecognized option: " + tok + +@@ -842,8 +850,20 @@ + } + } + +- public void setValidateXml( boolean b ) { +- org.apache.jasper.xmlparser.ParserUtils.validating=b; ++ public void setValidateTld( boolean b ) { ++ this.validateTld = b; ++ } ++ ++ public boolean isValidateTld() { ++ return validateTld; ++ } ++ ++ public void setBlockExternal( boolean b ) { ++ this.blockExternal = b; ++ } ++ ++ public boolean isBlockExternal() { ++ return blockExternal; + } + + public void setListErrors( boolean b ) { +@@ -1257,8 +1277,6 @@ + + /** + * Executes the compilation. +- * +- * @throws JasperException If an error occurs + */ + @Override + public void execute() { +@@ -1426,6 +1444,13 @@ + } catch (MalformedURLException me) { + System.out.println("**" + me); + } ++ if (isValidateTld()) { ++ context.setInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM, "true"); ++ } ++ if (isBlockExternal()) { ++ context.setInitParameter(Constants.XML_BLOCK_EXTERNAL_INIT_PARAM, "true"); ++ } ++ + rctxt = new JspRuntimeContext(context, this); + jspConfig = new JspConfig(context); + tagPluginManager = new TagPluginManager(context); +--- java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java.orig 2014-07-21 17:24:05.597404000 -0400 ++++ java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java 2014-07-21 17:46:59.457040000 -0400 +@@ -14,7 +14,6 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +- + package org.apache.jasper.compiler; + + import java.io.InputStream; +@@ -24,11 +23,13 @@ + import java.util.Set; + import java.util.Vector; + ++import javax.servlet.ServletContext; + import javax.servlet.jsp.tagext.FunctionInfo; + import javax.servlet.jsp.tagext.TagFileInfo; + import javax.servlet.jsp.tagext.TagInfo; + import javax.servlet.jsp.tagext.TagLibraryInfo; + ++import org.apache.jasper.Constants; + import org.apache.jasper.JasperException; + import org.apache.jasper.JspCompilationContext; + import org.apache.jasper.util.ExceptionUtils; +@@ -124,7 +125,21 @@ + pi.addDependant(path, ctxt.getLastModified(path)); + } + +- ParserUtils pu = new ParserUtils(); ++ ServletContext servletContext = ctxt.getServletContext(); ++ boolean validate = Boolean.parseBoolean( ++ servletContext.getInitParameter( ++ Constants.XML_VALIDATION_TLD_INIT_PARAM)); ++ String blockExternalString = ++ servletContext.getInitParameter( ++ Constants.XML_BLOCK_EXTERNAL_INIT_PARAM); ++ boolean blockExternal; ++ if (blockExternalString == null) { ++ blockExternal = Constants.IS_SECURITY_ENABLED; ++ } else { ++ blockExternal = Boolean.parseBoolean(blockExternalString); ++ } ++ ++ ParserUtils pu = new ParserUtils(validate, blockExternal); + TreeNode tld = pu.parseXMLDocument(uri, in); + + if (tld.findAttribute("version") != null) { +--- java/org/apache/jasper/compiler/JspConfig.java.orig 2014-07-21 17:24:05.605401000 -0400 ++++ java/org/apache/jasper/compiler/JspConfig.java 2014-07-21 17:46:59.469055000 -0400 +@@ -22,6 +22,7 @@ + + import javax.servlet.ServletContext; + ++import org.apache.jasper.Constants; + import org.apache.jasper.JasperException; + import org.apache.jasper.xmlparser.ParserUtils; + import org.apache.jasper.xmlparser.TreeNode; +@@ -77,9 +78,20 @@ + try { + webXml = new WebXml(ctxt); + ++ boolean validate = Boolean.parseBoolean( ++ ctxt.getInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM)); ++ String blockExternalString = ++ ctxt.getInitParameter(Constants.XML_BLOCK_EXTERNAL_INIT_PARAM); ++ boolean blockExternal; ++ if (blockExternalString == null) { ++ blockExternal = Constants.IS_SECURITY_ENABLED; ++ } else { ++ blockExternal = Boolean.parseBoolean(blockExternalString); ++ } ++ + TreeNode webApp = null; + if (webXml.getInputSource() != null) { +- ParserUtils pu = new ParserUtils(); ++ ParserUtils pu = new ParserUtils(validate, blockExternal); + webApp = pu.parseXMLDocument(webXml.getSystemId(), + webXml.getInputSource()); + } +--- java/org/apache/jasper/compiler/JspDocumentParser.java.orig 2014-07-21 17:24:05.610399000 -0400 ++++ java/org/apache/jasper/compiler/JspDocumentParser.java 2014-07-21 17:46:59.476041000 -0400 +@@ -5,9 +5,9 @@ + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at +- * ++ * + * http://www.apache.org/licenses/LICENSE-2.0 +- * ++ * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@@ -30,17 +30,20 @@ + import javax.xml.parsers.SAXParser; + import javax.xml.parsers.SAXParserFactory; + ++import org.apache.jasper.Constants; + import org.apache.jasper.JasperException; + import org.apache.jasper.JspCompilationContext; ++import org.apache.tomcat.util.descriptor.DigesterFactory; ++import org.apache.tomcat.util.descriptor.LocalResolver; + import org.xml.sax.Attributes; + import org.xml.sax.InputSource; + import org.xml.sax.Locator; + import org.xml.sax.SAXException; + import org.xml.sax.SAXParseException; + import org.xml.sax.XMLReader; +-import org.xml.sax.ext.LexicalHandler; ++import org.xml.sax.ext.DefaultHandler2; ++import org.xml.sax.ext.EntityResolver2; + import org.xml.sax.helpers.AttributesImpl; +-import org.xml.sax.helpers.DefaultHandler; + + /** + * Class implementing a parser for a JSP document, that is, a JSP page in XML +@@ -51,8 +54,8 @@ + */ + + class JspDocumentParser +- extends DefaultHandler +- implements LexicalHandler, TagConstants { ++ extends DefaultHandler2 ++ implements TagConstants { + + private static final String LEXICAL_HANDLER_PROPERTY = + "http://xml.org/sax/properties/lexical-handler"; +@@ -71,7 +74,7 @@ + * Outermost (in the nesting hierarchy) node whose body is declared to be + * scriptless. If a node's body is declared to be scriptless, all its + * nested nodes must be scriptless, too. +- */ ++ */ + private Node scriptlessBodyNode; + + private Locator locator; +@@ -92,6 +95,7 @@ + private boolean inDTD; + + private boolean isValidating; ++ private final EntityResolver2 entityResolver; + + private ErrorDispatcher err; + private boolean isTagFile; +@@ -120,6 +124,20 @@ + this.isTagFile = isTagFile; + this.directivesOnly = directivesOnly; + this.isTop = true; ++ ++ String blockExternalString = ctxt.getServletContext().getInitParameter( ++ Constants.XML_BLOCK_EXTERNAL_INIT_PARAM); ++ boolean blockExternal; ++ if (blockExternalString == null) { ++ blockExternal = Constants.IS_SECURITY_ENABLED; ++ } else { ++ blockExternal = Boolean.parseBoolean(blockExternalString); ++ } ++ ++ this.entityResolver = new LocalResolver( ++ DigesterFactory.SERVLET_API_PUBLIC_IDS, ++ DigesterFactory.SERVLET_API_SYSTEM_IDS, ++ blockExternal); + } + + /* +@@ -162,6 +180,8 @@ + jspDocParser.isTop = false; + } + ++ jspDocParser.isValidating = false; ++ + // Parse the input + SAXParser saxParser = getSAXParser(false, jspDocParser); + InputStream inStream = null; +@@ -238,11 +258,34 @@ + } + } + ++ ++ @Override ++ public InputSource getExternalSubset(String name, String baseURI) ++ throws SAXException, IOException { ++ return entityResolver.getExternalSubset(name, baseURI); ++ } ++ ++ ++ ++ @Override ++ public InputSource resolveEntity(String publicId, String systemId) ++ throws SAXException, IOException { ++ return entityResolver.resolveEntity(publicId, systemId); ++ } ++ ++ ++ @Override ++ public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) ++ throws SAXException, IOException { ++ return entityResolver.resolveEntity(name, publicId, baseURI, systemId); ++ } ++ ++ + /* + * Receives notification of the start of an element. + * + * This method assigns the given tag attributes to one of 3 buckets: +- * ++ * + * - "xmlns" attributes that represent (standard or custom) tag libraries. + * - "xmlns" attributes that do not represent tag libraries. + * - all remaining attributes. +@@ -272,11 +315,8 @@ + return; + } + +- String currentPrefix = getPrefix(current.getQName()); +- + // jsp:text must not have any subelements +- if (JSP_URI.equals(uri) && TEXT_ACTION.equals(current.getLocalName()) +- && "jsp".equals(currentPrefix)) { ++ if (current instanceof Node.JspText) { + throw new SAXParseException( + Localizer.getMessage("jsp.error.text.has_subelement"), + locator); +@@ -288,7 +328,7 @@ + if (attrs != null) { + /* + * Notice that due to a bug in the underlying SAX parser, the +- * attributes must be enumerated in descending order. ++ * attributes must be enumerated in descending order. + */ + boolean isTaglib = false; + for (int i = attrs.getLength() - 1; i >= 0; i--) { +@@ -437,7 +477,7 @@ + * invoke this method with chunks of it. This is a problem when we try + * to determine if the text contains only whitespaces, or when we are + * looking for an EL expression string. Therefore it is necessary to +- * buffer and concatenate the chunks and process the concatenated text ++ * buffer and concatenate the chunks and process the concatenated text + * later (at beginTag and endTag) + * + * @param buf The characters +@@ -670,7 +710,7 @@ + if (!(child instanceof Node.NamedAttribute)) { + throw new SAXParseException(Localizer.getMessage( + "jasper.error.emptybodycontent.nonempty", +- current.qName), locator); ++ current.qName), locator); + } + } + } +@@ -785,7 +825,7 @@ + } + + /* +- * Receives notification of the start of a Namespace mapping. ++ * Receives notification of the start of a Namespace mapping. + */ + @Override + public void startPrefixMapping(String prefix, String uri) +@@ -795,7 +835,7 @@ + if (directivesOnly && !(JSP_URI.equals(uri))) { + return; + } +- ++ + try { + taglibInfo = getTaglibInfo(prefix, uri); + } catch (JasperException je) { +@@ -816,7 +856,7 @@ + } + + /* +- * Receives notification of the end of a Namespace mapping. ++ * Receives notification of the end of a Namespace mapping. + */ + @Override + public void endPrefixMapping(String prefix) throws SAXException { +@@ -1425,17 +1465,25 @@ + throws Exception { + + SAXParserFactory factory = SAXParserFactory.newInstance(); +- factory.setNamespaceAware(true); + ++ factory.setNamespaceAware(true); + // Preserve xmlns attributes + factory.setFeature( + "http://xml.org/sax/features/namespace-prefixes", + true); ++ + factory.setValidating(validating); +- //factory.setFeature( +- // "http://xml.org/sax/features/validation", +- // validating); +- ++ if (validating) { ++ // Enable DTD validation ++ factory.setFeature( ++ "http://xml.org/sax/features/validation", ++ true); ++ // Enable schema validation ++ factory.setFeature( ++ "http://apache.org/xml/features/validation/schema", ++ true); ++ } ++ + // Configure the parser + SAXParser saxParser = factory.newSAXParser(); + XMLReader xmlReader = saxParser.getXMLReader(); +--- java/org/apache/jasper/compiler/TagLibraryInfoImpl.java.orig 2014-07-21 17:24:05.614400000 -0400 ++++ java/org/apache/jasper/compiler/TagLibraryInfoImpl.java 2014-07-21 17:46:59.483050000 -0400 +@@ -31,6 +31,7 @@ + import java.util.Map; + import java.util.Vector; + ++import javax.servlet.ServletContext; + import javax.servlet.jsp.tagext.FunctionInfo; + import javax.servlet.jsp.tagext.PageData; + import javax.servlet.jsp.tagext.TagAttributeInfo; +@@ -43,6 +44,7 @@ + import javax.servlet.jsp.tagext.ValidationMessage; + import javax.servlet.jsp.tagext.VariableInfo; + ++import org.apache.jasper.Constants; + import org.apache.jasper.JasperException; + import org.apache.jasper.JspCompilationContext; + import org.apache.jasper.util.ExceptionUtils; +@@ -212,8 +214,20 @@ + Vector tagFileVector = new Vector(); + Hashtable functionTable = new Hashtable(); + ++ ServletContext servletContext = ctxt.getServletContext(); ++ boolean validate = Boolean.parseBoolean(servletContext.getInitParameter( ++ Constants.XML_VALIDATION_TLD_INIT_PARAM)); ++ String blockExternalString = servletContext.getInitParameter( ++ Constants.XML_BLOCK_EXTERNAL_INIT_PARAM); ++ boolean blockExternal; ++ if (blockExternalString == null) { ++ blockExternal = Constants.IS_SECURITY_ENABLED; ++ } else { ++ blockExternal = Boolean.parseBoolean(blockExternalString); ++ } ++ + // Create an iterator over the child elements of our element +- ParserUtils pu = new ParserUtils(); ++ ParserUtils pu = new ParserUtils(validate, blockExternal); + TreeNode tld = pu.parseXMLDocument(uri, in); + + // Check to see if the root element contains a 'version' +--- java/org/apache/jasper/compiler/TagPluginManager.java.orig 2014-07-21 17:24:05.619399000 -0400 ++++ java/org/apache/jasper/compiler/TagPluginManager.java 2014-07-21 17:46:59.492036000 -0400 +@@ -5,9 +5,9 @@ + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at +- * ++ * + * http://www.apache.org/licenses/LICENSE-2.0 +- * ++ * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@@ -25,6 +25,7 @@ + + import javax.servlet.ServletContext; + ++import org.apache.jasper.Constants; + import org.apache.jasper.JasperException; + import org.apache.jasper.compiler.tagplugin.TagPlugin; + import org.apache.jasper.compiler.tagplugin.TagPluginContext; +@@ -45,7 +46,6 @@ + private boolean initialized = false; + private HashMap tagPlugins = null; + private ServletContext ctxt; +- private PageInfo pageInfo; + + public TagPluginManager(ServletContext ctxt) { + this.ctxt = ctxt; +@@ -59,19 +59,9 @@ + return; + } + +- this.pageInfo = pageInfo; +- +- page.visit(new Node.Visitor() { +- @Override +- public void visit(Node.CustomTag n) +- throws JasperException { +- invokePlugin(n); +- visitBody(n); +- } +- }); +- ++ page.visit(new NodeVisitor(this, pageInfo)); + } +- ++ + private void init(ErrorDispatcher err) throws JasperException { + if (initialized) + return; +@@ -130,8 +120,18 @@ + private void loadTagPlugins(ErrorDispatcher err, InputStream is) + throws JasperException { + +- TreeNode root = +- (new ParserUtils()).parseXMLDocument(TAG_PLUGINS_XML, is); ++ String blockExternalString = ctxt.getInitParameter( ++ Constants.XML_BLOCK_EXTERNAL_INIT_PARAM); ++ boolean blockExternal; ++ if (blockExternalString == null) { ++ blockExternal = Constants.IS_SECURITY_ENABLED; ++ } else { ++ blockExternal = Boolean.parseBoolean(blockExternalString); ++ } ++ ++ ParserUtils pu = new ParserUtils(false, blockExternal); ++ ++ TreeNode root = pu.parseXMLDocument(TAG_PLUGINS_XML, is); + if (root == null) { + return; + } +@@ -175,12 +175,12 @@ + } + + /** +- * Invoke tag plugin for the given custom tag, if a plugin exists for ++ * Invoke tag plugin for the given custom tag, if a plugin exists for + * the custom tag's tag handler. + * + * The given custom tag node will be manipulated by the plugin. + */ +- private void invokePlugin(Node.CustomTag n) { ++ private void invokePlugin(Node.CustomTag n, PageInfo pageInfo) { + TagPlugin tagPlugin = tagPlugins.get(n.getTagHandlerClass().getName()); + if (tagPlugin == null) { + return; +@@ -191,8 +191,24 @@ + tagPlugin.doTag(tagPluginContext); + } + +- static class TagPluginContextImpl implements TagPluginContext { +- private Node.CustomTag node; ++ private static class NodeVisitor extends Node.Visitor { ++ private final TagPluginManager manager; ++ private final PageInfo pageInfo; ++ ++ public NodeVisitor(TagPluginManager manager, PageInfo pageInfo) { ++ this.manager = manager; ++ this.pageInfo = pageInfo; ++ } ++ ++ @Override ++ public void visit(Node.CustomTag n) throws JasperException { ++ manager.invokePlugin(n, pageInfo); ++ visitBody(n); ++ } ++ } ++ ++ private static class TagPluginContextImpl implements TagPluginContext { ++ private final Node.CustomTag node; + private Node.Nodes curNodes; + private PageInfo pageInfo; + private HashMap pluginAttributes; +@@ -291,7 +307,7 @@ + + @Override + public void generateBody() { +- // Since we'll generate the body anyway, this is really a nop, ++ // Since we'll generate the body anyway, this is really a nop, + // except for the fact that it lets us put the Java sources the + // plugins produce in the correct order (w.r.t the body). + curNodes = node.getAtETag(); +--- java/org/apache/jasper/compiler/TldLocationsCache.java.orig 2014-07-21 17:24:05.623404000 -0400 ++++ java/org/apache/jasper/compiler/TldLocationsCache.java 2014-07-21 17:46:59.500034000 -0400 +@@ -286,9 +286,23 @@ + return; + } + ++ boolean validate = Boolean.parseBoolean( ++ ctxt.getInitParameter( ++ Constants.XML_VALIDATION_TLD_INIT_PARAM)); ++ String blockExternalString = ctxt.getInitParameter( ++ Constants.XML_BLOCK_EXTERNAL_INIT_PARAM); ++ boolean blockExternal; ++ if (blockExternalString == null) { ++ blockExternal = Constants.IS_SECURITY_ENABLED; ++ } else { ++ blockExternal = Boolean.parseBoolean(blockExternalString); ++ } ++ + // Parse the web application deployment descriptor ++ ParserUtils pu = new ParserUtils(validate, blockExternal); ++ + TreeNode webtld = null; +- webtld = new ParserUtils().parseXMLDocument(webXml.getSystemId(), ++ webtld = pu.parseXMLDocument(webXml.getSystemId(), + webXml.getInputSource()); + + // Allow taglib to be an element of the root or jsp-config (JSP2.0) +@@ -491,8 +505,20 @@ + // Parse the tag library descriptor at the specified resource path + String uri = null; + +- TreeNode tld = +- new ParserUtils().parseXMLDocument(resourcePath, stream); ++ boolean validate = Boolean.parseBoolean( ++ ctxt.getInitParameter( ++ Constants.XML_VALIDATION_TLD_INIT_PARAM)); ++ String blockExternalString = ctxt.getInitParameter( ++ Constants.XML_BLOCK_EXTERNAL_INIT_PARAM); ++ boolean blockExternal; ++ if (blockExternalString == null) { ++ blockExternal = Constants.IS_SECURITY_ENABLED; ++ } else { ++ blockExternal = Boolean.parseBoolean(blockExternalString); ++ } ++ ++ ParserUtils pu = new ParserUtils(validate, blockExternal); ++ TreeNode tld = pu.parseXMLDocument(resourcePath, stream); + TreeNode uriNode = tld.findChild("uri"); + if (uriNode != null) { + String body = uriNode.getBody(); +--- java/org/apache/jasper/xmlparser/ParserUtils.java.orig 2014-07-21 17:24:05.628407000 -0400 ++++ java/org/apache/jasper/xmlparser/ParserUtils.java 2014-07-21 17:46:59.508034000 -0400 +@@ -14,7 +14,6 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +- + package org.apache.jasper.xmlparser; + + import java.io.IOException; +@@ -27,8 +26,9 @@ + import org.apache.jasper.Constants; + import org.apache.jasper.JasperException; + import org.apache.jasper.compiler.Localizer; +-import org.apache.juli.logging.Log; +-import org.apache.juli.logging.LogFactory; ++import org.apache.tomcat.util.descriptor.DigesterFactory; ++import org.apache.tomcat.util.descriptor.LocalResolver; ++import org.apache.tomcat.util.descriptor.XmlErrorHandler; + import org.w3c.dom.Comment; + import org.w3c.dom.Document; + import org.w3c.dom.NamedNodeMap; +@@ -48,24 +48,38 @@ + * use a separate class loader for the parser to be used. + * + * @author Craig R. McClanahan +- * @version $Id: ParserUtils.java 1301227 2012-03-15 21:59:06Z markt $ ++ * @version $Id: ParserUtils.java 1549529 2013-12-09 10:05:56Z markt $ + */ +- + public class ParserUtils { + + /** + * An error handler for use when parsing XML documents. + */ +- static ErrorHandler errorHandler = new MyErrorHandler(); ++ static ErrorHandler errorHandler = new XmlErrorHandler(); + + /** + * An entity resolver for use when parsing XML documents. + */ +- static EntityResolver entityResolver = new MyEntityResolver(); +- +- // Turn off for JSP 2.0 until switch over to using xschema. +- public static boolean validating = false; +- ++ static EntityResolver entityResolver; ++ ++ private final EntityResolver entityResolverInstance; ++ ++ private final boolean validating; ++ ++ public ParserUtils(boolean validating) { ++ this(validating, Constants.IS_SECURITY_ENABLED); ++ } ++ ++ public ParserUtils(boolean validating, boolean blockExternal) { ++ this.validating = validating; ++ if (entityResolver == null) { ++ this.entityResolverInstance = new LocalResolver( ++ DigesterFactory.SERVLET_API_PUBLIC_IDS, ++ DigesterFactory.SERVLET_API_SYSTEM_IDS, blockExternal); ++ } else { ++ this.entityResolverInstance = entityResolver; ++ } ++ } + + // --------------------------------------------------------- Public Methods + +@@ -91,7 +105,7 @@ + factory.setNamespaceAware(true); + factory.setValidating(validating); + DocumentBuilder builder = factory.newDocumentBuilder(); +- builder.setEntityResolver(entityResolver); ++ builder.setEntityResolver(entityResolverInstance); + builder.setErrorHandler(errorHandler); + document = builder.parse(is); + } catch (ParserConfigurationException ex) { +@@ -196,56 +210,3 @@ + return (treeNode); + } + } +- +- +-// ------------------------------------------------------------ Private Classes +- +-class MyEntityResolver implements EntityResolver { +- +- @Override +- public InputSource resolveEntity(String publicId, String systemId) +- throws SAXException { +- for (int i = 0; i < Constants.CACHED_DTD_PUBLIC_IDS.size(); i++) { +- String cachedDtdPublicId = Constants.CACHED_DTD_PUBLIC_IDS.get(i); +- if (cachedDtdPublicId.equals(publicId)) { +- String resourcePath = +- Constants.CACHED_DTD_RESOURCE_PATHS.get(i); +- InputStream input = this.getClass().getResourceAsStream( +- resourcePath); +- if (input == null) { +- throw new SAXException(Localizer.getMessage( +- "jsp.error.internal.filenotfound", resourcePath)); +- } +- InputSource isrc = new InputSource(input); +- return isrc; +- } +- } +- Log log = LogFactory.getLog(MyEntityResolver.class); +- if (log.isDebugEnabled()) +- log.debug("Resolve entity failed" + publicId + " " + systemId); +- log.error(Localizer.getMessage("jsp.error.parse.xml.invalidPublicId", +- publicId)); +- return null; +- } +-} +- +-class MyErrorHandler implements ErrorHandler { +- +- @Override +- public void warning(SAXParseException ex) throws SAXException { +- Log log = LogFactory.getLog(MyErrorHandler.class); +- if (log.isDebugEnabled()) +- log.debug("ParserUtils: warning ", ex); +- // We ignore warnings +- } +- +- @Override +- public void error(SAXParseException ex) throws SAXException { +- throw ex; +- } +- +- @Override +- public void fatalError(SAXParseException ex) throws SAXException { +- throw ex; +- } +-} +--- webapps/docs/changelog.xml.orig 2014-07-22 17:42:18.576034000 -0400 ++++ webapps/docs/changelog.xml 2014-07-22 18:48:34.775453000 -0400 +@@ -58,6 +58,12 @@ +

+ + ++ ++ Add an option to the Context to control the blocking of XML external ++ entities when parsing XML configuration files and enable this blocking ++ by default when a security manager is used. The block is implemented via ++ a custom resolver to enable the logging of any blocked entities. (markt) ++ + + CVE-2014-0099, Fix overflow when parsing long values from + byte array. (markt) Patch applied by Red Hat Jun 16 2014 +--- webapps/docs/config/context.xml.orig 2014-07-21 17:24:05.643402000 -0400 ++++ webapps/docs/config/context.xml 2014-07-21 17:46:59.530037000 -0400 +@@ -448,6 +448,14 @@ + useful for portlet specification implementations) set this attribute to + / in the global CATALINA_BASE/conf/context.xml + file.

++

Note: Once one web application using ++ sessionCookiePath="/" obtains a session, all ++ subsequent sessions for any other web application in the same host also ++ configured with sessionCookiePath="/" will always ++ use the same session ID. This holds even if the session is invalidated ++ and a new one created. This makes session fixation protection more ++ difficult and requires custom, Tomcat specific code to change the ++ session ID shared by the multiple applications.

+ + + +@@ -493,18 +501,6 @@ + of the flag is false.

+
+ +- +-

If the value of this flag is true, the TLD files +- XML validation will be namespace-aware. If you turn this flag on, +- you should probably also turn tldValidation on. If the +- org.apache.catalina.STRICT_SERVLET_COMPLIANCE +- system property is set to +- true, the default value of this attribute will be +- true, else the default value will be false. +- Setting this attribute to true will incur a performance +- penalty.

+-
+- + +

If the value of this flag is true, the TLD files + will be XML validated on context startup. If the +@@ -528,11 +524,26 @@ + Context. If not specified, a standard default value will be used.

+
+ ++ ++

If the value of this flag is true, the parsing of ++ web.xml, web-fragment.xml, *.tld, ++ *.jspx, *.tagx and tagPlugins.xml ++ files for this web application will not permit external entities to be ++ loaded. If a SecurityManager is configured then the default ++ value of this attribute will be true, else the default ++ value will be false.

++
++ + +-

If the value of this flag is true, the validation of +- XML files will be namespace-aware. If you turn this flag on, +- you should probably also turn xmlValidation on. If +- the org.apache.catalina.STRICT_SERVLET_COMPLIANCE ++

If the value of this flag is true, the parsing of ++ web.xml and web-fragment.xml files for this ++ web application will be namespace-aware. Note that *.tld, ++ *.jspx and *.tagx files are always parsed ++ using a namespace-aware parser and that the tagPlugins.xml ++ file (if any) is never parsed using a namespace-aware parser. Note also ++ that if you turn this flag on, you should probably also turn ++ xmlValidation on. If the ++ org.apache.catalina.STRICT_SERVLET_COMPLIANCE + system property is set to + true, the default value of this attribute will be + true, else the default value will be false. +@@ -541,8 +552,9 @@ + + + +-

If the value of this flag is true, the XML files +- will be validated on context startup. If the ++

If the value of this flag is true, the parsing of ++ web.xml and web-fragment.xml files for this ++ web application will use a validating parser. If the + org.apache.catalina.STRICT_SERVLET_COMPLIANCE + system property is set to + true, the default value of this attribute will be +@@ -706,7 +718,10 @@ + is likely to result in instability. As such, enabling this should be + viewed as an option of last resort in a development environment and is + not recommended in a production environment. If not specified, the +- default value of false will be used.

++ default value of false will be used. If this feature is ++ enabled, web applications may take up to two seconds longer to stop as ++ executor threads are given up to two seconds to stop gracefully before ++ Thread.stop() is called on any remaining threads.

+
+ + +@@ -717,6 +732,22 @@ + not specified, the default value of false will be used.

+
+ ++ ++

Set to true if you want a context XML descriptor ++ embedded inside the application (located at ++ /META-INF/context.xml) to be copied to the owning ++ Host's xmlBase when the application ++ is deployed. On subsequent starts, the copied context XML descriptor ++ will be used in preference to any context XML descriptor embedded inside ++ the application even if the descriptor embedded inside the application ++ is more recent. The flag's value defaults to false. Note if ++ the deployXML attribute of the owning ++ Host is false or if the ++ copyXML attribute of the owning ++ Host is true, this attribute will ++ have no effect.

++
++ + +

If true, any attempt by an application to modify the + provided JNDI context with a call to bind(), unbind(), +--- webapps/docs/security-howto.xml.orig 2014-07-21 17:24:05.649404000 -0400 ++++ webapps/docs/security-howto.xml 2014-07-21 17:46:59.538035000 -0400 +@@ -72,10 +72,74 @@ +

+ +
+-

Tomcat ships with a number of web applications by default. +- Vulnerabilities have been discovered in these applications in the past. +- Applications that are not required should be removed so the system will not +- be at risk if another vulnerability is discovered.

++ ++ ++

Tomcat ships with a number of web applications that are enabled by ++ default. Vulnerabilities have been discovered in these applications in the ++ past. Applications that are not required should be removed so the system ++ will not be at risk if another vulnerability is discovered.

++
++ ++ ++

The ROOT web application presents a very low security risk but it does ++ include the version of Tomcat that is being used. The ROOT web application ++ should normally be removed from a publicly accessible Tomcat instance, not ++ for security reasons, but so that a more appropriate default page is shown ++ to users.

++
++ ++ ++

The documentation web application presents a very low security risk but ++ it does identify the version of Tomcat that is being used. It should ++ normally be removed from a publicly accessible Tomcat instance.

++
++ ++ ++

The examples web application should always be removed from any security ++ sensitive installation. While the examples web application does not ++ contain any known vulnerabilities, it is known to contain features ++ (particularly the cookie examples that display the contents of all ++ received and allow new cookies to be set) that may be used by an attacker ++ in conjunction with a vulnerability in another application deployed on the ++ Tomcat instance to obtain additional information that would otherwise be ++ unavailable.

++
++ ++ ++

The Manager application allows the remote deployment of web ++ applications and is frequently targeted by attackers due to the widespread ++ use of weak passwords and publicly accessible Tomcat instances with the ++ Manager application enabled. The Manager application is not accessible by ++ default as no users are configured with the necessary access. If the ++ Manager application is enabled then guidance in the section ++ Securing Management Applications section should be ++ followed.

++
++ ++ ++

The Host Manager application allows the creation and management of ++ virtual hosts - including the enabling of the Manager application for a ++ virtual host. The Host Manager application is not accessible by default ++ as no users are configured with the necessary access. If the Host Manager ++ application is enabled then guidance in the section Securing ++ Management Applications section should be followed.

++
++ ++ ++

When deploying a web application that provides management functions for ++ the Tomcat instance, the following guidelines should be followed:

++
    ++
      Ensure that any users permitted to access the management application ++ have strong passwords.
    ++
      Do not remove the use of the LockOutRealm ++ which prevents brute force attacks against user passwords.
    ++
      Uncomment the RemoteAddrValve ++ in /META-INF/context.xml which limits access to ++ localhost. If remote access is required, limit it to specific IP ++ addresses using this valve.
    ++
++
+
+ +
+@@ -109,6 +173,16 @@ + manager should be introduced at the start of the development cycle as it can + be time-consuming to track down and fix issues caused by enabling a security + manager for a mature application.

++ ++

Enabling the security manager changes the defaults for the following ++ settings:

++ +
+ +
+@@ -229,9 +303,11 @@ +

+ +

In a hosted environment where web applications may not be trusted, set +- the deployXML attribute to false to ignore any +- context.xml packaged with the web application that may try to assign +- increased privileges to the web application.

++ the deployXML attribute to false to ignore ++ any context.xml packaged with the web application that may try to assign ++ increased privileges to the web application. Note that if the security ++ manager is enabled that the deployXML attribute will ++ default to false.

+ + + +--- java/org/apache/catalina/core/DefaultInstanceManager.java.orig 2014-07-22 16:56:51.460868000 -0400 ++++ java/org/apache/catalina/core/DefaultInstanceManager.java 2014-07-22 16:59:03.496296000 -0400 +@@ -55,7 +55,7 @@ + import org.apache.tomcat.util.res.StringManager; + + /** +- * @version $Id: DefaultInstanceManager.java 1437338 2013-01-23 11:02:35Z markt $ ++ * @version $Id: DefaultInstanceManager.java 1514663 2013-08-16 11:51:28Z markt $ + */ + public class DefaultInstanceManager implements InstanceManager { + +@@ -133,6 +133,11 @@ + } + + @Override ++ public Object newInstance(Class clazz) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException { ++ return newInstance(clazz.newInstance(), clazz); ++ } ++ ++ @Override + public Object newInstance(String className) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { + Class clazz = loadClassMaybePrivileged(className, classLoader); + return newInstance(clazz.newInstance(), clazz); +--- java/org/apache/tomcat/InstanceManager.java.orig 2014-07-22 16:57:21.347937000 -0400 ++++ java/org/apache/tomcat/InstanceManager.java 2014-07-22 17:00:47.400650000 -0400 +@@ -21,10 +21,14 @@ + import javax.naming.NamingException; + + /** +- * @version $Id: InstanceManager.java 1200164 2011-11-10 05:46:02Z kkolinko $ ++ * @version $Id: InstanceManager.java 1514663 2013-08-16 11:51:28Z markt $ + */ + public interface InstanceManager { + ++ public Object newInstance(Class clazz) ++ throws IllegalAccessException, InvocationTargetException, NamingException, ++ InstantiationException; ++ + public Object newInstance(String className) + throws IllegalAccessException, InvocationTargetException, NamingException, + InstantiationException, ClassNotFoundException; +--- java/org/apache/jasper/EmbeddedServletOptions.java.orig 2014-07-22 17:08:09.862127000 -0400 ++++ java/org/apache/jasper/EmbeddedServletOptions.java 2014-07-22 17:08:43.749244000 -0400 +@@ -30,7 +30,6 @@ + import org.apache.jasper.compiler.Localizer; + import org.apache.jasper.compiler.TagPluginManager; + import org.apache.jasper.compiler.TldLocationsCache; +-import org.apache.jasper.xmlparser.ParserUtils; + import org.apache.juli.logging.Log; + import org.apache.juli.logging.LogFactory; + +@@ -456,11 +455,7 @@ + String v=config.getInitParameter( k ); + setProperty( k, v); + } +- +- // quick hack +- String validating=config.getInitParameter( "validating"); +- if( "false".equals( validating )) ParserUtils.validating=false; +- ++ + String keepgen = config.getInitParameter("keepgenerated"); + if (keepgen != null) { + if (keepgen.equalsIgnoreCase("true")) { +--- java/org/apache/tomcat/util/descriptor/DigesterFactory.java.orig 2014-07-21 17:24:05.654400000 -0400 ++++ java/org/apache/tomcat/util/descriptor/DigesterFactory.java 2014-07-21 17:46:59.547034000 -0400 +@@ -0,0 +1,135 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.tomcat.util.descriptor; ++ ++import java.net.URL; ++import java.util.Collections; ++import java.util.HashMap; ++import java.util.Map; ++ ++import javax.servlet.ServletContext; ++ ++import org.apache.tomcat.util.digester.Digester; ++import org.apache.tomcat.util.digester.RuleSet; ++import org.xml.sax.ext.EntityResolver2; ++ ++/** ++ * Wrapper class around the Digester that hide Digester's initialization ++ * details. ++ */ ++public class DigesterFactory { ++ ++ /** ++ * Mapping of well-known public IDs used by the Servlet API to the matching ++ * local resource. ++ */ ++ public static final Map SERVLET_API_PUBLIC_IDS; ++ ++ /** ++ * Mapping of well-known system IDs used by the Servlet API to the matching ++ * local resource. ++ */ ++ public static final Map SERVLET_API_SYSTEM_IDS; ++ ++ static { ++ Map publicIds = new HashMap(); ++ Map systemIds = new HashMap(); ++ ++ // W3C ++ publicIds.put(XmlIdentifiers.XSD_10_PUBLIC, idFor("XMLSchema.dtd")); ++ publicIds.put(XmlIdentifiers.DATATYPES_PUBLIC, idFor("datatypes.dtd")); ++ systemIds.put(XmlIdentifiers.XML_2001_XSD, idFor("xml.xsd")); ++ ++ // from J2EE 1.2 ++ publicIds.put(XmlIdentifiers.WEB_22_PUBLIC, idFor("web-app_2_2.dtd")); ++ publicIds.put(XmlIdentifiers.TLD_11_PUBLIC, idFor("web-jsptaglibrary_1_1.dtd")); ++ ++ // from J2EE 1.3 ++ publicIds.put(XmlIdentifiers.WEB_23_PUBLIC, idFor("web-app_2_3.dtd")); ++ publicIds.put(XmlIdentifiers.TLD_12_PUBLIC, idFor("web-jsptaglibrary_1_2.dtd")); ++ ++ // from J2EE 1.4 ++ systemIds.put("http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd", ++ idFor("j2ee_web_services_1_1.xsd")); ++ systemIds.put("http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd", ++ idFor("j2ee_web_services_client_1_1.xsd")); ++ systemIds.put(XmlIdentifiers.WEB_24_XSD, idFor("web-app_2_4.xsd")); ++ systemIds.put(XmlIdentifiers.TLD_20_XSD, idFor("web-jsptaglibrary_2_0.xsd")); ++ addSelf(systemIds, "j2ee_1_4.xsd"); ++ addSelf(systemIds, "jsp_2_0.xsd"); ++ ++ // from JavaEE 5 ++ systemIds.put(XmlIdentifiers.WEB_25_XSD, idFor("web-app_2_5.xsd")); ++ systemIds.put(XmlIdentifiers.TLD_21_XSD, idFor("web-jsptaglibrary_2_1.xsd")); ++ addSelf(systemIds, "javaee_5.xsd"); ++ addSelf(systemIds, "jsp_2_1.xsd"); ++ addSelf(systemIds, "javaee_web_services_1_2.xsd"); ++ addSelf(systemIds, "javaee_web_services_client_1_2.xsd"); ++ ++ // from JavaEE 6 ++ systemIds.put(XmlIdentifiers.WEB_30_XSD, idFor("web-app_3_0.xsd")); ++ systemIds.put(XmlIdentifiers.WEB_FRAGMENT_30_XSD, idFor("web-fragment_3_0.xsd")); ++ addSelf(systemIds, "web-common_3_0.xsd"); ++ addSelf(systemIds, "javaee_6.xsd"); ++ addSelf(systemIds, "jsp_2_2.xsd"); ++ addSelf(systemIds, "javaee_web_services_1_3.xsd"); ++ addSelf(systemIds, "javaee_web_services_client_1_3.xsd"); ++ ++ SERVLET_API_PUBLIC_IDS = Collections.unmodifiableMap(publicIds); ++ SERVLET_API_SYSTEM_IDS = Collections.unmodifiableMap(systemIds); ++ } ++ ++ private static void addSelf(Map ids, String id) { ++ String systemId = idFor(id); ++ ids.put(systemId, systemId); ++ ids.put(id, systemId); ++ } ++ ++ private static String idFor(String url) { ++ URL id = ServletContext.class.getResource("resources/" + url); ++ if (id == null) { ++ id = ServletContext.class.getResource("jsp/resources/" + url); ++ } ++ return id.toExternalForm(); ++ } ++ ++ ++ /** ++ * Create a Digester parser. ++ * @param xmlValidation turn on/off xml validation ++ * @param xmlNamespaceAware turn on/off namespace validation ++ * @param rule an instance of RuleSet used for parsing the xml. ++ * @param blockExternal turn on/off the blocking of external resources ++ */ ++ public static Digester newDigester(boolean xmlValidation, ++ boolean xmlNamespaceAware, ++ RuleSet rule, ++ boolean blockExternal) { ++ Digester digester = new Digester(); ++ digester.setNamespaceAware(xmlNamespaceAware); ++ digester.setValidating(xmlValidation); ++ digester.setUseContextClassLoader(true); ++ EntityResolver2 resolver = new LocalResolver(SERVLET_API_PUBLIC_IDS, ++ SERVLET_API_SYSTEM_IDS, blockExternal); ++ digester.setEntityResolver(resolver); ++ if (rule != null) { ++ digester.addRuleSet(rule); ++ } ++ ++ return digester; ++ } ++} +--- java/org/apache/tomcat/util/descriptor/LocalResolver.java.orig 2014-07-21 17:24:05.658412000 -0400 ++++ java/org/apache/tomcat/util/descriptor/LocalResolver.java 2014-07-21 17:46:59.555034000 -0400 +@@ -0,0 +1,146 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.tomcat.util.descriptor; ++ ++import java.io.FileNotFoundException; ++import java.io.IOException; ++import java.net.MalformedURLException; ++import java.net.URI; ++import java.net.URISyntaxException; ++import java.net.URL; ++import java.util.Map; ++ ++import org.apache.tomcat.util.res.StringManager; ++import org.xml.sax.InputSource; ++import org.xml.sax.SAXException; ++import org.xml.sax.ext.EntityResolver2; ++ ++/** ++ * A resolver for locally cached XML resources. ++ */ ++public class LocalResolver implements EntityResolver2 { ++ ++ private static final StringManager sm = ++ StringManager.getManager(Constants.PACKAGE_NAME); ++ ++ private final Map publicIds; ++ private final Map systemIds; ++ private final boolean blockExternal; ++ ++ /** ++ * Constructor providing mappings of public and system identifiers to local ++ * resources. Each map contains a mapping from a well-known identifier to a ++ * URL for a local resource path. ++ * ++ * @param publicIds mapping of well-known public identifiers to local ++ * resources ++ * @param systemIds mapping of well-known system identifiers to local ++ * resources ++ * @param blockExternal are external resources blocked that are not ++ * well-known ++ */ ++ public LocalResolver(Map publicIds, ++ Map systemIds, boolean blockExternal) { ++ this.publicIds = publicIds; ++ this.systemIds = systemIds; ++ this.blockExternal = blockExternal; ++ } ++ ++ ++ @Override ++ public InputSource resolveEntity(String publicId, String systemId) ++ throws SAXException, IOException { ++ return resolveEntity(null, publicId, null, systemId); ++ } ++ ++ ++ @Override ++ public InputSource resolveEntity(String name, String publicId, ++ String base, String systemId) throws SAXException, IOException { ++ ++ // First try resolving using the publicId ++ String resolved = publicIds.get(publicId); ++ if (resolved != null) { ++ InputSource is = new InputSource(resolved); ++ is.setPublicId(publicId); ++ return is; ++ } ++ ++ // If there is no systemId, can't try anything else ++ if (systemId == null) { ++ throw new FileNotFoundException(sm.getString("localResolver.unresolvedEntity", ++ name, publicId, systemId, base)); ++ } ++ ++ // Try resolving with the supplied systemId ++ resolved = systemIds.get(systemId); ++ if (resolved != null) { ++ InputSource is = new InputSource(resolved); ++ is.setPublicId(publicId); ++ return is; ++ } ++ ++ // Resolve the supplied systemId against the base ++ URI systemUri; ++ try { ++ if (base == null) { ++ systemUri = new URI(systemId); ++ } else { ++ // Can't use URI.resolve() because "jar:..." URLs are not valid ++ // hierarchical URIs so resolve() does not work. new URL() ++ // delegates to the jar: stream handler and it manages to figure ++ // it out. ++ URI baseUri = new URI(base); ++ systemUri = new URL(baseUri.toURL(), systemId).toURI(); ++ } ++ systemUri = systemUri.normalize(); ++ } catch (URISyntaxException e) { ++ // May be caused by a | being used instead of a : in an absolute ++ // file URI on Windows. ++ if (blockExternal) { ++ // Absolute paths aren't allowed so block it ++ throw new MalformedURLException(e.getMessage()); ++ } else { ++ // See if the URLHandler can resolve it ++ return new InputSource(systemId); ++ } ++ } ++ if (systemUri.isAbsolute()) { ++ // Try the resolved systemId ++ resolved = systemIds.get(systemUri.toString()); ++ if (resolved != null) { ++ InputSource is = new InputSource(resolved); ++ is.setPublicId(publicId); ++ return is; ++ } ++ if (!blockExternal) { ++ InputSource is = new InputSource(systemUri.toString()); ++ is.setPublicId(publicId); ++ return is; ++ } ++ } ++ throw new FileNotFoundException(sm.getString("localResolver.unresolvedEntity", ++ name, publicId, systemId, base)); ++ } ++ ++ ++ @Override ++ public InputSource getExternalSubset(String name, String baseURI) ++ throws SAXException, IOException { ++ return null; ++ } ++} +--- java/org/apache/tomcat/util/descriptor/LocalStrings.properties.orig 2014-07-21 17:24:05.663406000 -0400 ++++ java/org/apache/tomcat/util/descriptor/LocalStrings.properties 2014-07-21 17:46:59.562036000 -0400 +@@ -0,0 +1,19 @@ ++# Licensed to the Apache Software Foundation (ASF) under one or more ++# contributor license agreements. See the NOTICE file distributed with ++# this work for additional information regarding copyright ownership. ++# The ASF licenses this file to You under the Apache License, Version 2.0 ++# (the "License"); you may not use this file except in compliance with ++# the License. You may obtain a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++ ++localResolver.unresolvedEntity=Could not resolve XML resource [{0}] with public ID [{1}], system ID [{2}] and base URI [{3}] to a known, local entity. ++ ++xmlErrorHandler.error=Non-fatal error [{0}] reported processing [{1}]. ++xmlErrorHandler.warning=Warning [{0}] reported processing [{1}]. +--- java/org/apache/tomcat/util/descriptor/Constants.java.orig 2014-07-21 17:24:05.668398000 -0400 ++++ java/org/apache/tomcat/util/descriptor/Constants.java 2014-07-21 17:46:59.569034000 -0400 +@@ -0,0 +1,24 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.tomcat.util.descriptor; ++ ++public class Constants { ++ ++ public static final String PACKAGE_NAME = ++ Constants.class.getPackage().getName(); ++ ++} +--- java/org/apache/tomcat/util/descriptor/LocalStrings_es.properties.orig 2014-07-21 17:24:05.672404000 -0400 ++++ java/org/apache/tomcat/util/descriptor/LocalStrings_es.properties 2014-07-21 17:46:59.574035000 -0400 +@@ -0,0 +1,17 @@ ++# Licensed to the Apache Software Foundation (ASF) under one or more ++# contributor license agreements. See the NOTICE file distributed with ++# this work for additional information regarding copyright ownership. ++# The ASF licenses this file to You under the Apache License, Version 2.0 ++# (the "License"); you may not use this file except in compliance with ++# the License. You may obtain a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++ ++xmlErrorHandler.error = Error no fatal [{0}] reportado por el proceso [{1}]. ++xmlErrorHandler.warning = Aviso [{0}] reportado por el proceso [{1}]. +--- java/org/apache/tomcat/util/descriptor/XmlIdentifiers.java.orig 2014-07-21 17:24:05.677400000 -0400 ++++ java/org/apache/tomcat/util/descriptor/XmlIdentifiers.java 2014-07-21 17:46:59.580036000 -0400 +@@ -0,0 +1,77 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.tomcat.util.descriptor; ++ ++/** ++ * Defines constants for well-known Public and System identifiers documented by ++ * the Servlet and JSP specifications. ++ */ ++public final class XmlIdentifiers { ++ ++ // from W3C ++ public static final String XML_2001_XSD = "http://www.w3.org/2001/xml.xsd"; ++ public static final String DATATYPES_PUBLIC = "datatypes"; ++ public static final String XSD_10_PUBLIC = ++ "-//W3C//DTD XMLSCHEMA 200102//EN"; ++ ++ // from J2EE 1.2 ++ public static final String WEB_22_PUBLIC = ++ "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"; ++ public static final String WEB_22_SYSTEM = ++ "http://java.sun.com/dtd/web-app_2_2.dtd"; ++ public static final String TLD_11_PUBLIC = ++ "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"; ++ public static final String TLD_11_SYSTEM = ++ "http://java.sun.com/dtd/web-jsptaglibrary_1_1.dtd"; ++ ++ // from J2EE 1.3 ++ public static final String WEB_23_PUBLIC = ++ "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"; ++ public static final String WEB_23_SYSTEM = ++ "http://java.sun.com/dtd/web-app_2_3.dtd"; ++ public static final String TLD_12_PUBLIC = ++ "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"; ++ public static final String TLD_12_SYSTEM = ++ "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"; ++ ++ // from J2EE 1.4 ++ public static final String WEB_24_XSD = ++ "http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"; ++ public static final String TLD_20_XSD = ++ "http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"; ++ public static final String WEBSERVICES_11_XSD = ++ "http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd"; ++ ++ // from JavaEE 5 ++ public static final String WEB_25_XSD = ++ "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"; ++ public static final String TLD_21_XSD = ++ "http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"; ++ public static final String WEBSERVICES_12_XSD = ++ "http://java.sun.com/xml/ns/javaee/javaee_web_services_1_2.xsd"; ++ ++ // from JavaEE 6 ++ public static final String WEB_30_XSD = ++ "http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"; ++ public static final String WEB_FRAGMENT_30_XSD = ++ "http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"; ++ public static final String WEBSERVICES_13_XSD = ++ "http://java.sun.com/xml/ns/javaee/javaee_web_services_1_3.xsd"; ++ ++ private XmlIdentifiers() { ++ } ++} +\ No newline at end of file +--- java/org/apache/tomcat/util/descriptor/XmlErrorHandler.java.orig 2014-07-21 17:24:05.683398000 -0400 ++++ java/org/apache/tomcat/util/descriptor/XmlErrorHandler.java 2014-07-21 17:46:59.586038000 -0400 +@@ -0,0 +1,75 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.tomcat.util.descriptor; ++ ++import java.util.HashSet; ++import java.util.Set; ++ ++import org.apache.juli.logging.Log; ++import org.apache.tomcat.util.res.StringManager; ++import org.xml.sax.ErrorHandler; ++import org.xml.sax.SAXException; ++import org.xml.sax.SAXParseException; ++ ++public class XmlErrorHandler implements ErrorHandler { ++ ++ private static final StringManager sm = ++ StringManager.getManager(Constants.PACKAGE_NAME); ++ ++ private final Set errors = new HashSet(); ++ ++ private final Set warnings = new HashSet(); ++ ++ @Override ++ public void error(SAXParseException exception) throws SAXException { ++ // Collect non-fatal errors ++ errors.add(exception); ++ } ++ ++ @Override ++ public void fatalError(SAXParseException exception) throws SAXException { ++ // Re-throw fatal errors ++ throw exception; ++ } ++ ++ @Override ++ public void warning(SAXParseException exception) throws SAXException { ++ // Collect warnings ++ warnings.add(exception); ++ } ++ ++ public Set getErrors() { ++ // Internal use only - don't worry about immutability ++ return errors; ++ } ++ ++ public Set getWarnings() { ++ // Internal use only - don't worry about immutability ++ return warnings; ++ } ++ ++ public void logFindings(Log log, String source) { ++ for (SAXParseException e : getWarnings()) { ++ log.warn(sm.getString( ++ "xmlErrorHandler.warning", e.getMessage(), source)); ++ } ++ for (SAXParseException e : getErrors()) { ++ log.warn(sm.getString( ++ "xmlErrorHandler.error", e.getMessage(), source)); ++ } ++ } ++} diff --git a/SOURCES/tomcat-7.0.42-CVE-2014-0119.patch b/SOURCES/tomcat-7.0.42-CVE-2014-0119.patch new file mode 100644 index 0000000..84e93a2 --- /dev/null +++ b/SOURCES/tomcat-7.0.42-CVE-2014-0119.patch @@ -0,0 +1,678 @@ +--- java/org/apache/catalina/security/SecurityClassLoad.java.orig 2014-07-24 18:29:38.830023000 -0400 ++++ java/org/apache/catalina/security/SecurityClassLoad.java 2014-07-24 18:31:18.655356000 -0400 +@@ -25,9 +25,7 @@ + * + * @author Glenn L. Nielsen + * @author Jean-Francois Arcand +- * @version $Id: SecurityClassLoad.java 1410548 2012-11-16 19:38:51Z markt $ + */ +- + public final class SecurityClassLoad { + + public static void securityClassLoad(ClassLoader loader) +@@ -41,6 +39,7 @@ + loadCoyotePackage(loader); + loadLoaderPackage(loader); + loadRealmPackage(loader); ++ loadServletsPackage(loader); + loadSessionPackage(loader); + loadUtilPackage(loader); + loadValvesPackage(loader); +@@ -76,12 +75,6 @@ + "AsyncContextImpl$1"); + loader.loadClass + (basePackage + +- "AsyncContextImpl$PrivilegedGetTccl"); +- loader.loadClass +- (basePackage + +- "AsyncContextImpl$PrivilegedSetTccl"); +- loader.loadClass +- (basePackage + + "AsyncListenerWrapper"); + loader.loadClass + (basePackage + +@@ -124,14 +117,24 @@ + } + + ++ private static final void loadServletsPackage(ClassLoader loader) ++ throws Exception { ++ final String basePackage = "org.apache.catalina.servlets."; ++ // Avoid a possible memory leak in the DefaultServlet when running with ++ // a security manager. The DefaultServlet needs to load an XML parser ++ // when running under a security manager. We want this to be loaded by ++ // the container rather than a web application to prevent a memory leak ++ // via web application class loader. ++ loader.loadClass(basePackage + "DefaultServlet"); ++ } ++ ++ + private static final void loadSessionPackage(ClassLoader loader) + throws Exception { + final String basePackage = "org.apache.catalina.session."; + loader.loadClass + (basePackage + "StandardSession"); + loader.loadClass +- (basePackage + "StandardSession$PrivilegedSetTccl"); +- loader.loadClass + (basePackage + "StandardSession$1"); + loader.loadClass + (basePackage + "StandardManager$PrivilegedDoUnload"); +@@ -280,10 +283,9 @@ + loader.loadClass(basePackage + + "util.net.NioBlockingSelector$BlockPoller$3"); + loader.loadClass(basePackage + "util.net.SSLSupport$CipherData"); +- loader.loadClass +- (basePackage + "util.net.JIoEndpoint$PrivilegedSetTccl"); +- loader.loadClass +- (basePackage + "util.net.AprEndpoint$PrivilegedSetTccl"); ++ // security ++ loader.loadClass(basePackage + "util.security.PrivilegedGetTccl"); ++ loader.loadClass(basePackage + "util.security.PrivilegedSetTccl"); + } + } + +--- java/org/apache/catalina/servlets/DefaultServlet.java.orig 2014-07-24 18:29:38.875020000 -0400 ++++ java/org/apache/catalina/servlets/DefaultServlet.java 2014-07-24 18:31:18.695352000 -0400 +@@ -14,8 +14,6 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +- +- + package org.apache.catalina.servlets; + + +@@ -34,6 +32,7 @@ + import java.io.Reader; + import java.io.StringReader; + import java.io.StringWriter; ++import java.security.AccessController; + import java.util.ArrayList; + import java.util.Iterator; + import java.util.Locale; +@@ -76,11 +75,14 @@ + import org.apache.naming.resources.Resource; + import org.apache.naming.resources.ResourceAttributes; + import org.apache.tomcat.util.res.StringManager; +- ++import org.apache.tomcat.util.security.PrivilegedGetTccl; ++import org.apache.tomcat.util.security.PrivilegedSetTccl; + import org.w3c.dom.Document; + import org.xml.sax.InputSource; + import org.xml.sax.SAXException; + import org.xml.sax.ext.EntityResolver2; ++ ++ + /** + *

The default resource-serving servlet for most web applications, + * used to serve static resources such as HTML pages and images. +@@ -122,9 +124,7 @@ + *

+ * @author Craig R. McClanahan + * @author Remy Maucherat +- * @version $Id: DefaultServlet.java 1301255 2012-03-15 22:47:40Z markt $ + */ +- + public class DefaultServlet + extends HttpServlet { + +@@ -132,10 +132,10 @@ + + private static final DocumentBuilderFactory factory; + +- private static final SecureEntityResolver secureEntityResolver = +- new SecureEntityResolver(); +- // ----------------------------------------------------- Instance Variables ++ private static final SecureEntityResolver secureEntityResolver; ++ + ++ // ----------------------------------------------------- Instance Variables + + /** + * The debugging detail level for this servlet. +@@ -225,6 +225,11 @@ + */ + protected static final ArrayList FULL = new ArrayList(); + ++ /** ++ * Flag to determine if server information is presented. ++ */ ++ protected boolean showServerInfo = true; ++ + + // ----------------------------------------------------- Static Initializer + +@@ -239,9 +244,16 @@ + urlEncoder.addSafeCharacter('.'); + urlEncoder.addSafeCharacter('*'); + urlEncoder.addSafeCharacter('/'); +- factory = DocumentBuilderFactory.newInstance(); +- factory.setNamespaceAware(true); +- factory.setValidating(false); ++ ++ if (Globals.IS_SECURITY_ENABLED) { ++ factory = DocumentBuilderFactory.newInstance(); ++ factory.setNamespaceAware(true); ++ factory.setValidating(false); ++ secureEntityResolver = new SecureEntityResolver(); ++ } else { ++ factory = null; ++ secureEntityResolver = null; ++ } + } + + +@@ -270,6 +282,7 @@ + protected static final int BUFFER_SIZE = 4096; + + ++ + // --------------------------------------------------------- Public Methods + + +@@ -345,6 +358,9 @@ + throw new UnavailableException("No resources"); + } + ++ if (getServletConfig().getInitParameter("showServerInfo") != null) { ++ showServerInfo = Boolean.parseBoolean(getServletConfig().getInitParameter("showServerInfo")); ++ } + } + + +@@ -1251,7 +1267,6 @@ + } + + +- + /** + * Decide which way to render. HTML or XML. + */ +@@ -1259,13 +1274,15 @@ + throws IOException, ServletException { + + Source xsltSource = findXsltInputStream(cacheEntry.context); +- if (xsltSource ==null) { ++ ++ if (xsltSource == null) { + return renderHtml(contextPath, cacheEntry); + } + return renderXml(contextPath, cacheEntry, xsltSource); + + } + ++ + /** + * Return an InputStream to an HTML representation of the contents + * of this directory. +@@ -1362,11 +1379,27 @@ + sb.append("]]>"); + } + +- + sb.append(""); + +- ++ // Prevent possible memory leak. Ensure Transformer and ++ // TransformerFactory are not loaded from the web application. ++ ClassLoader original; ++ if (Globals.IS_SECURITY_ENABLED) { ++ PrivilegedGetTccl pa = new PrivilegedGetTccl(); ++ original = AccessController.doPrivileged(pa); ++ } else { ++ original = Thread.currentThread().getContextClassLoader(); ++ } + try { ++ if (Globals.IS_SECURITY_ENABLED) { ++ PrivilegedSetTccl pa = ++ new PrivilegedSetTccl(DefaultServlet.class.getClassLoader()); ++ AccessController.doPrivileged(pa); ++ } else { ++ Thread.currentThread().setContextClassLoader( ++ DefaultServlet.class.getClassLoader()); ++ } ++ + TransformerFactory tFactory = TransformerFactory.newInstance(); + Source xmlSource = new StreamSource(new StringReader(sb.toString())); + Transformer transformer = tFactory.newTransformer(xsltSource); +@@ -1379,6 +1412,13 @@ + return (new ByteArrayInputStream(stream.toByteArray())); + } catch (TransformerException e) { + throw new ServletException("XSL transformer error", e); ++ } finally { ++ if (Globals.IS_SECURITY_ENABLED) { ++ PrivilegedSetTccl pa = new PrivilegedSetTccl(original); ++ AccessController.doPrivileged(pa); ++ } else { ++ Thread.currentThread().setContextClassLoader(original); ++ } + } + } + +@@ -1530,7 +1570,9 @@ + sb.append("
"); + } + +- sb.append("

").append(ServerInfo.getServerInfo()).append("

"); ++ if (showServerInfo) { ++ sb.append("

").append(ServerInfo.getServerInfo()).append("

"); ++ } + sb.append("\r\n"); + sb.append("\r\n"); + +@@ -1588,7 +1630,7 @@ + + + /** +- * Return the xsl template inputstream (if possible) ++ * Return a Source for the xsl template (if possible) + */ + protected Source findXsltInputStream(DirContext directory) + throws IOException { +@@ -1630,31 +1672,32 @@ + /* Open and read in file in one fell swoop to reduce chance + * chance of leaving handle open. + */ +- if (globalXsltFile != null) { +- File f = validateGlobalXsltFile(); +- if (f != null ){ +- FileInputStream fis = null; +- try { +- fis = new FileInputStream(f); +- byte b[] = new byte[(int)f.length()]; /* danger! */ +- fis.read(b); +- return new StreamSource(new ByteArrayInputStream(b)); +- } finally { +- if (fis != null) { +- try { +- fis.close(); +- } catch(IOException ioe) { +- // ignore +- } +- } +- } +- } ++ if (globalXsltFile != null) { ++ File f = validateGlobalXsltFile(); ++ if (f != null){ ++ FileInputStream fis = null; ++ try { ++ fis = new FileInputStream(f); ++ byte b[] = new byte[(int)f.length()]; /* danger! */ ++ fis.read(b); ++ return new StreamSource(new ByteArrayInputStream(b)); ++ } finally { ++ if (fis != null) { ++ try { ++ fis.close(); ++ } catch (IOException ioe) { ++ // Ignore ++ } ++ } ++ } ++ } + } + + return null; + + } + ++ + private File validateGlobalXsltFile() { + + File result = null; +@@ -1705,6 +1748,7 @@ + return candidate; + } + ++ + private Source secureXslt(InputStream is) { + // Need to filter out any external entities + Source result = null; +@@ -1740,7 +1784,6 @@ + + // -------------------------------------------------------- protected Methods + +- + /** + * Check if sendfile can be used. + */ +@@ -2240,9 +2283,6 @@ + } + + +- // ------------------------------------------------------ Range Inner Class +- +- + protected static class Range { + + public long start; +@@ -2259,6 +2299,7 @@ + } + } + ++ + /** + * This is secure in the sense that any attempt to use an external entity + * will trigger an exception. +@@ -2288,4 +2329,3 @@ + } + } + } +- +--- webapps/docs/changelog.xml.orig 2014-07-24 18:29:38.917021000 -0400 ++++ webapps/docs/changelog.xml 2014-07-24 18:36:52.526481000 -0400 +@@ -158,6 +158,15 @@ + 55176: Correctly handle regular expressions within SSI + expressions that contain an equals character. (markt) + ++ ++ Ensure that a TLD parser obtained from the cache has the correct value ++ of blockExternal. (markt) ++ ++ ++ Extend XML factory, parser etc. memory leak protection to cover some ++ additional locations where, theoretically, a memory leak could occur. ++ (markt) ++ + +
+ +@@ -352,6 +361,10 @@ + request if the CRLF terminating the request line was split across + multiple packets. Patch by Konstantin Preißer. (markt) + ++ ++ Only create XML parsing objects if required and fix associated potential ++ memory leak in the default Servlet. (markt) ++ + + + +--- java/org/apache/jasper/xmlparser/ParserUtils.java.orig 2014-07-24 18:29:38.952016000 -0400 ++++ java/org/apache/jasper/xmlparser/ParserUtils.java 2014-07-24 18:31:18.746354000 -0400 +@@ -18,6 +18,7 @@ + + import java.io.IOException; + import java.io.InputStream; ++import java.security.AccessController; + + import javax.xml.parsers.DocumentBuilder; + import javax.xml.parsers.DocumentBuilderFactory; +@@ -29,6 +30,8 @@ + import org.apache.tomcat.util.descriptor.DigesterFactory; + import org.apache.tomcat.util.descriptor.LocalResolver; + import org.apache.tomcat.util.descriptor.XmlErrorHandler; ++import org.apache.tomcat.util.security.PrivilegedGetTccl; ++import org.apache.tomcat.util.security.PrivilegedSetTccl; + import org.w3c.dom.Comment; + import org.w3c.dom.Document; + import org.w3c.dom.NamedNodeMap; +@@ -36,7 +39,6 @@ + import org.w3c.dom.NodeList; + import org.w3c.dom.Text; + import org.xml.sax.EntityResolver; +-import org.xml.sax.ErrorHandler; + import org.xml.sax.InputSource; + import org.xml.sax.SAXException; + import org.xml.sax.SAXParseException; +@@ -48,16 +50,10 @@ + * use a separate class loader for the parser to be used. + * + * @author Craig R. McClanahan +- * @version $Id: ParserUtils.java 1549529 2013-12-09 10:05:56Z markt $ + */ + public class ParserUtils { + + /** +- * An error handler for use when parsing XML documents. +- */ +- static ErrorHandler errorHandler = new XmlErrorHandler(); +- +- /** + * An entity resolver for use when parsing XML documents. + */ + static EntityResolver entityResolver; +@@ -99,15 +95,46 @@ + Document document = null; + + // Perform an XML parse of this document, via JAXP ++ ClassLoader original; ++ if (Constants.IS_SECURITY_ENABLED) { ++ PrivilegedGetTccl pa = new PrivilegedGetTccl(); ++ original = AccessController.doPrivileged(pa); ++ } else { ++ original = Thread.currentThread().getContextClassLoader(); ++ } + try { ++ if (Constants.IS_SECURITY_ENABLED) { ++ PrivilegedSetTccl pa = ++ new PrivilegedSetTccl(ParserUtils.class.getClassLoader()); ++ AccessController.doPrivileged(pa); ++ } else { ++ Thread.currentThread().setContextClassLoader( ++ ParserUtils.class.getClassLoader()); ++ } ++ + DocumentBuilderFactory factory = + DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setValidating(validating); ++ if (validating) { ++ // Enable DTD validation ++ factory.setFeature( ++ "http://xml.org/sax/features/validation", ++ true); ++ // Enable schema validation ++ factory.setFeature( ++ "http://apache.org/xml/features/validation/schema", ++ true); ++ } + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.setEntityResolver(entityResolverInstance); +- builder.setErrorHandler(errorHandler); ++ XmlErrorHandler handler = new XmlErrorHandler(); ++ builder.setErrorHandler(handler); + document = builder.parse(is); ++ if (!handler.getErrors().isEmpty()) { ++ // throw the first to indicate there was a error during processing ++ throw handler.getErrors().iterator().next(); ++ } + } catch (ParserConfigurationException ex) { + throw new JasperException + (Localizer.getMessage("jsp.error.parse.xml", location), ex); +@@ -124,6 +151,13 @@ + } catch (IOException io) { + throw new JasperException + (Localizer.getMessage("jsp.error.parse.xml", location), io); ++ } finally { ++ if (Constants.IS_SECURITY_ENABLED) { ++ PrivilegedSetTccl pa = new PrivilegedSetTccl(original); ++ AccessController.doPrivileged(pa); ++ } else { ++ Thread.currentThread().setContextClassLoader(original); ++ } + } + + // Convert the resulting document to a graph of TreeNodes +--- java/org/apache/jasper/compiler/JspDocumentParser.java.orig 2014-07-24 18:29:38.974016000 -0400 ++++ java/org/apache/jasper/compiler/JspDocumentParser.java 2014-07-24 18:31:18.774352000 -0400 +@@ -20,6 +20,7 @@ + import java.io.FileNotFoundException; + import java.io.IOException; + import java.io.InputStream; ++import java.security.AccessController; + import java.util.Iterator; + import java.util.List; + import java.util.jar.JarFile; +@@ -35,6 +36,8 @@ + import org.apache.jasper.JspCompilationContext; + import org.apache.tomcat.util.descriptor.DigesterFactory; + import org.apache.tomcat.util.descriptor.LocalResolver; ++import org.apache.tomcat.util.security.PrivilegedGetTccl; ++import org.apache.tomcat.util.security.PrivilegedSetTccl; + import org.xml.sax.Attributes; + import org.xml.sax.InputSource; + import org.xml.sax.Locator; +@@ -129,7 +132,7 @@ + Constants.XML_BLOCK_EXTERNAL_INIT_PARAM); + boolean blockExternal; + if (blockExternalString == null) { +- blockExternal = Constants.IS_SECURITY_ENABLED; ++ blockExternal = true; + } else { + blockExternal = Boolean.parseBoolean(blockExternalString); + } +@@ -1464,33 +1467,58 @@ + JspDocumentParser jspDocParser) + throws Exception { + +- SAXParserFactory factory = SAXParserFactory.newInstance(); +- +- factory.setNamespaceAware(true); +- // Preserve xmlns attributes +- factory.setFeature( +- "http://xml.org/sax/features/namespace-prefixes", +- true); +- +- factory.setValidating(validating); +- if (validating) { +- // Enable DTD validation +- factory.setFeature( +- "http://xml.org/sax/features/validation", +- true); +- // Enable schema validation +- factory.setFeature( +- "http://apache.org/xml/features/validation/schema", +- true); ++ ClassLoader original; ++ if (Constants.IS_SECURITY_ENABLED) { ++ PrivilegedGetTccl pa = new PrivilegedGetTccl(); ++ original = AccessController.doPrivileged(pa); ++ } else { ++ original = Thread.currentThread().getContextClassLoader(); + } ++ try { ++ if (Constants.IS_SECURITY_ENABLED) { ++ PrivilegedSetTccl pa = ++ new PrivilegedSetTccl(JspDocumentParser.class.getClassLoader()); ++ AccessController.doPrivileged(pa); ++ } else { ++ Thread.currentThread().setContextClassLoader( ++ JspDocumentParser.class.getClassLoader()); ++ } ++ ++ SAXParserFactory factory = SAXParserFactory.newInstance(); + +- // Configure the parser +- SAXParser saxParser = factory.newSAXParser(); +- XMLReader xmlReader = saxParser.getXMLReader(); +- xmlReader.setProperty(LEXICAL_HANDLER_PROPERTY, jspDocParser); +- xmlReader.setErrorHandler(jspDocParser); ++ factory.setNamespaceAware(true); ++ // Preserve xmlns attributes ++ factory.setFeature( ++ "http://xml.org/sax/features/namespace-prefixes", ++ true); + +- return saxParser; ++ factory.setValidating(validating); ++ if (validating) { ++ // Enable DTD validation ++ factory.setFeature( ++ "http://xml.org/sax/features/validation", ++ true); ++ // Enable schema validation ++ factory.setFeature( ++ "http://apache.org/xml/features/validation/schema", ++ true); ++ } ++ ++ // Configure the parser ++ SAXParser saxParser = factory.newSAXParser(); ++ XMLReader xmlReader = saxParser.getXMLReader(); ++ xmlReader.setProperty(LEXICAL_HANDLER_PROPERTY, jspDocParser); ++ xmlReader.setErrorHandler(jspDocParser); ++ ++ return saxParser; ++ } finally { ++ if (Constants.IS_SECURITY_ENABLED) { ++ PrivilegedSetTccl pa = new PrivilegedSetTccl(original); ++ AccessController.doPrivileged(pa); ++ } else { ++ Thread.currentThread().setContextClassLoader(original); ++ } ++ } + } + + /* +--- java/org/apache/tomcat/util/security/PrivilegedGetTccl.java.orig 2014-07-24 18:59:42.923103000 -0400 ++++ java/org/apache/tomcat/util/security/PrivilegedGetTccl.java 2014-07-24 18:56:17.729411000 -0400 +@@ -0,0 +1,28 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.tomcat.util.security; ++ ++import java.security.PrivilegedAction; ++ ++public class PrivilegedGetTccl implements PrivilegedAction { ++ @Override ++ public ClassLoader run() { ++ return Thread.currentThread().getContextClassLoader(); ++ } ++} ++ ++ +--- java/org/apache/tomcat/util/security/PrivilegedSetTccl.java.orig 2014-07-24 18:59:42.928107000 -0400 ++++ java/org/apache/tomcat/util/security/PrivilegedSetTccl.java 2014-07-24 18:56:17.736421000 -0400 +@@ -0,0 +1,34 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.tomcat.util.security; ++ ++import java.security.PrivilegedAction; ++ ++public class PrivilegedSetTccl implements PrivilegedAction { ++ ++ private ClassLoader cl; ++ ++ public PrivilegedSetTccl(ClassLoader cl) { ++ this.cl = cl; ++ } ++ ++ @Override ++ public Void run() { ++ Thread.currentThread().setContextClassLoader(cl); ++ return null; ++ } ++} +\ No newline at end of file diff --git a/SPECS/tomcat.spec b/SPECS/tomcat.spec index 798d69a..60dd0bc 100644 --- a/SPECS/tomcat.spec +++ b/SPECS/tomcat.spec @@ -54,7 +54,7 @@ Name: tomcat Epoch: 0 Version: %{major_version}.%{minor_version}.%{micro_version} -Release: 6%{?dist} +Release: 8%{?dist} Summary: Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API Group: System Environment/Daemons @@ -91,10 +91,8 @@ Patch4: %{name}-%{version}-CVE-2014-0050.patch Patch5: %{name}-%{version}-CVE-2014-0099.patch Patch6: %{name}-%{version}-CVE-2014-0096.patch Patch7: %{name}-%{version}-CVE-2014-0075.patch -# postponed. apply with 4590 -# Deferred -#Patch5: %{name}-%{version}-CVE-2013-4590.patch -#Patch8: %{name}-%{version}-CVE-2014-0119.patch +Patch8: %{name}-%{version}-CVE-2013-4590.patch +Patch9: %{name}-%{version}-CVE-2014-0119.patch BuildArch: noarch @@ -258,8 +256,8 @@ find . -type f \( -name "*.bat" -o -name "*.class" -o -name Thumbs.db -o -name " %patch5 -p0 %patch6 -p0 %patch7 -p0 -# postponed. apply with 4590 -#%patch8 -p0 +%patch8 -p0 +%patch9 -p0 %{__ln_s} $(build-classpath jakarta-taglibs-core) webapps/examples/WEB-INF/lib/jstl.jar @@ -700,6 +698,14 @@ fi %attr(0644,root,root) %{_unitdir}/%{name}-jsvc.service %changelog +* Tue Jul 22 2014 David Knox - 0:7.0.42-8 +- Resolves: CVE-2013-4590 +- Resolves: CVE-2014-0119 + +* Tue Jul 8 2014 David Knox - 0:7.0.42-7 +- Related: CVE-2014-0099 incrementing release so rpmdiff doesn't complain about +- no new entries in the changelog + * Wed Jun 11 2014 David Knox - 0:7.0.42-6 - Resolves: CVE-2014-0099 Fix possible overflow when parsing - long values from byte array