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 when a security manager is used. 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/tc7.0.x/trunk@1549529 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
markt-asf committed Dec 9, 2013
1 parent 72613a0 commit b9e06ea
Show file tree
Hide file tree
Showing 26 changed files with 374 additions and 102 deletions.
19 changes: 19 additions & 0 deletions java/org/apache/catalina/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,25 @@ public void setSessionCookiePathUsesTrailingSlash(
public void setTldNamespaceAware(boolean tldNamespaceAware);


/**
* 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
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,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
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,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 @@ -87,7 +88,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
Original file line number Diff line number Diff line change
Expand Up @@ -320,12 +320,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 @@ -338,11 +346,14 @@ public String getInitParameter(final String name) {
public Enumeration<String> getInitParameterNames() {
Set<String> names = new HashSet<String>();
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
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,13 @@ public StandardContext() {
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.
*/
Expand Down Expand Up @@ -6624,6 +6631,18 @@ public void setTldNamespaceAware(boolean tldNamespaceAware){
}


@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
6 changes: 4 additions & 2 deletions java/org/apache/catalina/startup/ContextConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -516,14 +516,16 @@ protected void authenticatorConfig() {
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();
}

Expand Down
5 changes: 5 additions & 0 deletions java/org/apache/catalina/startup/FailedContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,11 @@ public void setXmlValidation(boolean xmlValidation) { /* NO-OP */ }

@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; }

Expand Down
10 changes: 6 additions & 4 deletions java/org/apache/catalina/startup/TldConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,21 @@ public final class TldConfig implements LifecycleListener {
* Create (if necessary) and return a Digester configured to process the
* tld.
*/
private static Digester createTldDigester(boolean validation) {
private static Digester createTldDigester(boolean validation,
boolean blockExternal) {

Digester digester = null;
if (!validation) {
if (tldDigesters[0] == null) {
tldDigesters[0] = DigesterFactory.newDigester(validation,
true, new TldRuleSet());
true, new TldRuleSet(), blockExternal);
tldDigesters[0].getParser();
}
digester = tldDigesters[0];
} else {
if (tldDigesters[1] == null) {
tldDigesters[1] = DigesterFactory.newDigester(validation,
true, new TldRuleSet());
true, new TldRuleSet(), blockExternal);
tldDigesters[1].getParser();
}
digester = tldDigesters[1];
Expand Down Expand Up @@ -567,7 +568,8 @@ public void lifecycleEvent(LifecycleEvent event) {

private void init() {
if (tldDigester == null){
tldDigester = createTldDigester(context.getTldValidation());
tldDigester = createTldDigester(context.getTldValidation(),
context.getXmlBlockExternal());
}
}

Expand Down
9 changes: 9 additions & 0 deletions java/org/apache/jasper/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,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";
}
15 changes: 15 additions & 0 deletions java/org/apache/jasper/JspC.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,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 @@ -158,6 +159,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 @@ -367,6 +369,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 @@ -854,6 +858,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 @@ -1435,6 +1447,9 @@ protected void initServletContext() {
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);
Expand Down
17 changes: 14 additions & 3 deletions java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,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 @@ -124,11 +125,21 @@ public ImplicitTagLibraryInfo(JspCompilationContext ctxt,
pi.addDependant(path, ctxt.getLastModified(path));
}

ServletContext servletContext = ctxt.getServletContext();
boolean validate = Boolean.parseBoolean(
ctxt.getServletContext().getInitParameter(
servletContext.getInitParameter(
Constants.XML_VALIDATION_TLD_INIT_PARAM));

ParserUtils pu = new ParserUtils(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);
}

ParserUtils pu = new ParserUtils(validate, blockExternal);
TreeNode tld = pu.parseXMLDocument(uri, in);

if (tld.findAttribute("version") != null) {
Expand Down
10 changes: 9 additions & 1 deletion java/org/apache/jasper/compiler/JspConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,18 @@ private void processWebDotXml() throws JasperException {

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(validate);
ParserUtils pu = new ParserUtils(validate, blockExternal);
webApp = pu.parseXMLDocument(webXml.getSystemId(),
webXml.getInputSource());
}
Expand Down
38 changes: 37 additions & 1 deletion java/org/apache/jasper/compiler/JspDocumentParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,19 @@
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.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 ErrorDispatcher err;
private 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 @@ -239,12 +258,29 @@ private void addInclude(Node parent, List<String> files) throws SAXException {
}
}


@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 null;
return entityResolver.resolveEntity(name, publicId, baseURI, systemId);
}


/*
* Receives notification of the start of an element.
*
Expand Down
Loading

0 comments on commit b9e06ea

Please sign in to comment.