Blame SOURCES/qtsvg-do-stricter-error-checking-when-parsing-path-nodes.patch

8d2edd
From 5b9285c34731e67f9f1d61ec804740991f2a0380 Mon Sep 17 00:00:00 2001
8d2edd
From: Eirik Aavitsland <eirik.aavitsland@qt.io>
8d2edd
Date: Mon, 25 Oct 2021 14:17:55 +0200
8d2edd
Subject: [PATCH] Do stricter error checking when parsing path nodes
8d2edd
MIME-Version: 1.0
8d2edd
Content-Type: text/plain; charset=UTF-8
8d2edd
Content-Transfer-Encoding: 8bit
8d2edd
8d2edd
The SVG spec mandates that path parsing should terminate on the first
8d2edd
error encountered, and an error be reported. To improve the handling
8d2edd
of corrupt files, implement such error handling, and also limit the
8d2edd
number of QPainterPath elements to a reasonable range.
8d2edd
8d2edd
Fixes: QTBUG-96044
8d2edd
Pick-to: 6.2 5.15 5.12
8d2edd
Change-Id: Ic5e65d6b658516d6f1317c72de365c8c7ad81891
8d2edd
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
8d2edd
Reviewed-by: Robert Löhning <robert.loehning@qt.io>
8d2edd
(cherry picked from commit 36cfd9efb9b22b891adee9c48d30202289cfa620)
8d2edd
---
8d2edd
 src/svg/qsvghandler.cpp | 59 +++++++++++++++++------------------------
8d2edd
 1 file changed, 25 insertions(+), 34 deletions(-)
8d2edd
8d2edd
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
8d2edd
index b542089..2ea80ed 100644
8d2edd
--- a/src/svg/qsvghandler.cpp
8d2edd
+++ b/src/svg/qsvghandler.cpp
8d2edd
@@ -1627,6 +1627,7 @@ static void pathArc(QPainterPath &path,
8d2edd
8d2edd
 static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
 {
8d2edd
+    const int maxElementCount = 0x7fff; // Assume file corruption if more path elements than this
8d2edd
     qreal x0 = 0, y0 = 0;              // starting point
8d2edd
     qreal x = 0, y = 0;                // current point
8d2edd
     char lastMode = 0;
8d2edd
@@ -1634,7 +1635,8 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
     const QChar *str = dataStr.constData();
8d2edd
     const QChar *end = str + dataStr.size();
8d2edd
8d2edd
-    while (str != end) {
8d2edd
+    bool ok = true;
8d2edd
+    while (ok && str != end) {
8d2edd
         while (str->isSpace() && (str + 1) != end)
8d2edd
             ++str;
8d2edd
         QChar pathElem = *str;
8d2edd
@@ -1651,14 +1653,13 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             arg.append(0);//dummy
8d2edd
         const qreal *num = arg.constData();
8d2edd
         int count = arg.count();
8d2edd
-        while (count > 0) {
8d2edd
+        while (ok && count > 0) {
8d2edd
             qreal offsetX = x;        // correction offsets
8d2edd
             qreal offsetY = y;        // for relative commands
8d2edd
             switch (pathElem.unicode()) {
8d2edd
             case 'm': {
8d2edd
                 if (count < 2) {
8d2edd
-                    num++;
8d2edd
-                    count--;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 x = x0 = num[0] + offsetX;
8d2edd
@@ -1675,8 +1676,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
                 break;
8d2edd
             case 'M': {
8d2edd
                 if (count < 2) {
8d2edd
-                    num++;
8d2edd
-                    count--;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 x = x0 = num[0];
8d2edd
@@ -1702,8 +1702,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
                 break;
8d2edd
             case 'l': {
8d2edd
                 if (count < 2) {
8d2edd
-                    num++;
8d2edd
-                    count--;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 x = num[0] + offsetX;
8d2edd
@@ -1716,8 +1715,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
                 break;
8d2edd
             case 'L': {
8d2edd
                 if (count < 2) {
8d2edd
-                    num++;
8d2edd
-                    count--;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 x = num[0];
8d2edd
@@ -1757,8 +1755,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
                 break;
8d2edd
             case 'c': {
8d2edd
                 if (count < 6) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 QPointF c1(num[0] + offsetX, num[1] + offsetY);
8d2edd
@@ -1774,8 +1771,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
             case 'C': {
8d2edd
                 if (count < 6) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 QPointF c1(num[0], num[1]);
8d2edd
@@ -1791,8 +1787,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
             case 's': {
8d2edd
                 if (count < 4) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 QPointF c1;
8d2edd
@@ -1813,8 +1808,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
             case 'S': {
8d2edd
                 if (count < 4) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 QPointF c1;
8d2edd
@@ -1835,8 +1829,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
             case 'q': {
8d2edd
                 if (count < 4) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 QPointF c(num[0] + offsetX, num[1] + offsetY);
8d2edd
@@ -1851,8 +1844,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
             case 'Q': {
8d2edd
                 if (count < 4) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 QPointF c(num[0], num[1]);
8d2edd
@@ -1867,8 +1859,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
             case 't': {
8d2edd
                 if (count < 2) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 QPointF e(num[0] + offsetX, num[1] + offsetY);
8d2edd
@@ -1888,8 +1879,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
             case 'T': {
8d2edd
                 if (count < 2) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 QPointF e(num[0], num[1]);
8d2edd
@@ -1909,8 +1899,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
             case 'a': {
8d2edd
                 if (count < 7) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 qreal rx = (*num++);
8d2edd
@@ -1932,8 +1921,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
                 break;
8d2edd
             case 'A': {
8d2edd
                 if (count < 7) {
8d2edd
-                    num += count;
8d2edd
-                    count = 0;
8d2edd
+                    ok = false;
8d2edd
                     break;
8d2edd
                 }
8d2edd
                 qreal rx = (*num++);
8d2edd
@@ -1954,12 +1942,15 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
8d2edd
             }
8d2edd
                 break;
8d2edd
             default:
8d2edd
-                return false;
8d2edd
+                ok = false;
8d2edd
+                break;
8d2edd
             }
8d2edd
             lastMode = pathElem.toLatin1();
8d2edd
+            if (path.elementCount() > maxElementCount)
8d2edd
+                ok = false;
8d2edd
         }
8d2edd
     }
8d2edd
-    return true;
8d2edd
+    return ok;
8d2edd
 }
8d2edd
8d2edd
 static bool parseStyle(QSvgNode *node,
8d2edd
@@ -2997,8 +2988,8 @@ static QSvgNode *createPathNode(QSvgNode *parent,
8d2edd
8d2edd
     QPainterPath qpath;
8d2edd
     qpath.setFillRule(Qt::WindingFill);
8d2edd
-    //XXX do error handling
8d2edd
-    parsePathDataFast(data, qpath);
8d2edd
+    if (!parsePathDataFast(data, qpath))
8d2edd
+        qCWarning(lcSvgHandler, "Invalid path data; path truncated.");
8d2edd
8d2edd
     QSvgNode *path = new QSvgPath(parent, qpath);
8d2edd
     return path;
8d2edd
--
8d2edd
GitLab
8d2edd