Skip to content

Commit

Permalink
Add an option to the Context to control the blocking of XML external …
Browse files Browse the repository at this point in the history
…entities when parsing XML configuration files and enable this blocking by default. The block is implemented via a custom resolver to enable the logging of any blocked entities.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1549528 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
markt-asf committed Dec 9, 2013
1 parent 70dc3b2 commit 05c84ff
Show file tree
Hide file tree
Showing 29 changed files with 351 additions and 109 deletions.
19 changes: 19 additions & 0 deletions java/org/apache/catalina/Context.java
Expand Up @@ -616,6 +616,25 @@ public void setSessionCookiePathUsesTrailingSlash(
public void setXmlValidation(boolean xmlValidation);


/**
* 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 boolean getXmlBlockExternal();


/**
* 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 void setXmlBlockExternal(boolean xmlBlockExternal);


/**
* Will the parsing of *.tld files for this Context be performed by a
* validating parser?
Expand Down
11 changes: 11 additions & 0 deletions java/org/apache/catalina/Globals.java
Expand Up @@ -279,4 +279,15 @@ public final class Globals {
*/
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.
* <p>
* 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";
}
6 changes: 5 additions & 1 deletion java/org/apache/catalina/ant/ValidatorTask.java
Expand Up @@ -24,6 +24,7 @@
import java.io.FileInputStream;
import java.io.InputStream;

import org.apache.catalina.Globals;
import org.apache.catalina.startup.Constants;
import org.apache.tomcat.util.descriptor.DigesterFactory;
import org.apache.tomcat.util.digester.Digester;
Expand Down Expand Up @@ -90,7 +91,10 @@ public void execute() throws BuildException {
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 =
Expand Down
17 changes: 14 additions & 3 deletions java/org/apache/catalina/core/ApplicationContext.java
Expand Up @@ -304,12 +304,20 @@ public String getContextPath() {
*/
@Override
public String getInitParameter(final String name) {
// Special handling for XML validation as the context setting must
// 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);
}

Expand All @@ -322,11 +330,14 @@ public String getInitParameter(final String name) {
public Enumeration<String> getInitParameterNames() {
Set<String> names = new HashSet<>();
names.addAll(parameters.keySet());
// Special handling for XML validation as this attribute will always be
// available if validation has been enabled on the context
// 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);
}

Expand Down
19 changes: 19 additions & 0 deletions java/org/apache/catalina/core/StandardContext.java
Expand Up @@ -699,6 +699,13 @@ public StandardContext() {
*/
private boolean webXmlNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE;


/**
* Attribute used to turn on/off the use of external entities.
*/
private boolean xmlBlockExternal = Globals.IS_SECURITY_ENABLED;


/**
* Attribute value used to turn on/off XML validation
*/
Expand Down Expand Up @@ -6386,6 +6393,18 @@ public boolean getXmlValidation() {
}


@Override
public void setXmlBlockExternal(boolean xmlBlockExternal) {
this.xmlBlockExternal = xmlBlockExternal;
}


@Override
public boolean getXmlBlockExternal() {
return xmlBlockExternal;
}


@Override
public void setTldValidation(boolean tldValidation) {
this.tldValidation = tldValidation;
Expand Down
2 changes: 1 addition & 1 deletion java/org/apache/catalina/startup/ContextConfig.java
Expand Up @@ -730,7 +730,7 @@ protected void init() {
contextConfig(contextDigester);

webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
context.getXmlValidation());
context.getXmlValidation(), context.getXmlBlockExternal());
}


Expand Down
5 changes: 5 additions & 0 deletions java/org/apache/catalina/startup/FailedContext.java
Expand Up @@ -455,6 +455,11 @@ public void setXmlNamespaceAware(boolean xmlNamespaceAware) { /* NO-OP */ }
@Override
public void setXmlValidation(boolean xmlValidation) { /* NO-OP */ }

@Override
public boolean getXmlBlockExternal() { return true; }
@Override
public void setXmlBlockExternal(boolean xmlBlockExternal) { /* NO-OP */ }

@Override
public boolean getTldValidation() { return false; }
@Override
Expand Down
9 changes: 9 additions & 0 deletions java/org/apache/jasper/Constants.java
Expand Up @@ -160,4 +160,13 @@ public class Constants {
*/
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.
* <p>
* 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";
}
18 changes: 17 additions & 1 deletion java/org/apache/jasper/JspC.java
Expand Up @@ -134,6 +134,7 @@ public class JspC extends Task implements Options {
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;
Expand Down Expand Up @@ -165,6 +166,7 @@ public class JspC extends Task implements Options {
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;
Expand Down Expand Up @@ -373,6 +375,8 @@ public void setArgs(String[] arg) throws JasperException {
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 +
Expand Down Expand Up @@ -860,6 +864,14 @@ public boolean isValidateTld() {
return validateTld;
}

public void setBlockExternal( boolean b ) {
this.blockExternal = b;
}

public boolean isBlockExternal() {
return blockExternal;
}

public void setListErrors( boolean b ) {
listErrors = b;
}
Expand Down Expand Up @@ -1440,8 +1452,12 @@ protected void initServletContext(ClassLoader classLoader)
if (isValidateTld()) {
context.setInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM, "true");
}
if (isBlockExternal()) {
context.setInitParameter(Constants.XML_BLOCK_EXTERNAL_INIT_PARAM, "true");
}

TldScanner scanner = new TldScanner(context, true, isValidateTld());
TldScanner scanner = new TldScanner(
context, true, isValidateTld(), isBlockExternal());
scanner.setClassLoader(classLoader);

try {
Expand Down
15 changes: 13 additions & 2 deletions java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java
Expand Up @@ -24,6 +24,7 @@
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;
Expand Down Expand Up @@ -119,10 +120,20 @@ public ImplicitTagLibraryInfo(JspCompilationContext ctxt,
try {
URL url = ctxt.getResource(path);
TldResourcePath resourcePath = new TldResourcePath(url, path);
ServletContext servletContext = ctxt.getServletContext();
boolean validate = Boolean.parseBoolean(
ctxt.getServletContext().getInitParameter(
servletContext.getInitParameter(
Constants.XML_VALIDATION_TLD_INIT_PARAM));
TldParser parser = new TldParser(true, validate, new ImplicitTldRuleSet());
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);
}
TldParser parser = new TldParser(true, validate,
new ImplicitTldRuleSet(), blockExternal);
taglibXml = parser.parse(resourcePath);
} catch (IOException | SAXException e) {
err.jspError(e);
Expand Down
42 changes: 37 additions & 5 deletions java/org/apache/jasper/compiler/JspDocumentParser.java
Expand Up @@ -28,8 +28,11 @@
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.apache.tomcat.util.descriptor.tld.TldResourcePath;
import org.apache.tomcat.util.scan.Jar;
import org.xml.sax.Attributes;
Expand All @@ -39,6 +42,7 @@
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.DefaultHandler2;
import org.xml.sax.ext.EntityResolver2;
import org.xml.sax.helpers.AttributesImpl;

/**
Expand Down Expand Up @@ -91,6 +95,7 @@ class JspDocumentParser
private boolean inDTD;

private boolean isValidating;
private final EntityResolver2 entityResolver;

private final ErrorDispatcher err;
private final boolean isTagFile;
Expand Down Expand Up @@ -119,6 +124,20 @@ public JspDocumentParser(
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);
}

/*
Expand Down Expand Up @@ -232,13 +251,26 @@ private void addInclude(Node parent, Collection<String> files) throws SAXExcepti
}
}


@Override
public InputSource getExternalSubset(String name, String baseURI)
throws SAXException, IOException {
return entityResolver.getExternalSubset(name, baseURI);
}

@Override
public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId)
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
// TODO URLs returned by the Jar abstraction may be of the form jar:jar: which
// is not a URL that can be resolved by the JRE. This should use the JarFactory
// to construct and return a valid InputSource.
return null;
return entityResolver.resolveEntity(publicId, systemId);
}

@Override
public InputSource resolveEntity(String name, String publicId,
String baseURI, String systemId) throws SAXException, IOException {
// TODO URLs returned by the Jar abstraction may be of the form jar:jar:
// which is not a URL that can be resolved by the JRE. This should
// use the JarFactory to construct and return a valid InputSource.
return entityResolver.resolveEntity(name, publicId, baseURI, systemId);
}

/*
Expand Down
12 changes: 11 additions & 1 deletion java/org/apache/jasper/compiler/TagPluginManager.java
Expand Up @@ -24,6 +24,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;
Expand Down Expand Up @@ -61,7 +62,16 @@ private void init(ErrorDispatcher err) throws JasperException {
if (initialized)
return;

TagPluginParser parser = new TagPluginParser(ctxt);
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);
}

TagPluginParser parser = new TagPluginParser(ctxt, blockExternal);

try {
Enumeration<URL> urls =
Expand Down
10 changes: 9 additions & 1 deletion java/org/apache/jasper/compiler/TldCache.java
Expand Up @@ -74,7 +74,15 @@ public TldCache(ServletContext servletContext,
}
boolean validate = Boolean.parseBoolean(
servletContext.getInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM));
tldParser = new TldParser(true, validate);
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);
}
tldParser = new TldParser(true, validate, blockExternal);
}


Expand Down
10 changes: 9 additions & 1 deletion java/org/apache/jasper/servlet/JasperInitializer.java
Expand Up @@ -80,9 +80,17 @@ public void onStartup(Set<Class<?>> types, ServletContext context) throws Servle

boolean validate = Boolean.parseBoolean(
context.getInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM));
String blockExternalString = context.getInitParameter(
Constants.XML_BLOCK_EXTERNAL_INIT_PARAM);
boolean blockExternal;
if (blockExternalString == null) {
blockExternal = Constants.IS_SECURITY_ENABLED;
} else {
blockExternal = Boolean.parseBoolean(blockExternalString);
}

// scan the application for TLDs
TldScanner scanner = new TldScanner(context, true, validate);
TldScanner scanner = new TldScanner(context, true, validate, blockExternal);
try {
scanner.scan();
} catch (IOException | SAXException e) {
Expand Down

0 comments on commit 05c84ff

Please sign in to comment.