Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion core/src/main/java/org/apache/calcite/runtime/XmlFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@
} catch (TransformerConfigurationException e) {
throw new IllegalStateException("Transformer Factory configuration failed", e);
}
try {
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Transformer Factory does not support restricting"
+ " access to external DTDs and stylesheets", e);
}
return transformerFactory;
});

Expand Down Expand Up @@ -147,17 +154,21 @@
}
try {
final Source xsltSource = new StreamSource(new StringReader(xslt));
final Source xmlSource = new StreamSource(new StringReader(xml));
final Transformer transformer =
TRANSFORMER_FACTORY.get().newTransformer(xsltSource);
final Source xmlSource = new DOMSource(getDocumentNode(xml));
final StringWriter writer = new StringWriter();
final StreamResult result = new StreamResult(writer);
transformer.setErrorListener(new InternalErrorListener());
transformer.transform(xmlSource, result);
return writer.toString();
} catch (IllegalArgumentException e) {
// getDocumentNode rejected the XML argument (e.g. it contains a
// DOCTYPE declaration, or is not well-formed).
throw RESOURCE.invalidInputForXmlTransform(xml).ex();
} catch (TransformerConfigurationException e) {
throw RESOURCE.illegalXslt(xslt).ex();
} catch (TransformerException e) {

Check warning on line 171 in core/src/main/java/org/apache/calcite/runtime/XmlFunctions.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Combine this catch with the one at line 165, which has the same body.

See more on https://sonarcloud.io/project/issues?id=apache_calcite&issues=AaCv80Zvyz3W5ou-SDXC&open=AaCv80Zvyz3W5ou-SDXC&pullRequest=5270
throw RESOURCE.invalidInputForXmlTransform(xml).ex();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,44 @@ class SqlXmlFunctionsTest {
assertXmlTransformFailed(XML, xsltExternalEntity, Matchers.expectThrowable(expected));
}

@Test void testXmlTransformDocumentFunctionDenied() {
String xslt = "<xsl:stylesheet version=\"1.0\""
+ " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
+ "<xsl:template match=\"/\">"
+ "<xsl:copy-of select=\"document('file:///dev/null')\"/>"
+ "</xsl:template></xsl:stylesheet>";
String message = "Invalid input for XMLTRANSFORM xml: '" + XML + "'";
CalciteException expected = new CalciteException(message, null);
assertXmlTransformFailed(XML, xslt, Matchers.expectThrowable(expected));
}

@Test void testXmlTransformXslIncludeDenied() {
String xslt = "<xsl:stylesheet version=\"1.0\""
+ " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
+ "<xsl:include href=\"file:///dev/null\"/>"
+ "</xsl:stylesheet>";
String message = "Illegal xslt specified : '" + xslt + "'";
CalciteException expected = new CalciteException(message, null);
assertXmlTransformFailed(XML, xslt, Matchers.expectThrowable(expected));
}

@Test void testXmlTransformXslImportDenied() {
String xslt = "<xsl:stylesheet version=\"1.0\""
+ " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
+ "<xsl:import href=\"file:///dev/null\"/>"
+ "</xsl:stylesheet>";
String message = "Illegal xslt specified : '" + xslt + "'";
CalciteException expected = new CalciteException(message, null);
assertXmlTransformFailed(XML, xslt, Matchers.expectThrowable(expected));
}

@Test void testXmlTransformDoctypeDenied() {
String xml = "<!DOCTYPE document [<!ENTITY a \"b\">]><document>&a;</document>";
String message = "Invalid input for XMLTRANSFORM xml: '" + xml + "'";
CalciteException expected = new CalciteException(message, null);
assertXmlTransformFailed(xml, XSLT, Matchers.expectThrowable(expected));
}

@Test void testXmlTransform() {
assertXmlTransform(null, "", nullValue());
assertXmlTransform("", null, nullValue());
Expand Down
6 changes: 3 additions & 3 deletions site/_docs/security_threat_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ land.
carries a `CancelFlag` in the planner context, so a deadline can build on it;
the firing and size caps are new.
* **Execution.** Catastrophic regex backtracking in `LIKE`, `SIMILAR TO`, or
`RLIKE`, or an unbounded join, exhausts resources at run time. Planning bounds
do not help here; the mitigation is a match-time limit or a backtracking-free
regex engine.
`RLIKE`, an unbounded XSLT program in `XMLTRANSFORM`, or an unbounded join,
exhausts resources at run time. Planning bounds do not help here; the
mitigation is a match-time limit or a backtracking-free regex engine.
* **Parsing.** Deeply nested expressions can overflow the parser stack. The
mitigation is a nesting-depth limit.

Expand Down
Loading