[Buildroot] [PATCH v2] package/qt5/qt5base: fix CVE-2021-38593
Quentin Schulz
quentin.schulz at theobroma-systems.com
Fri Jan 21 16:50:46 UTC 2022
5.15.2 is the last public release of 5.15 and does not contain this CVE
fix. However, >=6.1.2 and >5.12.12 all contain the necessary patches so
let's port them to 5.15.2.
Technically only the first two patches are required to patch the CVE.
However, the second patch introduces a regression that is fixed in the third
patch.
The patches are taken from KDE kde/5.15 git branch.
Cc: Quentin Schulz <foss+buildroot at 0leil.net>
Signed-off-by: Quentin Schulz <quentin.schulz at theobroma-systems.com>
---
v2:
- added third patch for fixing regression introduced by the second patch,
- cherry-picked commits from kde git kde/5.15 branch instead of taking
patches from 5.12.12 since they all applied nicely,
...-intensive-painting-of-high-number-o.patch | 163 ++++++++++++++++++
...-avoiding-huge-number-of-tiny-dashes.patch | 37 ++++
...-avoiding-huge-number-of-tiny-dashes.patch | 100 +++++++++++
package/qt5/qt5base/qt5base.mk | 4 +
4 files changed, 304 insertions(+)
create mode 100644 package/qt5/qt5base/0010-Avoid-processing-intensive-painting-of-high-number-o.patch
create mode 100644 package/qt5/qt5base/0011-Improve-fix-for-avoiding-huge-number-of-tiny-dashes.patch
create mode 100644 package/qt5/qt5base/0012-Refix-for-avoiding-huge-number-of-tiny-dashes.patch
diff --git a/package/qt5/qt5base/0010-Avoid-processing-intensive-painting-of-high-number-o.patch b/package/qt5/qt5base/0010-Avoid-processing-intensive-painting-of-high-number-o.patch
new file mode 100644
index 0000000000..03287d19ca
--- /dev/null
+++ b/package/qt5/qt5base/0010-Avoid-processing-intensive-painting-of-high-number-o.patch
@@ -0,0 +1,163 @@
+From 307bc02e379e63aa9b7a3d21bbcd9c84d34c600f Mon Sep 17 00:00:00 2001
+From: Eirik Aavitsland <eirik.aavitsland at qt.io>
+Date: Tue, 13 Apr 2021 14:23:45 +0200
+Subject: [PATCH] Avoid processing-intensive painting of high number of tiny
+ dashes
+
+When stroking a dashed path, an unnecessary amount of processing would
+be spent if there is a huge number of dashes visible, e.g. because of
+scaling. Since the dashes are too small to be indivdually visible
+anyway, just replace with a semi-transparent solid line for such
+cases.
+
+Pick-to: 6.1 6.0 5.15
+Change-Id: I9e9f7861257ad5bce46a0cf113d1a9d7824911e6
+Reviewed-by: Allan Sandfeld Jensen <allan.jensen at qt.io>
+(cherry picked from commit f4d791b330d02777fcaf02938732892eb3167e9b)
+
+* asturmlechner 2021-08-21:
+Conflict from preceding 94dd2ceb in dev branch:
+ src/gui/painting/qpaintengineex.cpp
+ Resolved via:
+
+ if (pen.style() > Qt::SolidLine) {
+ QRectF cpRect = path.controlPointRect();
+ const QTransform &xf = state()->matrix;
+- if (pen.isCosmetic()) {
++ if (qt_pen_is_cosmetic(pen, state()->renderHints)){
+ clipRect = d->exDeviceRect;
+ cpRect.translate(xf.dx(), xf.dy());
+ } else {
+
+FTBFS from preceding 471e4fcb in dev branch changing QVector to QList:
+ Resolved via:
+
+ QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
+ qreal extent = qMax(extentRect.width(), extentRect.height());
+ qreal patternLength = 0;
+- const QList<qreal> pattern = pen.dashPattern();
++ const QVector<qreal> pattern = pen.dashPattern();
+ const int patternSize = qMin(pattern.size(), 32);
+ for (int i = 0; i < patternSize; i++)
+ patternLength += qMax(pattern.at(i), qreal(0));
+
+[Retrieved from: https://invent.kde.org/qt/qt/qtbase/-/commit/081d835c040a90f8ee76807354355062ac521dfb]
+Signed-off-by: Quentin Schulz <quentin.schulz at theobroma-systems.com>
+---
+ src/gui/painting/qpaintengineex.cpp | 44 +++++++++++++++----
+ .../other/lancelot/scripts/tinydashes.qps | 34 ++++++++++++++
+ 2 files changed, 69 insertions(+), 9 deletions(-)
+ create mode 100644 tests/auto/other/lancelot/scripts/tinydashes.qps
+
+diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
+index 5d8f89eadd..55fdb0c2a0 100644
+--- a/src/gui/painting/qpaintengineex.cpp
++++ b/src/gui/painting/qpaintengineex.cpp
+@@ -385,7 +385,7 @@ QPainterState *QPaintEngineEx::createState(QPainterState *orig) const
+
+ Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
+
+-void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
++void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
+ {
+ #ifdef QT_DEBUG_DRAW
+ qDebug() << "QPaintEngineEx::stroke()" << pen;
+@@ -403,6 +403,38 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
+ d->stroker.setCubicToHook(qpaintengineex_cubicTo);
+ }
+
++ QRectF clipRect;
++ QPen pen = inPen;
++ if (pen.style() > Qt::SolidLine) {
++ QRectF cpRect = path.controlPointRect();
++ const QTransform &xf = state()->matrix;
++ if (qt_pen_is_cosmetic(pen, state()->renderHints)){
++ clipRect = d->exDeviceRect;
++ cpRect.translate(xf.dx(), xf.dy());
++ } else {
++ clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
++ }
++ // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
++ QRectF extentRect = cpRect & clipRect;
++ qreal extent = qMax(extentRect.width(), extentRect.height());
++ qreal patternLength = 0;
++ const QVector<qreal> pattern = pen.dashPattern();
++ const int patternSize = qMin(pattern.size(), 32);
++ for (int i = 0; i < patternSize; i++)
++ patternLength += qMax(pattern.at(i), qreal(0));
++ if (pen.widthF())
++ patternLength *= pen.widthF();
++ if (qFuzzyIsNull(patternLength)) {
++ pen.setStyle(Qt::NoPen);
++ } else if (extent / patternLength > 10000) {
++ // approximate stream of tiny dashes with semi-transparent solid line
++ pen.setStyle(Qt::SolidLine);
++ QColor color(pen.color());
++ color.setAlpha(color.alpha() / 2);
++ pen.setColor(color);
++ }
++ }
++
+ if (!qpen_fast_equals(pen, d->strokerPen)) {
+ d->strokerPen = pen;
+ d->stroker.setJoinStyle(pen.joinStyle());
+@@ -430,14 +462,8 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
+ return;
+ }
+
+- if (pen.style() > Qt::SolidLine) {
+- if (qt_pen_is_cosmetic(pen, state()->renderHints)){
+- d->activeStroker->setClipRect(d->exDeviceRect);
+- } else {
+- QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect));
+- d->activeStroker->setClipRect(clipRect);
+- }
+- }
++ if (!clipRect.isNull())
++ d->activeStroker->setClipRect(clipRect);
+
+ if (d->activeStroker == &d->stroker)
+ d->stroker.setForceOpen(path.hasExplicitOpen());
+diff --git a/tests/auto/other/lancelot/scripts/tinydashes.qps b/tests/auto/other/lancelot/scripts/tinydashes.qps
+new file mode 100644
+index 0000000000..d41ced7f5f
+--- /dev/null
++++ b/tests/auto/other/lancelot/scripts/tinydashes.qps
+@@ -0,0 +1,34 @@
++# Version: 1
++# CheckVsReference: 5%
++
++path_addEllipse mypath 20.0 20.0 200.0 200.0
++
++save
++setPen blue 20 SolidLine FlatCap
++pen_setCosmetic true
++pen_setDashPattern [ 0.0004 0.0004 ]
++setBrush yellow
++
++drawPath mypath
++translate 300 0
++setRenderHint Antialiasing true
++drawPath mypath
++restore
++
++path_addEllipse bigpath 200000.0 200000.0 2000000.0 2000000.0
++
++setPen blue 20 DotLine FlatCap
++setBrush yellow
++
++save
++translate 0 300
++scale 0.0001 0.00011
++drawPath bigpath
++restore
++
++save
++translate 300 300
++setRenderHint Antialiasing true
++scale 0.0001 0.00011
++drawPath bigpath
++restore
+--
+2.34.1
+
diff --git a/package/qt5/qt5base/0011-Improve-fix-for-avoiding-huge-number-of-tiny-dashes.patch b/package/qt5/qt5base/0011-Improve-fix-for-avoiding-huge-number-of-tiny-dashes.patch
new file mode 100644
index 0000000000..16e0f20200
--- /dev/null
+++ b/package/qt5/qt5base/0011-Improve-fix-for-avoiding-huge-number-of-tiny-dashes.patch
@@ -0,0 +1,37 @@
+From 856d11f695fb6effe26a359f9ad0efdf24067085 Mon Sep 17 00:00:00 2001
+From: Eirik Aavitsland <eirik.aavitsland at qt.io>
+Date: Fri, 23 Jul 2021 15:53:56 +0200
+Subject: [PATCH] Improve fix for avoiding huge number of tiny dashes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some pathological cases were not caught by the previous fix.
+
+Fixes: QTBUG-95239
+Pick-to: 6.2 6.1 5.15
+Change-Id: I0337ee3923ff93ccb36c4d7b810a9c0667354cc5
+Reviewed-by: Robert Löhning <robert.loehning at qt.io>
+(cherry picked from commit 6b400e3147dcfd8cc3a393ace1bd118c93762e0c)
+[Retrieved from: https://invent.kde.org/qt/qt/qtbase/-/commit/fed5713eeba5bf8e0ee413cb4e77109bfa7c2bce]
+Signed-off-by: Quentin Schulz <quentin.schulz at theobroma-systems.com>
+---
+ src/gui/painting/qpaintengineex.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
+index 55fdb0c2a0..19e4b23423 100644
+--- a/src/gui/painting/qpaintengineex.cpp
++++ b/src/gui/painting/qpaintengineex.cpp
+@@ -426,7 +426,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
+ patternLength *= pen.widthF();
+ if (qFuzzyIsNull(patternLength)) {
+ pen.setStyle(Qt::NoPen);
+- } else if (extent / patternLength > 10000) {
++ } else if (qFuzzyIsNull(extent) || extent / patternLength > 10000) {
+ // approximate stream of tiny dashes with semi-transparent solid line
+ pen.setStyle(Qt::SolidLine);
+ QColor color(pen.color());
+--
+2.34.1
+
diff --git a/package/qt5/qt5base/0012-Refix-for-avoiding-huge-number-of-tiny-dashes.patch b/package/qt5/qt5base/0012-Refix-for-avoiding-huge-number-of-tiny-dashes.patch
new file mode 100644
index 0000000000..ca3c2736ae
--- /dev/null
+++ b/package/qt5/qt5base/0012-Refix-for-avoiding-huge-number-of-tiny-dashes.patch
@@ -0,0 +1,100 @@
+From 3b1a60f651776a7b2d155803b07a52a9e27bdf78 Mon Sep 17 00:00:00 2001
+From: Eirik Aavitsland <eirik.aavitsland at qt.io>
+Date: Fri, 30 Jul 2021 13:03:49 +0200
+Subject: [PATCH] Refix for avoiding huge number of tiny dashes
+
+Previous fix hit too widely so some valid horizontal and vertical
+lines were affected; the root problem being that such lines have an
+empty control point rect (width or height is 0). Fix by caculating in
+the pen width.
+
+Pick-to: 6.2 6.1 5.15
+Change-Id: I7a436e873f6d485028f6759d0e2c6456f07eebdc
+Reviewed-by: Allan Sandfeld Jensen <allan.jensen at qt.io>
+(cherry picked from commit 84aba80944a2e1c3058d7a1372e0e66676411884)
+[Retrieved from: https://invent.kde.org/qt/qt/qtbase/-/commit/427df34efdcb56582a9ae9f7d2d1f39eeff70328]
+Signed-off-by: Quentin Schulz <quentin.schulz at theobroma-systems.com>
+---
+ src/gui/painting/qpaintengineex.cpp | 8 ++---
+ .../gui/painting/qpainter/tst_qpainter.cpp | 31 +++++++++++++++++++
+ 2 files changed, 35 insertions(+), 4 deletions(-)
+
+diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
+index 19e4b23423..9fe510827a 100644
+--- a/src/gui/painting/qpaintengineex.cpp
++++ b/src/gui/painting/qpaintengineex.cpp
+@@ -415,18 +415,18 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
+ clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
+ }
+ // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
+- QRectF extentRect = cpRect & clipRect;
++ qreal pw = pen.widthF() ? pen.widthF() : 1;
++ QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
+ qreal extent = qMax(extentRect.width(), extentRect.height());
+ qreal patternLength = 0;
+ const QVector<qreal> pattern = pen.dashPattern();
+ const int patternSize = qMin(pattern.size(), 32);
+ for (int i = 0; i < patternSize; i++)
+ patternLength += qMax(pattern.at(i), qreal(0));
+- if (pen.widthF())
+- patternLength *= pen.widthF();
++ patternLength *= pw;
+ if (qFuzzyIsNull(patternLength)) {
+ pen.setStyle(Qt::NoPen);
+- } else if (qFuzzyIsNull(extent) || extent / patternLength > 10000) {
++ } else if (extent / patternLength > 10000) {
+ // approximate stream of tiny dashes with semi-transparent solid line
+ pen.setStyle(Qt::SolidLine);
+ QColor color(pen.color());
+diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
+index 42e98ce363..d7c3f95f1d 100644
+--- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
++++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
+@@ -308,6 +308,7 @@ private slots:
+ void fillPolygon();
+
+ void drawImageAtPointF();
++ void scaledDashes();
+
+ private:
+ void fillData();
+@@ -5468,6 +5469,36 @@ void tst_QPainter::drawImageAtPointF()
+ paint.end();
+ }
+
++void tst_QPainter::scaledDashes()
++{
++ // Test that we do not hit the limit-huge-number-of-dashes path
++ QRgb fore = qRgb(0, 0, 0xff);
++ QRgb back = qRgb(0xff, 0xff, 0);
++ QImage image(5, 32, QImage::Format_RGB32);
++ image.fill(back);
++ QPainter p(&image);
++ QPen pen(QColor(fore), 3, Qt::DotLine);
++ p.setPen(pen);
++ p.scale(1, 2);
++ p.drawLine(2, 0, 2, 16);
++ p.end();
++
++ bool foreFound = false;
++ bool backFound = false;
++ int i = 0;
++ while (i < 32 && (!foreFound || !backFound)) {
++ QRgb pix = image.pixel(3, i);
++ if (pix == fore)
++ foreFound = true;
++ else if (pix == back)
++ backFound = true;
++ i++;
++ }
++
++ QVERIFY(foreFound);
++ QVERIFY(backFound);
++}
++
+ QTEST_MAIN(tst_QPainter)
+
+ #include "tst_qpainter.moc"
+--
+2.34.1
+
diff --git a/package/qt5/qt5base/qt5base.mk b/package/qt5/qt5base/qt5base.mk
index bcdf036f00..4ef3759566 100644
--- a/package/qt5/qt5base/qt5base.mk
+++ b/package/qt5/qt5base/qt5base.mk
@@ -11,6 +11,10 @@ QT5BASE_SOURCE = qtbase-$(QT5_SOURCE_TARBALL_PREFIX)-$(QT5BASE_VERSION).tar.xz
QT5BASE_DEPENDENCIES = host-pkgconf pcre2 zlib
QT5BASE_INSTALL_STAGING = YES
+# 0010-Avoid-processing-intensive-painting-of-high-number-o.patch
+# 0011-Improve-fix-for-avoiding-huge-number-of-tiny-dashes.patch
+QT5BASE_IGNORE_CVES += CVE-2021-38593
+
# A few comments:
# * -no-pch to workaround the issue described at
# http://comments.gmane.org/gmane.comp.lib.qt.devel/5933.
--
2.34.1
More information about the buildroot
mailing list