Hello community, here is the log from the commit of package dom4j for openSUSE:Factory checked in at 2018-09-26 16:01:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dom4j (Old) and /work/SRC/openSUSE:Factory/.dom4j.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dom4j" Wed Sep 26 16:01:44 2018 rev:21 rq:636366 version:1.6.1 Changes: -------- --- /work/SRC/openSUSE:Factory/dom4j/dom4j.changes 2018-07-24 17:33:01.584110366 +0200 +++ /work/SRC/openSUSE:Factory/.dom4j.new/dom4j.changes 2018-09-26 16:01:50.144450738 +0200 @@ -1,0 +2,10 @@ +Tue Sep 18 10:31:28 UTC 2018 - [email protected] + +- Security fix: [bsc#1105443, CVE-2018-1000632] + * Version prior to version 2.1.1 contains a CWE-91: XML + Injectionvulnerability in Class: Element. Methods: addElement, + addAttribute that canresult in an attacker tampering with XML + documents through. + * Added dom4j-CVE-2018-1000632.patch + +------------------------------------------------------------------- New: ---- dom4j-CVE-2018-1000632.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dom4j.spec ++++++ --- /var/tmp/diff_new_pack.ujUEeD/_old 2018-09-26 16:01:51.260448803 +0200 +++ /var/tmp/diff_new_pack.ujUEeD/_new 2018-09-26 16:01:51.260448803 +0200 @@ -37,6 +37,8 @@ Patch0: dom4j-1.6.1-bug1618750.patch Patch1: dom4j-sourcetarget.patch Patch2: dom4j-javadoc.patch +# PATCH-FIX-UPSTREAM bsc#1105443 CVE-2018-1000632 +Patch3: dom4j-CVE-2018-1000632.patch BuildRequires: ant >= 1.6.5 BuildRequires: ant-apache-resolver BuildRequires: ant-junit @@ -130,6 +132,7 @@ %patch0 -p1 -b .bug1618750 %patch1 -p1 -b .sourcetarget %patch2 -p1 -b .javadoc +%patch3 -p1 perl -pi -e 's/\r//g' LICENSE.txt docs/clover/*.css docs/style/*.css docs/xref/*.css docs/xref-test/*.css src/doc/style/*.css docs/benchmarks/xpath/*.java pushd lib @@ -187,7 +190,7 @@ cp -pr xml %{buildroot}%{_datadir}/%{name} mkdir -p %{buildroot}%{_datadir}/%{name}/src cp -pr src/samples %{buildroot}%{_datadir}/%{name}/src -#cp -pr build/classes/org/dom4j/samples $RPM_BUILD_ROOT%{_datadir}/%{name}/classes/org/dom4j +#cp -pr build/classes/org/dom4j/samples $RPM_BUILD_ROOT%%{_datadir}/%%{name}/classes/org/dom4j install -m 0755 run.sh %{buildroot}%{_datadir}/%{name} %fdupes -s %{buildroot}%{_javadocdir}/%{name} %fdupes -s %{buildroot}%{_docdir}/%{name}-%{version} ++++++ dom4j-CVE-2018-1000632.patch ++++++ Index: dom4j/src/java/org/dom4j/Namespace.java =================================================================== --- dom4j.orig/src/java/org/dom4j/Namespace.java +++ dom4j/src/java/org/dom4j/Namespace.java @@ -51,6 +51,10 @@ public class Namespace extends AbstractN public Namespace(String prefix, String uri) { this.prefix = (prefix != null) ? prefix : ""; this.uri = (uri != null) ? uri : ""; + + if (!this.prefix.isEmpty()) { + QName.validateNCName(this.prefix); + } } /** Index: dom4j/src/java/org/dom4j/QName.java =================================================================== --- dom4j.orig/src/java/org/dom4j/QName.java +++ dom4j/src/java/org/dom4j/QName.java @@ -11,6 +11,7 @@ import java.io.IOException; 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; @@ -20,6 +21,7 @@ import org.dom4j.util.SingletonStrategy; * <code>QName</code> represents a qualified name value of an XML element or * attribute. It consists of a local name and a {@link Namespace}instance. This * object is immutable. + * @author Filip Jirsak * </p> * * @author <a href="mailto:[email protected]">James Strachan </a> @@ -28,6 +30,81 @@ public class QName implements Serializab /** The Singleton instance */ private static SingletonStrategy 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} + * {@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"; @@ -73,6 +150,11 @@ public class QName implements Serializab 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) { @@ -80,6 +162,8 @@ public class QName implements Serializab this.qualifiedName = qualifiedName; this.namespace = (namespace == null) ? Namespace.NO_NAMESPACE : namespace; + validateNCName(this.name); + validateQName(this.qualifiedName); } public static QName get(String name) { @@ -253,6 +337,24 @@ public class QName implements Serializab QNameCache cache = (QNameCache) 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)); + } + } } Index: dom4j/src/java/org/dom4j/tree/QNameCache.java =================================================================== --- dom4j.orig/src/java/org/dom4j/tree/QNameCache.java +++ dom4j/src/java/org/dom4j/tree/QNameCache.java @@ -164,6 +164,8 @@ public class QNameCache { 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); Index: dom4j/src/test/org/dom4j/AllowedCharsTest.java =================================================================== --- /dev/null +++ dom4j/src/test/org/dom4j/AllowedCharsTest.java @@ -0,0 +1,78 @@ +package org.dom4j;^M +^M +import org.testng.annotations.Test;^M +^M +/**^M + * @author Filip Jirsak^M + */^M +public class AllowedCharsTest {^M + @Test^M + public void localName() {^M + QName.get("element");^M + QName.get(":element");^M + QName.get("elem:ent");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void localNameFail() {^M + QName.get("!element");^M + }^M +^M + @Test^M + public void qname() {^M + QName.get("element", "http://example.com/namespace");^M + QName.get("ns:element", "http://example.com/namespace");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void qnameFail1() {^M + QName.get("ns:elem:ent", "http://example.com/namespace");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void qnameFail2() {^M + QName.get(":nselement", "http://example.com/namespace");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void createElementLT() {^M + DocumentHelper.createElement("element<name");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void createElementGT() {^M + DocumentHelper.createElement("element>name");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void createElementAmpersand() {^M + DocumentHelper.createElement("element&name");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void addElement() {^M + Element root = DocumentHelper.createElement("root");^M + root.addElement("element>name");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void addElementQualified() {^M + Element root = DocumentHelper.createElement("root");^M + root.addElement("element>name", "http://example.com/namespace");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void addElementQualifiedPrefix() {^M + Element root = DocumentHelper.createElement("root");^M + root.addElement("ns:element>name", "http://example.com/namespace");^M + }^M +^M + @Test(expectedExceptions = IllegalArgumentException.class)^M + public void addElementPrefix() {^M + Element root = DocumentHelper.createElement("root");^M + root.addElement("ns>:element", "http://example.com/namespace");^M + }^M +^M + //TODO It is illegal to create element or attribute with namespace prefix and empty namespace IRI.^M + //See https://www.w3.org/TR/2006/REC-xml-names11-20060816/#scoping^M +}^M
