patch
This commit is contained in:
parent
712d62d6cf
commit
07578962c8
152
CVE-2018-1000632-pre.patch
Normal file
152
CVE-2018-1000632-pre.patch
Normal file
@ -0,0 +1,152 @@
|
||||
From 92d87957c4c4948d048ff7729c77ba10474f73ae Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Filip=20Jirs=C3=A1k?= <filip@jirsak.org>
|
||||
Date: Sun, 1 Jul 2018 13:06:18 +0200
|
||||
Subject: [PATCH] Fix tests with invalid QNames.
|
||||
|
||||
---
|
||||
.../java/org/dom4j/datatype/SchemaParser.java | 29 +++++++++++--------
|
||||
src/test/java/org/dom4j/IteratorTest.java | 20 ++++++-------
|
||||
src/test/java/org/dom4j/dom/DOMTest.java | 2 +-
|
||||
3 files changed, 28 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/src/main/java/org/dom4j/datatype/SchemaParser.java b/src/main/java/org/dom4j/datatype/SchemaParser.java
|
||||
index c35806ba..ab299d82 100644
|
||||
--- a/src/main/java/org/dom4j/datatype/SchemaParser.java
|
||||
+++ b/src/main/java/org/dom4j/datatype/SchemaParser.java
|
||||
@@ -180,15 +180,19 @@ private void onDatatypeElement(Element xsdElement,
|
||||
DocumentFactory parentFactory) {
|
||||
String name = xsdElement.attributeValue("name");
|
||||
String type = xsdElement.attributeValue("type");
|
||||
- QName qname = getQName(name);
|
||||
|
||||
- DatatypeElementFactory factory = getDatatypeElementFactory(qname);
|
||||
+ QName qname = null;
|
||||
+ DatatypeElementFactory factory = null;
|
||||
+ if (name != null) {
|
||||
+ qname = getQName(name);
|
||||
+ factory = getDatatypeElementFactory(qname);
|
||||
+ }
|
||||
|
||||
if (type != null) {
|
||||
// register type with this element name
|
||||
XSDatatype dataType = getTypeByName(type);
|
||||
|
||||
- if (dataType != null) {
|
||||
+ if (dataType != null && factory != null) {
|
||||
factory.setChildElementXSDatatype(qname, dataType);
|
||||
} else {
|
||||
QName typeQName = getQName(type);
|
||||
@@ -205,24 +209,25 @@ private void onDatatypeElement(Element xsdElement,
|
||||
if (xsdSimpleType != null) {
|
||||
XSDatatype dataType = loadXSDatatypeFromSimpleType(xsdSimpleType);
|
||||
|
||||
- if (dataType != null) {
|
||||
+ if (dataType != null && factory != null) {
|
||||
factory.setChildElementXSDatatype(qname, dataType);
|
||||
}
|
||||
}
|
||||
|
||||
Element schemaComplexType = xsdElement.element(XSD_COMPLEXTYPE);
|
||||
|
||||
- if (schemaComplexType != null) {
|
||||
+ if (schemaComplexType != null && factory != null) {
|
||||
onSchemaComplexType(schemaComplexType, factory);
|
||||
}
|
||||
|
||||
- Iterator<Element> iter = xsdElement.elementIterator(XSD_ATTRIBUTE);
|
||||
-
|
||||
- if (iter.hasNext()) {
|
||||
- do {
|
||||
- onDatatypeAttribute(xsdElement, factory, iter
|
||||
- .next());
|
||||
- } while (iter.hasNext());
|
||||
+ if (factory != null) {
|
||||
+ Iterator<Element> iter = xsdElement.elementIterator(XSD_ATTRIBUTE);
|
||||
+ if (iter.hasNext()) {
|
||||
+ do {
|
||||
+ onDatatypeAttribute(xsdElement, factory, iter
|
||||
+ .next());
|
||||
+ } while (iter.hasNext());
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/test/java/org/dom4j/IteratorTest.java b/src/test/java/org/dom4j/IteratorTest.java
|
||||
index 76a2eef8..53091ae9 100644
|
||||
--- a/src/test/java/org/dom4j/IteratorTest.java
|
||||
+++ b/src/test/java/org/dom4j/IteratorTest.java
|
||||
@@ -31,7 +31,7 @@ public void setUp() throws Exception {
|
||||
Element root = iterDocument.addElement("root");
|
||||
|
||||
for (int i = 0; i < NUMELE; i++) {
|
||||
- root.addElement("iterator test").addAttribute("instance",
|
||||
+ root.addElement("iterator-test").addAttribute("instance",
|
||||
Integer.toString(i));
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public void testElementCount() throws Exception {
|
||||
Element root = iterDocument.getRootElement();
|
||||
assertTrue("Has root element", root != null);
|
||||
|
||||
- List elements = root.elements("iterator test");
|
||||
+ List elements = root.elements("iterator-test");
|
||||
int elementSize = elements.size();
|
||||
assertTrue("Root has " + elementSize + " children", (elements != null)
|
||||
&& (elementSize == NUMELE));
|
||||
@@ -50,8 +50,8 @@ public void testElementCount() throws Exception {
|
||||
|
||||
public void testPlainIteration() throws Exception {
|
||||
Element root = iterDocument.getRootElement();
|
||||
- List elements = root.elements("iterator test");
|
||||
- Iterator iter = root.elementIterator("iterator test");
|
||||
+ List elements = root.elements("iterator-test");
|
||||
+ Iterator iter = root.elementIterator("iterator-test");
|
||||
int elementSize = elements.size();
|
||||
|
||||
int count = 0;
|
||||
@@ -69,8 +69,8 @@ public void testPlainIteration() throws Exception {
|
||||
|
||||
public void testSkipAlternates() throws Exception {
|
||||
Element root = iterDocument.getRootElement();
|
||||
- List elements = root.elements("iterator test");
|
||||
- Iterator iter = root.elementIterator("iterator test");
|
||||
+ List elements = root.elements("iterator-test");
|
||||
+ Iterator iter = root.elementIterator("iterator-test");
|
||||
int elementSize = elements.size();
|
||||
int count = 0;
|
||||
|
||||
@@ -89,8 +89,8 @@ public void testSkipAlternates() throws Exception {
|
||||
|
||||
public void testNoHasNext() throws Exception {
|
||||
Element root = iterDocument.getRootElement();
|
||||
- List elements = root.elements("iterator test");
|
||||
- Iterator iter = root.elementIterator("iterator test");
|
||||
+ List elements = root.elements("iterator-test");
|
||||
+ Iterator iter = root.elementIterator("iterator-test");
|
||||
int elementSize = elements.size();
|
||||
int count = 0;
|
||||
Element e = null;
|
||||
@@ -121,8 +121,8 @@ public void testNoHasNext() throws Exception {
|
||||
|
||||
public void testExtraHasNexts() throws Exception {
|
||||
Element root = iterDocument.getRootElement();
|
||||
- List elements = root.elements("iterator test");
|
||||
- Iterator iter = root.elementIterator("iterator test");
|
||||
+ List elements = root.elements("iterator-test");
|
||||
+ Iterator iter = root.elementIterator("iterator-test");
|
||||
int elementSize = elements.size();
|
||||
int count = 0;
|
||||
|
||||
diff --git a/src/test/java/org/dom4j/dom/DOMTest.java b/src/test/java/org/dom4j/dom/DOMTest.java
|
||||
index f44d3e80..4b1f9c85 100644
|
||||
--- a/src/test/java/org/dom4j/dom/DOMTest.java
|
||||
+++ b/src/test/java/org/dom4j/dom/DOMTest.java
|
||||
@@ -109,7 +109,7 @@ public void testReplaceChild() throws Exception {
|
||||
assertEquals(newFirst, firstChild);
|
||||
|
||||
/* try to replace a node that doesn't exist */
|
||||
- org.w3c.dom.Element badNode = document.createElement("No Child");
|
||||
+ org.w3c.dom.Element badNode = document.createElement("No-Child");
|
||||
|
||||
try {
|
||||
parent.replaceChild(newFirst, badNode);
|
||||
257
CVE-2018-1000632.patch
Normal file
257
CVE-2018-1000632.patch
Normal file
@ -0,0 +1,257 @@
|
||||
diff --git a/src/main/java/org/dom4j/Namespace.java b/src/main/java/org/dom4j/Namespace.java
|
||||
index fd123b93..8f948ad8 100644
|
||||
--- a/src/main/java/org/dom4j/Namespace.java
|
||||
+++ b/src/main/java/org/dom4j/Namespace.java
|
||||
@@ -49,6 +49,10 @@
|
||||
public Namespace(String prefix, String uri) {
|
||||
this.prefix = (prefix != null) ? prefix : "";
|
||||
this.uri = (uri != null) ? uri : "";
|
||||
+
|
||||
+ if (!this.prefix.isEmpty()) {
|
||||
+ QName.validateNCName(this.prefix);
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/src/main/java/org/dom4j/QName.java b/src/main/java/org/dom4j/QName.java
|
||||
index 9ac0d4d8..e9b2170e 100644
|
||||
--- a/src/main/java/org/dom4j/QName.java
|
||||
+++ b/src/main/java/org/dom4j/QName.java
|
||||
@@ -11,6 +11,7 @@
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
+import java.util.regex.Pattern;
|
||||
|
||||
import org.dom4j.tree.QNameCache;
|
||||
import org.dom4j.util.SingletonStrategy;
|
||||
@@ -21,11 +22,86 @@
|
||||
* object is immutable.
|
||||
*
|
||||
* @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
|
||||
+ * @author Filip Jirsák
|
||||
*/
|
||||
public class QName implements Serializable {
|
||||
/** The Singleton instance */
|
||||
private static SingletonStrategy<QNameCache> singleton = null;
|
||||
|
||||
+ /**
|
||||
+ * {@code NameStartChar} without colon.
|
||||
+ *
|
||||
+ * <pre>NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]</pre>
|
||||
+ *
|
||||
+ * @see <a href="https://www.w3.org/TR/xml/#sec-common-syn">XML 1.0 – 2.3 Common Syntactic Constructs</a>
|
||||
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn">XML 1.1 – 2.3 Common Syntactic Constructs</a>
|
||||
+ */
|
||||
+ private static final String NAME_START_CHAR = "_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD";
|
||||
+
|
||||
+ /**
|
||||
+ * {@code NameChar} without colon.
|
||||
+ *
|
||||
+ * <pre>NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]</pre>
|
||||
+ *
|
||||
+ * @see <a href="https://www.w3.org/TR/xml/#sec-common-syn">XML 1.0 – 2.3 Common Syntactic Constructs</a>
|
||||
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn">XML 1.1 – 2.3 Common Syntactic Constructs</a>
|
||||
+ */
|
||||
+ private static final String NAME_CHAR = NAME_START_CHAR + "-.0-9\u00B7\u0300-\u036F\u203F-\u2040";
|
||||
+
|
||||
+ /**
|
||||
+ * {@code NCName}
|
||||
+ *
|
||||
+ * <pre>
|
||||
+ * NCName ::= NCNameStartChar NCNameChar* (An XML Name, minus the ":")
|
||||
+ * NCNameChar ::= NameChar -':'
|
||||
+ * NCNameStartChar ::= NameStartChar -':'
|
||||
+ * </pre>
|
||||
+ *
|
||||
+ * @see <a href="https://www.w3.org/TR/xml-names/#ns-qualnames">Namespaces in XML 1.0 – 4 Qualified Names</a>
|
||||
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml-names11-20060816/#ns-qualnames">Namespaces in XML 1.1 – 4 Qualified Names</a>
|
||||
+ */
|
||||
+ private static final String NCNAME = "["+NAME_START_CHAR+"]["+NAME_CHAR+"]*";
|
||||
+
|
||||
+ /**
|
||||
+ * Regular expression for {@code Name} (with colon).
|
||||
+ *
|
||||
+ * <pre>Name ::= NameStartChar (NameChar)*</pre>
|
||||
+ *
|
||||
+ * @see <a href="https://www.w3.org/TR/xml/#sec-common-syn">XML 1.0 – 2.3 Common Syntactic Constructs</a>
|
||||
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn">XML 1.1 – 2.3 Common Syntactic Constructs</a>
|
||||
+ */
|
||||
+ private static final Pattern RE_NAME = Pattern.compile("[:"+NAME_START_CHAR+"][:"+NAME_CHAR+"]*");
|
||||
+
|
||||
+ /**
|
||||
+ * Regular expression for {@code NCName}.
|
||||
+ *
|
||||
+ * <pre>
|
||||
+ * NCName ::= NCNameStartChar NCNameChar* (An XML Name, minus the ":")
|
||||
+ * NCNameChar ::= NameChar -':'
|
||||
+ * NCNameStartChar ::= NameStartChar -':'
|
||||
+ * </pre>
|
||||
+ *
|
||||
+ * @see <a href="https://www.w3.org/TR/xml-names/#ns-qualnames">Namespaces in XML 1.0 – 4 Qualified Names</a>
|
||||
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml-names11-20060816/#ns-qualnames">Namespaces in XML 1.1 – 4 Qualified Names</a>
|
||||
+ */
|
||||
+ private static final Pattern RE_NCNAME = Pattern.compile(NCNAME);
|
||||
+
|
||||
+ /**
|
||||
+ * Regular expression for {@code QName}.
|
||||
+ *
|
||||
+ * <pre>
|
||||
+ * QName ::= PrefixedName | UnprefixedName
|
||||
+ * PrefixedName ::= Prefix ':' LocalPart
|
||||
+ * UnprefixedName ::= LocalPart
|
||||
+ * Prefix ::= NCName
|
||||
+ * LocalPart ::= NCName
|
||||
+ * </pre>
|
||||
+ *
|
||||
+ * @see <a href="https://www.w3.org/TR/xml-names/#ns-qualnames">Namespaces in XML 1.0 – 4 Qualified Names</a>
|
||||
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml-names11-20060816/#ns-qualnames">Namespaces in XML 1.1 – 4 Qualified Names</a>
|
||||
+ */
|
||||
+ private static final Pattern RE_QNAME = Pattern.compile("(?:"+NCNAME+":)?"+NCNAME);
|
||||
+
|
||||
static {
|
||||
try {
|
||||
String defaultSingletonClass = "org.dom4j.util.SimpleSingleton";
|
||||
@@ -71,6 +147,11 @@ public QName(String name, Namespace namespace) {
|
||||
this.name = (name == null) ? "" : name;
|
||||
this.namespace = (namespace == null) ? Namespace.NO_NAMESPACE
|
||||
: namespace;
|
||||
+ if (this.namespace.equals(Namespace.NO_NAMESPACE)) {
|
||||
+ validateName(this.name);
|
||||
+ } else {
|
||||
+ validateNCName(this.name);
|
||||
+ }
|
||||
}
|
||||
|
||||
public QName(String name, Namespace namespace, String qualifiedName) {
|
||||
@@ -78,6 +159,8 @@ public QName(String name, Namespace namespace, String qualifiedName) {
|
||||
this.qualifiedName = qualifiedName;
|
||||
this.namespace = (namespace == null) ? Namespace.NO_NAMESPACE
|
||||
: namespace;
|
||||
+ validateNCName(this.name);
|
||||
+ validateQName(this.qualifiedName);
|
||||
}
|
||||
|
||||
public static QName get(String name) {
|
||||
@@ -251,6 +334,24 @@ private static QNameCache getCache() {
|
||||
QNameCache cache = singleton.instance();
|
||||
return cache;
|
||||
}
|
||||
+
|
||||
+ private static void validateName(String name) {
|
||||
+ if (!RE_NAME.matcher(name).matches()) {
|
||||
+ throw new IllegalArgumentException(String.format("Illegal character in name: '%s'.", name));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected static void validateNCName(String ncname) {
|
||||
+ if (!RE_NCNAME.matcher(ncname).matches()) {
|
||||
+ throw new IllegalArgumentException(String.format("Illegal character in local name: '%s'.", ncname));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void validateQName(String qname) {
|
||||
+ if (!RE_QNAME.matcher(qname).matches()) {
|
||||
+ throw new IllegalArgumentException(String.format("Illegal character in qualified name: '%s'.", qname));
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/dom4j/tree/QNameCache.java b/src/main/java/org/dom4j/tree/QNameCache.java
|
||||
index 330f3794..d37e8aaa 100644
|
||||
--- a/src/main/java/org/dom4j/tree/QNameCache.java
|
||||
+++ b/src/main/java/org/dom4j/tree/QNameCache.java
|
||||
@@ -152,6 +152,8 @@ public QName get(String qualifiedName, String uri) {
|
||||
|
||||
if (index < 0) {
|
||||
return get(qualifiedName, Namespace.get(uri));
|
||||
+ } else if (index == 0){
|
||||
+ throw new IllegalArgumentException("Qualified name cannot start with ':'.");
|
||||
} else {
|
||||
String name = qualifiedName.substring(index + 1);
|
||||
String prefix = qualifiedName.substring(0, index);
|
||||
diff --git a/src/test/java/org/dom4j/AllowedCharsTest.java b/src/test/java/org/dom4j/AllowedCharsTest.java
|
||||
new file mode 100644
|
||||
index 00000000..20c1de0b
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/org/dom4j/AllowedCharsTest.java
|
||||
@@ -0,0 +1,78 @@
|
||||
+package org.dom4j;
|
||||
+
|
||||
+import org.testng.annotations.Test;
|
||||
+
|
||||
+/**
|
||||
+ * @author Filip Jirsák
|
||||
+ */
|
||||
+public class AllowedCharsTest {
|
||||
+ @Test
|
||||
+ public void localName() {
|
||||
+ QName.get("element");
|
||||
+ QName.get(":element");
|
||||
+ QName.get("elem:ent");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void localNameFail() {
|
||||
+ QName.get("!element");
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void qname() {
|
||||
+ QName.get("element", "http://example.com/namespace");
|
||||
+ QName.get("ns:element", "http://example.com/namespace");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void qnameFail1() {
|
||||
+ QName.get("ns:elem:ent", "http://example.com/namespace");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void qnameFail2() {
|
||||
+ QName.get(":nselement", "http://example.com/namespace");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void createElementLT() {
|
||||
+ DocumentHelper.createElement("element<name");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void createElementGT() {
|
||||
+ DocumentHelper.createElement("element>name");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void createElementAmpersand() {
|
||||
+ DocumentHelper.createElement("element&name");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void addElement() {
|
||||
+ Element root = DocumentHelper.createElement("root");
|
||||
+ root.addElement("element>name");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void addElementQualified() {
|
||||
+ Element root = DocumentHelper.createElement("root");
|
||||
+ root.addElement("element>name", "http://example.com/namespace");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void addElementQualifiedPrefix() {
|
||||
+ Element root = DocumentHelper.createElement("root");
|
||||
+ root.addElement("ns:element>name", "http://example.com/namespace");
|
||||
+ }
|
||||
+
|
||||
+ @Test(expectedExceptions = IllegalArgumentException.class)
|
||||
+ public void addElementPrefix() {
|
||||
+ Element root = DocumentHelper.createElement("root");
|
||||
+ root.addElement("ns>:element", "http://example.com/namespace");
|
||||
+ }
|
||||
+
|
||||
+ //TODO It is illegal to create element or attribute with namespace prefix and empty namespace IRI.
|
||||
+ //See https://www.w3.org/TR/2006/REC-xml-names11-20060816/#scoping
|
||||
+}
|
||||
|
||||
BIN
dom4j-2.0.0-6.fc29.src.rpm
Normal file
BIN
dom4j-2.0.0-6.fc29.src.rpm
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user