[SCM] qtbase packaging branch, master, updated. debian/5.1.1+dfsg-5-2-gdb0eb79

Lisandro Damián Nicanor Pérez lisandro at moszumanska.debian.org
Thu Dec 5 15:03:53 UTC 2013


Gitweb-URL: http://git.debian.org/?p=pkg-kde/qt/qtbase.git;a=commitdiff;h=db0eb79

The following commit has been merged in the master branch:
commit db0eb79841147a5838385b232029991841809d17
Author: Lisandro Damián Nicanor Pérez Meyer <perezmeyer at gmail.com>
Date:   Thu Dec 5 12:03:24 2013 -0300

    Backport Disallow_deep_or_widely_nested_entity_references.patch
    
    Fix CVE-2013-4549: XML Entity Expansion Denial of Service.
---
 debian/changelog                                   |   4 +
 ...w_deep_or_widely_nested_entity_references.patch | 261 +++++++++++++++++++++
 debian/patches/series                              |   1 +
 3 files changed, 266 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index ecc8f57..51411ac 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,9 @@
 qtbase-opensource-src (5.1.1+dfsg-6) UNRELEASED; urgency=low
 
+  [ Lisandro Damián Nicanor Pérez Meyer ]
+  * Backport Disallow_deep_or_widely_nested_entity_references.patch to fix
+    CVE-2013-4549: XML Entity Expansion Denial of Service.
+
  -- Debian Qt/KDE Maintainers <debian-qt-kde at lists.debian.org>  Thu, 05 Dec 2013 11:59:03 -0300
 
 qtbase-opensource-src (5.1.1+dfsg-5) unstable; urgency=low
diff --git a/debian/patches/Disallow_deep_or_widely_nested_entity_references.patch b/debian/patches/Disallow_deep_or_widely_nested_entity_references.patch
new file mode 100644
index 0000000..c74e477
--- /dev/null
+++ b/debian/patches/Disallow_deep_or_widely_nested_entity_references.patch
@@ -0,0 +1,261 @@
+From b57ddb1aff55a20a07b27135c6eab268764527fd Mon Sep 17 00:00:00 2001
+From: Mitch Curtis <mitch.curtis at digia.com>
+Date: Fri, 27 Sep 2013 12:32:28 +0200
+Subject: [PATCH] Disallow deep or widely nested entity references.
+
+Nested entities with a depth of 2 or more will fail. Entities
+that fully expand to more than 1024 characters will also fail.
+
+Change-Id: I75525bc1edfa796c4db30a5109fe21011ad43a2d
+Reviewed-by: Richard J. Moore <rich at kde.org>
+Reviewed-by: Lars Knoll <lars.knoll at digia.com>
+(cherries picked from commits 46a8885ae486e238a39efa5119c2714f328b08e4
+and f1053d94f59f053ce4acad9320df14f1fbe4faac)
+---
+ src/xml/sax/qxml.cpp                               | 63 ++++++++++++++++++++++
+ .../sax/qxmlsimplereader/tst_qxmlsimplereader.cpp  | 58 ++++++++++++++++++++
+ .../xmldocs/1-levels-nested-dtd.xml                | 12 +++++
+ .../xmldocs/2-levels-nested-dtd.xml                | 13 +++++
+ .../internal-entity-polynomial-attribute.xml       | 13 +++++
+ 5 files changed, 159 insertions(+)
+ create mode 100644 tests/auto/xml/sax/qxmlsimplereader/xmldocs/1-levels-nested-dtd.xml
+ create mode 100644 tests/auto/xml/sax/qxmlsimplereader/xmldocs/2-levels-nested-dtd.xml
+ create mode 100644 tests/auto/xml/sax/qxmlsimplereader/xmldocs/internal-entity-polynomial-attribute.xml
+
+diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp
+index 0e20041..5ddcf27 100644
+--- a/src/xml/sax/qxml.cpp
++++ b/src/xml/sax/qxml.cpp
+@@ -424,6 +424,12 @@ private:
+     int     stringValueLen;
+     QString emptyStr;
+ 
++    // The limit to the amount of times the DTD parsing functions can be called
++    // for the DTD currently being parsed.
++    static const int dtdRecursionLimit = 2;
++    // The maximum amount of characters an entity value may contain, after expansion.
++    static const int entityCharacterLimit = 1024;
++
+     const QString &string();
+     void stringClear();
+     void stringAddC(QChar);
+@@ -493,6 +499,8 @@ private:
+     void parseFailed(ParseFunction where, int state);
+     void pushParseState(ParseFunction function, int state);
+ 
++    bool isExpandedEntityValueTooLarge(QString *errorMessage);
++
+     Q_DECLARE_PUBLIC(QXmlSimpleReader)
+     QXmlSimpleReader *q_ptr;
+ 
+@@ -5035,6 +5043,11 @@ bool QXmlSimpleReaderPrivate::parseDoctype()
+                 }
+                 break;
+             case Mup:
++                if (dtdRecursionLimit > 0 && parameterEntities.size() > dtdRecursionLimit) {
++                    reportParseError(QString::fromLatin1(
++                        "DTD parsing exceeded recursion limit of %1.").arg(dtdRecursionLimit));
++                    return false;
++                }
+                 if (!parseMarkupdecl()) {
+                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
+                     return false;
+@@ -6644,6 +6657,50 @@ bool QXmlSimpleReaderPrivate::parseChoiceSeq()
+     return false;
+ }
+ 
++bool QXmlSimpleReaderPrivate::isExpandedEntityValueTooLarge(QString *errorMessage)
++{
++    QMap<QString, int> literalEntitySizes;
++    // The entity at (QMap<QString,) referenced the entities at (QMap<QString,) (int>) times.
++    QMap<QString, QMap<QString, int> > referencesToOtherEntities;
++    QMap<QString, int> expandedSizes;
++
++    // For every entity, check how many times all entity names were referenced in its value.
++    foreach (QString toSearch, entities.keys()) {
++        // The amount of characters that weren't entity names, but literals, like 'X'.
++        QString leftOvers = entities.value(toSearch);
++        // How many times was entityName referenced by toSearch?
++        foreach (QString entityName, entities.keys()) {
++            for (int i = 0; i < leftOvers.size() && i != -1; ) {
++                i = leftOvers.indexOf(QString::fromLatin1("&%1;").arg(entityName), i);
++                if (i != -1) {
++                    leftOvers.remove(i, entityName.size() + 2);
++                    // The entityName we're currently trying to find was matched in this string; increase our count.
++                    ++referencesToOtherEntities[toSearch][entityName];
++                }
++            }
++        }
++        literalEntitySizes[toSearch] = leftOvers.size();
++    }
++
++    foreach (QString entity, referencesToOtherEntities.keys()) {
++        expandedSizes[entity] = literalEntitySizes[entity];
++        foreach (QString referenceTo, referencesToOtherEntities.value(entity).keys()) {
++            const int references = referencesToOtherEntities.value(entity).value(referenceTo);
++            // The total size of an entity's value is the expanded size of all of its referenced entities, plus its literal size.
++            expandedSizes[entity] += expandedSizes[referenceTo] * references + literalEntitySizes[referenceTo] * references;
++        }
++
++        if (expandedSizes[entity] > entityCharacterLimit) {
++            if (errorMessage) {
++                *errorMessage = QString::fromLatin1("The XML entity \"%1\" expands too a string that is too large to process (%2 characters > %3).");
++                *errorMessage = (*errorMessage).arg(entity).arg(expandedSizes[entity]).arg(entityCharacterLimit);
++            }
++            return true;
++        }
++    }
++    return false;
++}
++
+ /*
+   Parse a EntityDecl [70].
+ 
+@@ -6738,6 +6795,12 @@ bool QXmlSimpleReaderPrivate::parseEntityDecl()
+         switch (state) {
+             case EValue:
+                 if ( !entityExist(name())) {
++                    QString errorMessage;
++                    if (isExpandedEntityValueTooLarge(&errorMessage)) {
++                        reportParseError(errorMessage);
++                        return false;
++                    }
++
+                     entities.insert(name(), string());
+                     if (declHnd) {
+                         if (!declHnd->internalEntityDecl(name(), string())) {
+diff --git a/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp b/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp
+index d4c0ff4..d6ad867 100644
+--- a/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp
++++ b/tests/auto/xml/sax/qxmlsimplereader/tst_qxmlsimplereader.cpp
+@@ -160,6 +160,7 @@ class tst_QXmlSimpleReader : public QObject
+         void reportNamespace() const;
+         void reportNamespace_data() const;
+         void roundtripWithNamespaces() const;
++        void dtdRecursionLimit();
+ 
+     private:
+         static QDomDocument fromByteArray(const QString &title, const QByteArray &ba, bool *ok);
+@@ -770,5 +771,62 @@ void tst_QXmlSimpleReader::roundtripWithNamespaces() const
+     }
+ }
+ 
++class TestHandler : public QXmlDefaultHandler
++{
++public:
++    TestHandler() :
++        recursionCount(0)
++    {
++    }
++
++    bool internalEntityDecl(const QString &name, const QString &value)
++    {
++        ++recursionCount;
++        return QXmlDefaultHandler::internalEntityDecl(name, value);
++    }
++
++    int recursionCount;
++};
++
++void tst_QXmlSimpleReader::dtdRecursionLimit()
++{
++    QFile file("xmldocs/2-levels-nested-dtd.xml");
++    QVERIFY(file.open(QIODevice::ReadOnly));
++    QXmlSimpleReader xmlReader;
++    {
++        QXmlInputSource *source = new QXmlInputSource(&file);
++        TestHandler handler;
++        xmlReader.setDeclHandler(&handler);
++        xmlReader.setErrorHandler(&handler);
++        QVERIFY(!xmlReader.parse(source));
++    }
++
++    file.close();
++    file.setFileName("xmldocs/1-levels-nested-dtd.xml");
++    QVERIFY(file.open(QIODevice::ReadOnly));
++    {
++        QXmlInputSource *source = new QXmlInputSource(&file);
++        TestHandler handler;
++        xmlReader.setDeclHandler(&handler);
++        xmlReader.setErrorHandler(&handler);
++        QVERIFY(!xmlReader.parse(source));
++        // The error wasn't because of the recursion limit being reached,
++        // it was because the document is not valid.
++        QVERIFY(handler.recursionCount < 2);
++    }
++
++    file.close();
++    file.setFileName("xmldocs/internal-entity-polynomial-attribute.xml");
++    QVERIFY(file.open(QIODevice::ReadOnly));
++    {
++        QXmlInputSource *source = new QXmlInputSource(&file);
++        TestHandler handler;
++        xmlReader.setDeclHandler(&handler);
++        xmlReader.setErrorHandler(&handler);
++        QVERIFY(!xmlReader.parse(source));
++        QCOMPARE(handler.recursionCount, 2);
++    }
++}
++
+ QTEST_MAIN(tst_QXmlSimpleReader)
+ #include "tst_qxmlsimplereader.moc"
+diff --git a/tests/auto/xml/sax/qxmlsimplereader/xmldocs/1-levels-nested-dtd.xml b/tests/auto/xml/sax/qxmlsimplereader/xmldocs/1-levels-nested-dtd.xml
+new file mode 100644
+index 0000000..0dfc15b
+--- /dev/null
++++ b/tests/auto/xml/sax/qxmlsimplereader/xmldocs/1-levels-nested-dtd.xml
+@@ -0,0 +1,12 @@
++<?xml version="1.0"?>
++<!-- Test non-deterministic content model matching.
++
++Entity references are not part of the internal DTD subset (for good reason).
++
++-->
++<!DOCTYPE root [
++<!ELEMENT e0 EMPTY>
++<!ENTITY % e1 "(e0,e0)">
++<!ELEMENT root (%e1;)?>
++]>
++<root/>
+\ No newline at end of file
+diff --git a/tests/auto/xml/sax/qxmlsimplereader/xmldocs/2-levels-nested-dtd.xml b/tests/auto/xml/sax/qxmlsimplereader/xmldocs/2-levels-nested-dtd.xml
+new file mode 100644
+index 0000000..7ec06db
+--- /dev/null
++++ b/tests/auto/xml/sax/qxmlsimplereader/xmldocs/2-levels-nested-dtd.xml
+@@ -0,0 +1,13 @@
++<?xml version="1.0"?>
++<!-- Test non-deterministic content model matching.
++
++Entity references are not part of the internal DTD subset (for good reason).
++
++-->
++<!DOCTYPE root [
++<!ELEMENT e0 EMPTY>
++<!ENTITY % e1 "(e0,e0)">
++<!ENTITY % e2 "(%e1;,%e1;,%e1;,%e1;,%e1;,%e1;,%e1;,%e1;,%e1;,%e1;,%e1;,%e1;,%e1;)">
++<!ELEMENT root (%e2;)?>
++]>
++<root/>
+diff --git a/tests/auto/xml/sax/qxmlsimplereader/xmldocs/internal-entity-polynomial-attribute.xml b/tests/auto/xml/sax/qxmlsimplereader/xmldocs/internal-entity-polynomial-attribute.xml
+new file mode 100644
+index 0000000..bbb88f3
+--- /dev/null
++++ b/tests/auto/xml/sax/qxmlsimplereader/xmldocs/internal-entity-polynomial-attribute.xml
+@@ -0,0 +1,13 @@
++<?xml version="1.0"?>
++<!-- Test polynomial growth of expanded XML.
++     Expansion happens in an attribute. -->
++<!DOCTYPE root [
++<!ELEMENT root EMPTY>
++<!ATTLIST root id CDATA #IMPLIED>
++<!ENTITY e1 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX">
++<!ENTITY e2 "&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;">
++<!ENTITY e3 "&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;">
++<!ENTITY e4 "&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;">
++]>
++<root id="&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;"/>
++
+-- 
+1.8.4.2
+
diff --git a/debian/patches/series b/debian/patches/series
index 348d46c..22e9ee9 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -2,5 +2,6 @@ sha3_64bit_BE.diff
 linux_no_perf.diff
 fix_usr-move_workaround_in_the_presence_of_multi-arch.patch
 hurd_opengl_incldir.diff
+Disallow_deep_or_widely_nested_entity_references.patch
 
 # Debian specific.

-- 
qtbase packaging



More information about the pkg-kde-commits mailing list