Author: kkolinko Date: Sun May 11 17:15:52 2014 New Revision: 1593821 URL: http://svn.apache.org/r1593821 Log: Defensive coding around some XML activities that are triggered by web applications and are therefore at potential risk of a memory leak. Patch by markt.
Added: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/ - copied from r1593818, tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/security/ Modified: tomcat/tc6.0.x/trunk/STATUS.txt tomcat/tc6.0.x/trunk/java/org/apache/catalina/security/SecurityClassLoad.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/servlets/DefaultServlet.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELFunctionMapper.java tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java tomcat/tc6.0.x/trunk/java/org/apache/jasper/xmlparser/ParserUtils.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedGetTccl.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedSetTccl.java tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Modified: tomcat/tc6.0.x/trunk/STATUS.txt URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1593821&r1=1593820&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/STATUS.txt (original) +++ tomcat/tc6.0.x/trunk/STATUS.txt Sun May 11 17:15:52 2014 @@ -28,12 +28,6 @@ None PATCHES PROPOSED TO BACKPORT: [ New proposals should be added at the end of the list ] -* Defensive coding around some XML activities that are triggered by web - applications and are therefore at potential risk of a memory leak. - http://people.apache.org/~markt/patches/2014-04-25-memory-leak-tc6-v1.patch - +1: markt, kkolinko, fhanik - -1: - * Followup to r1589635 To simplify code and align it with TC7 & 8. (Discussed in Re:r1589635) Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/security/SecurityClassLoad.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/security/SecurityClassLoad.java?rev=1593821&r1=1593820&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/security/SecurityClassLoad.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/security/SecurityClassLoad.java Sun May 11 17:15:52 2014 @@ -96,17 +96,10 @@ public final class SecurityClassLoad { private final static void loadSessionPackage(ClassLoader loader) throws Exception { - String basePackage = "org.apache.catalina."; - loader.loadClass - (basePackage + "session.StandardSession"); - loader.loadClass - (basePackage + "session.StandardSession$PrivilegedSetTccl"); - loader.loadClass - (basePackage + - "session.StandardSession$1"); - loader.loadClass - (basePackage + - "session.StandardManager$PrivilegedDoUnload"); + String basePackage = "org.apache.catalina.session."; + loader.loadClass(basePackage + "StandardSession"); + loader.loadClass(basePackage + "StandardSession$1"); + loader.loadClass(basePackage + "StandardManager$PrivilegedDoUnload"); } @@ -229,6 +222,10 @@ public final class SecurityClassLoad { Class<?> clazz = loader.loadClass( basePackage + "util.http.FastHttpDateFormat"); clazz.newInstance(); + + // security + loader.loadClass(basePackage + "util.security.PrivilegedGetTccl"); + loader.loadClass(basePackage + "util.security.PrivilegedSetTccl"); } } Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/servlets/DefaultServlet.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/servlets/DefaultServlet.java?rev=1593821&r1=1593820&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/servlets/DefaultServlet.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/servlets/DefaultServlet.java Sun May 11 17:15:52 2014 @@ -31,6 +31,7 @@ import java.io.RandomAccessFile; 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; @@ -68,6 +69,8 @@ import org.apache.naming.resources.Cache import org.apache.naming.resources.ProxyDirContext; import org.apache.naming.resources.Resource; import org.apache.naming.resources.ResourceAttributes; +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; @@ -1326,11 +1329,27 @@ public class DefaultServlet sb.append("]]></readme>"); } - sb.append("</listing>"); - + // 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); @@ -1343,6 +1362,13 @@ public class DefaultServlet 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); + } } } Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java?rev=1593821&r1=1593820&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/session/StandardSession.java Sun May 11 17:15:52 2014 @@ -60,6 +60,7 @@ import org.apache.catalina.core.Standard import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.security.SecurityUtil; import org.apache.catalina.session.ManagerBase.SessionTiming; +import org.apache.tomcat.util.security.PrivilegedSetTccl; /** * Standard implementation of the <b>Session</b> interface. This object is @@ -1744,28 +1745,9 @@ public class StandardSession (sm.getString("standardSession.attributeEvent"), t); } } - } - - - private static class PrivilegedSetTccl - implements PrivilegedAction<Void> { - - private ClassLoader cl; - - PrivilegedSetTccl(ClassLoader cl) { - this.cl = cl; - } - - public Void run() { - Thread.currentThread().setContextClassLoader(cl); - return null; - } - } - } - // ------------------------------------------------------------ Protected Class Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELFunctionMapper.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELFunctionMapper.java?rev=1593821&r1=1593820&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELFunctionMapper.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELFunctionMapper.java Sun May 11 17:15:52 2014 @@ -24,6 +24,7 @@ import javax.servlet.jsp.tagext.Function import org.apache.jasper.Constants; import org.apache.jasper.JasperException; +import org.apache.tomcat.util.security.PrivilegedGetTccl; /** * This class generates functions mappers for the EL expressions in the page. @@ -307,13 +308,5 @@ public class ELFunctionMapper { return clazz.getCanonicalName(); } } - - private static class PrivilegedGetTccl - implements PrivilegedAction<ClassLoader> { - - public ClassLoader run() { - return Thread.currentThread().getContextClassLoader(); - } - } } Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java?rev=1593821&r1=1593820&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java Sun May 11 17:15:52 2014 @@ -20,7 +20,7 @@ import java.io.CharArrayWriter; 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; @@ -36,6 +36,8 @@ 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.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; @@ -1454,33 +1456,58 @@ class JspDocumentParser 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); + } + } } /* Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/xmlparser/ParserUtils.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/xmlparser/ParserUtils.java?rev=1593821&r1=1593820&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/jasper/xmlparser/ParserUtils.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/xmlparser/ParserUtils.java Sun May 11 17:15:52 2014 @@ -18,6 +18,7 @@ package org.apache.jasper.xmlparser; 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.jasper.compiler.Locali 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; @@ -105,7 +108,23 @@ public class ParserUtils { 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); @@ -129,23 +148,30 @@ public class ParserUtils { // 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); - } catch (SAXParseException ex) { - throw new JasperException - (Localizer.getMessage("jsp.error.parse.xml.line", - location, - Integer.toString(ex.getLineNumber()), - Integer.toString(ex.getColumnNumber())), - ex); - } catch (SAXException sx) { - throw new JasperException - (Localizer.getMessage("jsp.error.parse.xml", location), sx); + } catch (ParserConfigurationException ex) { + throw new JasperException( + Localizer.getMessage("jsp.error.parse.xml", location), ex); + } catch (SAXParseException ex) { + throw new JasperException( + Localizer.getMessage("jsp.error.parse.xml.line", + location, + Integer.toString(ex.getLineNumber()), + Integer.toString(ex.getColumnNumber())), + ex); + } catch (SAXException sx) { + throw new JasperException( + Localizer.getMessage("jsp.error.parse.xml", location), sx); } catch (IOException io) { - throw new JasperException - (Localizer.getMessage("jsp.error.parse.xml", location), 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 return (convert(null, document.getDocumentElement())); Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedGetTccl.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedGetTccl.java?rev=1593821&r1=1593818&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedGetTccl.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedGetTccl.java Sun May 11 17:15:52 2014 @@ -19,7 +19,6 @@ package org.apache.tomcat.util.security; import java.security.PrivilegedAction; public class PrivilegedGetTccl implements PrivilegedAction<ClassLoader> { - @Override public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedSetTccl.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedSetTccl.java?rev=1593821&r1=1593818&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedSetTccl.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/security/PrivilegedSetTccl.java Sun May 11 17:15:52 2014 @@ -26,7 +26,6 @@ public class PrivilegedSetTccl implement this.cl = cl; } - @Override public Void run() { Thread.currentThread().setContextClassLoader(cl); return null; Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1593821&r1=1593820&r2=1593821&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Sun May 11 17:15:52 2014 @@ -99,6 +99,11 @@ Ensure that a TLD parser obtained from the cache has the correct value of <code>blockExternal</code>. (markt/kkolinko) </fix> + <add> + Extend XML factory, parser etc. memory leak protection to cover some + additional locations where, theoretically, a memory leak could occur. + (markt) + </add> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org