From 51a3c45a15e1a09d99a5e446bc28f2089e434f96 Mon Sep 17 00:00:00 2001 From: kkkl12 <1604145060@qq.com> Date: Fri, 18 Sep 2020 09:33:30 +0800 Subject: [PATCH 01/13] Fix Source0 --- qt5-qtbase.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 9435a75..dd77390 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,10 +13,10 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 9 +Release: 10 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ -Source0: https://download.qt.io/official_releases/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz +Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz Source1: qtlogging.ini Source2: qconfig-multilib.h Source3: 10-qt5-check-opengl2.sh @@ -401,6 +401,9 @@ fi %changelog +* Fri Sep 18 2020 liuweibo - 5.11.1-10 +- Fix Source0 + * Wed Dec 25 2019 fengbing - 5.11.1-9 - Type:cves - ID:CVE-2018-15518 -- Gitee From 36b47f882087cf9b5a64c8702507b2d24e00c4a6 Mon Sep 17 00:00:00 2001 From: jackie_wu Date: Mon, 21 Sep 2020 21:00:02 +0800 Subject: [PATCH 02/13] fix CVE-2015-9541 --- CVE-2015-9541.patch | 159 ++++++++++++++++++++++++++++++++++++++++++++ qt5-qtbase.spec | 6 +- 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 CVE-2015-9541.patch diff --git a/CVE-2015-9541.patch b/CVE-2015-9541.patch new file mode 100644 index 0000000..79a6874 --- /dev/null +++ b/CVE-2015-9541.patch @@ -0,0 +1,159 @@ +From fd4be84d23a0db4186cb42e736a9de3af722c7f7 Mon Sep 17 00:00:00 2001 +From: Lars Knoll +Date: Wed, 26 Feb 2020 10:42:10 +0100 +Subject: Add an expansion limit for entities + +Recursively defined entities can easily exhaust all available +memory. Limit entity expansion to a default of 4096 characters to +avoid DoS attacks when a user loads untrusted content. + +Added a setter and getter to allow modifying the expansion limit. + +[ChangeLog][QtCore][QXmlStream] QXmlStreamReader does now by default +limit the expansion of entities to 4096 characters. Documents where +a single entity expands to more characters than the limit are not +considered well formed. The limit is there to avoid DoS attacks through +recursively expanding entities when loading untrusted content. The +limit can be changed through the QXmlStreamReader::setEntityExpansionLimit() +method. + +Fixes: QTBUG-47417 +Change-Id: I94387815d74fcf34783e136387ee57fac5ded0c9 +Reviewed-by: Oswald Buddenhagen +Reviewed-by: Volker Hilsheimer +--- + src/corelib/serialization/qxmlstream.cpp | 36 ++++++++++++++++++ + src/corelib/serialization/qxmlstream.g | 14 ++++++- + src/corelib/serialization/qxmlstream.h | 2 + + src/corelib/serialization/qxmlstream_p.h | 14 ++++++- + .../serialization/qxmlstream/tst_qxmlstream.cpp | 44 +++++++++++++++++++++- + 5 files changed, 106 insertions(+), 4 deletions(-) + +diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp +index 7ff87885a5..d7fb0d0d41 100644 +--- a/src/corelib/serialization/qxmlstream.cpp ++++ b/src/corelib/serialization/qxmlstream.cpp +@@ -2041,6 +2041,42 @@ QStringRef QXmlStreamReader::dtdSystemId() const + return QStringRef(); + } + ++/*! ++ \since 5.15 ++ ++ Returns the maximum amount of characters a single entity is ++ allowed to expand into. If a single entity expands past the ++ given limit, the document is not considered well formed. ++ ++ \sa setEntityExpansionLimit ++*/ ++int QXmlStreamReader::entityExpansionLimit() const ++{ ++ Q_D(const QXmlStreamReader); ++ return d->entityExpansionLimit; ++} ++ ++/*! ++ \since 5.15 ++ ++ Sets the maximum amount of characters a single entity is ++ allowed to expand into to \a limit. If a single entity expands ++ past the given limit, the document is not considered well formed. ++ ++ The limit is there to prevent DoS attacks when loading unknown ++ XML documents where recursive entity expansion could otherwise ++ exhaust all available memory. ++ ++ The default value for this property is 4096 characters. ++ ++ \sa entityExpansionLimit ++*/ ++void QXmlStreamReader::setEntityExpansionLimit(int limit) ++{ ++ Q_D(QXmlStreamReader); ++ d->entityExpansionLimit = limit; ++} ++ + /*! If the tokenType() is \l StartElement, this function returns the + element's namespace declarations. Otherwise an empty vector is + returned. +diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g +index 12ecc9bdb2..b623de9505 100644 +--- a/src/corelib/serialization/qxmlstream.g ++++ b/src/corelib/serialization/qxmlstream.g +@@ -285,9 +285,19 @@ public: + QHash entityHash; + QHash parameterEntityHash; + QXmlStreamSimpleStackentityReferenceStack; ++ int entityExpansionLimit = 4096; ++ int entityLength = 0; + inline bool referenceEntity(Entity &entity) { + if (entity.isCurrentlyReferenced) { +- raiseWellFormedError(QXmlStream::tr("Recursive entity detected.")); ++ raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected.")); ++ return false; ++ } ++ // entityLength represents the amount of additional characters the ++ // entity expands into (can be negative for e.g. &). It's used to ++ // avoid DoS attacks through recursive entity expansions ++ entityLength += entity.value.size() - entity.name.size() - 2; ++ if (entityLength > entityExpansionLimit) { ++ raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit.")); + return false; + } + entity.isCurrentlyReferenced = true; +@@ -838,6 +848,8 @@ entity_done ::= ENTITY_DONE; + /. + case $rule_number: + entityReferenceStack.pop()->isCurrentlyReferenced = false; ++ if (entityReferenceStack.isEmpty()) ++ entityLength = 0; + clearSym(); + break; + ./ +diff --git a/src/corelib/serialization/qxmlstream.h b/src/corelib/serialization/qxmlstream.h +index 7d0aa64570..c8647e0465 100644 +--- a/src/corelib/serialization/qxmlstream.h ++++ b/src/corelib/serialization/qxmlstream.h +@@ -426,6 +426,8 @@ public: + QStringRef dtdPublicId() const; + QStringRef dtdSystemId() const; + ++ int entityExpansionLimit() const; ++ void setEntityExpansionLimit(int limit); + + enum Error { + NoError, +diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h +index 9c94e6d434..103b123b10 100644 +--- a/src/corelib/serialization/qxmlstream_p.h ++++ b/src/corelib/serialization/qxmlstream_p.h +@@ -774,9 +774,19 @@ public: + QHash entityHash; + QHash parameterEntityHash; + QXmlStreamSimpleStackentityReferenceStack; ++ int entityExpansionLimit = 4096; ++ int entityLength = 0; + inline bool referenceEntity(Entity &entity) { + if (entity.isCurrentlyReferenced) { +- raiseWellFormedError(QXmlStream::tr("Recursive entity detected.")); ++ raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected.")); ++ return false; ++ } ++ // entityLength represents the amount of additional characters the ++ // entity expands into (can be negative for e.g. &). It's used to ++ // avoid DoS attacks through recursive entity expansions ++ entityLength += entity.value.size() - entity.name.size() - 2; ++ if (entityLength > entityExpansionLimit) { ++ raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit.")); + return false; + } + entity.isCurrentlyReferenced = true; +@@ -1308,6 +1318,8 @@ bool QXmlStreamReaderPrivate::parse() + + case 10: + entityReferenceStack.pop()->isCurrentlyReferenced = false; ++ if (entityReferenceStack.isEmpty()) ++ entityLength = 0; + clearSym(); + break; + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index dd77390..c9d7a76 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 10 +Release: 11 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -35,6 +35,7 @@ Patch0010: qtbase-everywhere-src-5.11.1-python3.patch Patch0011: qt5-qtbase-glibc.patch Patch6000: CVE-2018-15518.patch +Patch6001: CVE-2015-9541.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -401,6 +402,9 @@ fi %changelog +* Mon Sep 21 2020 wutao - 5.11.1-11 +- fix CVE-2015-9541 + * Fri Sep 18 2020 liuweibo - 5.11.1-10 - Fix Source0 -- Gitee From 9422674c943a4c7b9c7e3a2c6d00a17f2c05e8aa Mon Sep 17 00:00:00 2001 From: wang_yue111 <648774160@qq.com> Date: Thu, 22 Apr 2021 09:30:33 +0800 Subject: [PATCH 03/13] fix CVE-2019-18281 --- CVE-2019-18281.patch | 101 +++++++++++++++++++++++++++++++++++++++++++ qt5-qtbase.spec | 6 ++- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 CVE-2019-18281.patch diff --git a/CVE-2019-18281.patch b/CVE-2019-18281.patch new file mode 100644 index 0000000..c4ae797 --- /dev/null +++ b/CVE-2019-18281.patch @@ -0,0 +1,101 @@ +From af267657ea11e292012ac02634e8bd2dcf8328c7 Mon Sep 17 00:00:00 2001 +From: wang_yue111 <648774160@qq.com> +Date: Wed, 21 Apr 2021 11:35:47 +0800 +Subject: [PATCH] Fix crash when text contains too many directional chars + +In case a text to be layouted contains more than 128 directional characters +it causes the application to crash + +The function initScriptAnalysisAndIsolatePairs() collects information of +RTL/LTR chaaracters into vector "isolatePairs". The size of the vector is +capped to 128. Later the function generateDirectionalRuns() iterates +the text again and tries to access items from the previously capped vector +above the upper bound. + +Task-number: QTBUG-77819 +Change-Id: Ibb7bf12c12b1db22f43ff46236518da3fdeed26a +Reviewed-by: Simon Hausmann +(cherry picked from commit 1232205e32464d90e871f39eb1e14fcf9b78a163) +Reviewed-by: Jukka Jokiniva +Reviewed-by: Volker Hilsheimer +--- + src/gui/text/qtextengine.cpp | 15 +++++++-------- + .../gui/text/qtextlayout/tst_qtextlayout.cpp | 17 +++++++++++++++++ + 2 files changed, 24 insertions(+), 8 deletions(-) + +diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp +index 5e38311f..0c405cbf 100644 +--- a/src/gui/text/qtextengine.cpp ++++ b/src/gui/text/qtextengine.cpp +@@ -393,6 +393,7 @@ struct QBidiAlgorithm { + analysis[i].bidiDirection = (level & 1) ? QChar::DirR : QChar::DirL; + runHasContent = true; + lastRunWithContent = -1; ++ ++isolatePairPosition; + } + int runBeforeIsolate = runs.size(); + ushort newLevel = isRtl ? ((stack.top().level + 1) | 1) : ((stack.top().level + 2) & ~1); +@@ -434,20 +435,18 @@ struct QBidiAlgorithm { + doEmbed(true, true, false); + break; + case QChar::DirLRI: +- ++isolatePairPosition; +- Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i); + doEmbed(false, false, true); + break; + case QChar::DirRLI: +- ++isolatePairPosition; +- Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i); + doEmbed(true, false, true); + break; + case QChar::DirFSI: { +- ++isolatePairPosition; +- const auto &pair = isolatePairs.at(isolatePairPosition); +- Q_ASSERT(pair.start == i); +- bool isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft(); ++ bool isRtl = false; ++ if (isolatePairPosition < isolatePairs.size()) { ++ const auto &pair = isolatePairs.at(isolatePairPosition); ++ Q_ASSERT(pair.start == i); ++ isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft(); ++ } + doEmbed(isRtl, false, true); + break; + } +diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp +index 4e3d1da8..ec8b6116 100644 +--- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp ++++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp +@@ -137,6 +137,7 @@ private slots: + void nbspWithFormat(); + void noModificationOfInputString(); + void superscriptCrash_qtbug53911(); ++ void tooManyDirectionalCharctersCrash_qtbug77819(); + + private: + QFont testFont; +@@ -2291,5 +2292,21 @@ void tst_QTextLayout::nbspWithFormat() + QCOMPARE(layout.lineAt(1).textLength(), s2.length() + 1 + s3.length()); + } + ++void tst_QTextLayout::tooManyDirectionalCharctersCrash_qtbug77819() ++{ ++ QString data; ++ data += QString::fromUtf8("\xe2\x81\xa8"); // U+2068 FSI character ++ data += QString::fromUtf8("\xe2\x81\xa7"); // U+2067 RLI character ++ ++ // duplicating the text ++ for (int i = 0; i < 10; i++) ++ data += data; ++ ++ // Nothing to test. It must not crash in beginLayout(). ++ QTextLayout tl(data); ++ tl.beginLayout(); ++ tl.endLayout(); ++} ++ + QTEST_MAIN(tst_QTextLayout) + #include "tst_qtextlayout.moc" +-- +2.23.0 + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index c9d7a76..e8090a8 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 11 +Release: 12 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -36,6 +36,7 @@ Patch0011: qt5-qtbase-glibc.patch Patch6000: CVE-2018-15518.patch Patch6001: CVE-2015-9541.patch +Patch6002: CVE-2019-18281.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -402,6 +403,9 @@ fi %changelog +* Thu Apr 22 2021 wangyue - 5.11.1-12 +- fix CVE-2019-18281 + * Mon Sep 21 2020 wutao - 5.11.1-11 - fix CVE-2015-9541 -- Gitee From cbc3e7276e128d52edd35196f73e635471678669 Mon Sep 17 00:00:00 2001 From: wk333 <13474090681@163.com> Date: Tue, 26 Jul 2022 17:25:43 +0800 Subject: [PATCH 04/13] Fix CVE-2021-38593 and CVE-2022-25255 (cherry picked from commit fb537edb24b6d18187c0d177fd0d6c22423a70b3) --- CVE-2021-38593.patch | 84 +++++++++++++++++ CVE-2022-25255.patch | 219 +++++++++++++++++++++++++++++++++++++++++++ qt5-qtbase.spec | 9 +- 3 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 CVE-2021-38593.patch create mode 100644 CVE-2022-25255.patch diff --git a/CVE-2021-38593.patch b/CVE-2021-38593.patch new file mode 100644 index 0000000..05fbb4b --- /dev/null +++ b/CVE-2021-38593.patch @@ -0,0 +1,84 @@ +Description: 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 individually visible + anyway, just replace with a semi-transparent solid line for such + cases. +Origin: upstream, commits: + https://code.qt.io/cgit/qt/qtbase.git/commit/?id=7f345f2a1c8d9f60 + https://code.qt.io/cgit/qt/qtbase.git/commit/?id=9378ba2ae857df7e + https://code.qt.io/cgit/qt/qtbase.git/commit/?id=81998f50d039a631 + https://code.qt.io/cgit/qt/qtbase.git/commit/?id=cca8ed0547405b1c +Last-Update: 2021-12-12 + +--- a/src/gui/painting/qpaintengineex.cpp ++++ b/src/gui/painting/qpaintengineex.cpp +@@ -385,10 +385,10 @@ QPainterState *QPaintEngineEx::createSta + + 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; ++ qDebug() << "QPaintEngineEx::stroke()" << inPen; + #endif + + Q_D(QPaintEngineEx); +@@ -403,6 +403,38 @@ void QPaintEngineEx::stroke(const QVecto + 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 ++ 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 pattern = pen.dashPattern(); ++ const int patternSize = qMin(pattern.size(), 32); ++ for (int i = 0; i < patternSize; i++) ++ patternLength += qMax(pattern.at(i), qreal(0)); ++ patternLength *= pw; ++ 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 QVecto + 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); + + const QPainterPath::ElementType *types = path.elements(); + const qreal *points = path.points(); diff --git a/CVE-2022-25255.patch b/CVE-2022-25255.patch new file mode 100644 index 0000000..83fc328 --- /dev/null +++ b/CVE-2022-25255.patch @@ -0,0 +1,219 @@ +From ab3e0383b9de49c61bc49f5fbef80d1409fcafde Mon Sep 17 00:00:00 2001 +From: Thiago Macieira +Date: Mon, 31 Jan 2022 11:00:19 -0800 +Subject: [PATCH] QProcess/Unix: ensure we don't accidentally execute something + from CWD +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Unless "." (or the empty string) is in $PATH, we're not supposed to find +executables in the current directory. This is how the Unix shells behave +and we match their behavior. It's also the behavior Qt had prior to 5.9 +(commit 28666d167aa8e602c0bea25ebc4d51b55005db13). On Windows, searching +the current directory is the norm, so we keep that behavior. + +This commit does not add an explicit check for an empty return from +QStandardPaths::findExecutable(). Instead, we allow that empty string to +go all the way to execve(2), which will fail with ENOENT. We could catch +it early, before fork(2), but why add code for the error case? + +See https://kde.org/info/security/advisory-20220131-1.txt + +[ChangeLog][Important Behavior Changes] When passed a simple program +name with no slashes, QProcess on Unix systems will now only search the +current directory if "." is one of the entries in the PATH environment +variable. This bug fix restores the behavior QProcess had before Qt 5.9. +If launching an executable in the directory set by setWorkingDirectory() +or inherited from the parent is intended, pass a program name starting +with "./". For more information and best practices about finding an +executable, see QProcess' documentation. + +Pick-to: 5.15 6.2 6.3 +Change-Id: I54f205f6b7314351b078fffd16cf7013c97ee9fb +Reviewed-by: Qt CI Bot +Reviewed-by: Mårten Nordheim +Reviewed-by: Thiago Macieira +(cherry picked from commit 29fceed2ffb41954a63001414bd042611f2d4980) + +Note: This currently breaks various autotests, as they rely on the test +helpers (same directory as the test) to be in $PATH. In Qt 6, the CMake +test code sets this explicitly, which is not the case in Qt 5 (yet). +--- + src/corelib/io/qprocess_unix.cpp | 24 ++--- + .../auto/corelib/io/qprocess/tst_qprocess.cpp | 93 ++++++++++++++++++- + .../kernel/qapplication/tst_qapplication.cpp | 4 +- + 3 files changed, 107 insertions(+), 14 deletions(-) + +diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp +index 50390e57f5..5bd3b7f297 100644 +--- a/src/corelib/io/qprocess_unix.cpp ++++ b/src/corelib/io/qprocess_unix.cpp +@@ -1,7 +1,7 @@ + /**************************************************************************** + ** + ** Copyright (C) 2016 The Qt Company Ltd. +-** Copyright (C) 2016 Intel Corporation. ++** Copyright (C) 2022 Intel Corporation. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the QtCore module of the Qt Toolkit. +@@ -422,14 +422,15 @@ void QProcessPrivate::startProcess() + // Add the program name to the argument list. + argv[0] = nullptr; + if (!program.contains(QLatin1Char('/'))) { ++ // findExecutable() returns its argument if it's an absolute path, ++ // otherwise it searches $PATH; returns empty if not found (we handle ++ // that case much later) + const QString &exeFilePath = QStandardPaths::findExecutable(program); +- if (!exeFilePath.isEmpty()) { +- const QByteArray &tmp = QFile::encodeName(exeFilePath); +- argv[0] = ::strdup(tmp.constData()); +- } +- } +- if (!argv[0]) ++ const QByteArray &tmp = QFile::encodeName(exeFilePath); ++ argv[0] = ::strdup(tmp.constData()); ++ } else { + argv[0] = ::strdup(encodedProgramName.constData()); ++ } + + // Add every argument to the list + for (int i = 0; i < arguments.count(); ++i) +@@ -985,11 +986,12 @@ bool QProcessPrivate::startDetached(qint64 *pid) + + QByteArray tmp; + if (!program.contains(QLatin1Char('/'))) { ++ // findExecutable() returns its argument if it's an absolute path, ++ // otherwise it searches $PATH; returns empty if not found (we handle ++ // that case much later) + const QString &exeFilePath = QStandardPaths::findExecutable(program); +- if (!exeFilePath.isEmpty()) +- tmp = QFile::encodeName(exeFilePath); +- } +- if (tmp.isEmpty()) ++ tmp = QFile::encodeName(exeFilePath); ++ } else + tmp = QFile::encodeName(program); + argv[0] = tmp.data(); + +diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +index bc9df3f1f3..33051d3803 100644 +--- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp ++++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +@@ -1,7 +1,7 @@ + /**************************************************************************** + ** + ** Copyright (C) 2016 The Qt Company Ltd. +-** Copyright (C) 2016 Intel Corporation. ++** Copyright (C) 2022 Intel Corporation. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the test suite of the Qt Toolkit. +@@ -149,6 +149,8 @@ private slots: + void startStopStartStopBuffers(); + void processEventsInAReadyReadSlot_data(); + void processEventsInAReadyReadSlot(); ++ void startFromCurrentWorkingDir_data(); ++ void startFromCurrentWorkingDir(); + + // keep these at the end, since they use lots of processes and sometimes + // caused obscure failures to occur in tests that followed them (esp. on the Mac) +@@ -2732,5 +2734,94 @@ void tst_QProcess::finishProcessBeforeReadingDone_deprecated() + QVERIFY(process.waitForFinished()); + } + ++enum class ChdirMode { ++ None = 0, ++ InParent, ++ InChild ++}; ++Q_DECLARE_METATYPE(ChdirMode) ++ ++void tst_QProcess::startFromCurrentWorkingDir_data() ++{ ++ qRegisterMetaType(); ++ QTest::addColumn("programPrefix"); ++ QTest::addColumn("chdirMode"); ++ QTest::addColumn("success"); ++ ++ constexpr bool IsWindows = true ++#ifdef Q_OS_UNIX ++ && false ++#endif ++ ; ++ ++ // baseline: trying to execute the directory, this can't possibly succeed! ++ QTest::newRow("plain-same-cwd") << QString() << ChdirMode::None << false; ++ ++ // cross-platform behavior: neither OS searches the setWorkingDirectory() ++ // dir without "./" ++ QTest::newRow("plain-child-chdir") << QString() << ChdirMode::InChild << false; ++ ++ // cross-platform behavior: both OSes search the parent's CWD with "./" ++ QTest::newRow("prefixed-parent-chdir") << "./" << ChdirMode::InParent << true; ++ ++ // opposite behaviors: Windows searches the parent's CWD and Unix searches ++ // the child's with "./" ++ QTest::newRow("prefixed-child-chdir") << "./" << ChdirMode::InChild << !IsWindows; ++ ++ // Windows searches the parent's CWD without "./" ++ QTest::newRow("plain-parent-chdir") << QString() << ChdirMode::InParent << IsWindows; ++} ++ ++void tst_QProcess::startFromCurrentWorkingDir() ++{ ++ QFETCH(QString, programPrefix); ++ QFETCH(ChdirMode, chdirMode); ++ QFETCH(bool, success); ++ ++ QProcess process; ++ qRegisterMetaType(); ++ QSignalSpy errorSpy(&process, &QProcess::errorOccurred); ++ QVERIFY(errorSpy.isValid()); ++ ++ // both the dir name and the executable name ++ const QString target = QStringLiteral("testProcessNormal"); ++ process.setProgram(programPrefix + target); ++ ++#ifdef Q_OS_UNIX ++ // Reset PATH, to be sure it doesn't contain . or the empty path. ++ // We can't do this on Windows because DLLs are searched in PATH ++ // and Windows always searches "." anyway. ++ auto restoreEnv = qScopeGuard([old = qgetenv("PATH")] { ++ qputenv("PATH", old); ++ }); ++ qputenv("PATH", "/"); ++#endif ++ ++ switch (chdirMode) { ++ case ChdirMode::InParent: { ++ auto restoreCwd = qScopeGuard([old = QDir::currentPath()] { ++ QDir::setCurrent(old); ++ }); ++ QVERIFY(QDir::setCurrent(target)); ++ process.start(); ++ break; ++ } ++ case ChdirMode::InChild: ++ process.setWorkingDirectory(target); ++ Q_FALLTHROUGH(); ++ case ChdirMode::None: ++ process.start(); ++ break; ++ } ++ ++ QCOMPARE(process.waitForStarted(), success); ++ QCOMPARE(errorSpy.count(), int(!success)); ++ if (success) { ++ QVERIFY(process.waitForFinished()); ++ } else { ++ QCOMPARE(process.error(), QProcess::FailedToStart); ++ } ++} ++ + QTEST_MAIN(tst_QProcess) + #include "tst_qprocess.moc" +-- +2.34.0 + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index e8090a8..266d928 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 12 +Release: 13 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -37,6 +37,10 @@ Patch0011: qt5-qtbase-glibc.patch Patch6000: CVE-2018-15518.patch Patch6001: CVE-2015-9541.patch Patch6002: CVE-2019-18281.patch +# https://launchpad.net/ubuntu/+source/qtbase-opensource-src/5.12.8+dfsg-0ubuntu2.1 +Patch6003: CVE-2021-38593.patch +# https://build.opensuse.org/package/view_file/SUSE:SLE-15-SP3:Update/libqt5-qtbase/0001-QProcess-Unix-ensure-we-don-t-accidentally-execute-s.patch?expand=1 +Patch6004: CVE-2022-25255.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -403,6 +407,9 @@ fi %changelog +* Tue Jul 26 2022 wangkai - 5.11.1-13 +- Fix CVE-2021-38593 and CVE-2022-25255 + * Thu Apr 22 2021 wangyue - 5.11.1-12 - fix CVE-2019-18281 -- Gitee From 9179a4a9f034e07539e7b445c087beb30c7ddcfa Mon Sep 17 00:00:00 2001 From: dou33 Date: Mon, 22 May 2023 10:53:05 +0800 Subject: [PATCH 05/13] fix CVE-2023-24607 (cherry picked from commit 63abc0d432f0bff0c90d5c9f86eefae6dbfc3f72) --- CVE-2023-24607.patch | 336 +++++++++++++++++++++++++++++++++++++++++++ qt5-qtbase.spec | 8 +- 2 files changed, 342 insertions(+), 2 deletions(-) create mode 100644 CVE-2023-24607.patch diff --git a/CVE-2023-24607.patch b/CVE-2023-24607.patch new file mode 100644 index 0000000..6d2069f --- /dev/null +++ b/CVE-2023-24607.patch @@ -0,0 +1,336 @@ + src/plugins/sqldrivers/odbc/qsql_odbc.cpp | 210 ++++++++++++---------- + 1 file changed, 120 insertions(+), 90 deletions(-) + +diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp +index 547eb204..8d7ce3e3 100644 +--- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp ++++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp +@@ -91,23 +91,39 @@ inline static QString fromSQLTCHAR(const QVarLengthArray& input, int s + return result; + } + ++template ++void toSQLTCHARImpl(QVarLengthArray &result, const QString &input); // primary template undefined ++ ++template ++void do_append(QVarLengthArray &result, const Container &c) ++{ ++ result.append(reinterpret_cast(c.data()), c.size()); ++} ++ ++template <> ++void toSQLTCHARImpl<1>(QVarLengthArray &result, const QString &input) ++{ ++ const auto u8 = input.toUtf8(); ++ do_append(result, u8); ++} ++ ++template <> ++void toSQLTCHARImpl<2>(QVarLengthArray &result, const QString &input) ++{ ++ do_append(result, input); ++} ++ ++template <> ++void toSQLTCHARImpl<4>(QVarLengthArray &result, const QString &input) ++{ ++ const auto u32 = input.toUcs4(); ++ do_append(result, u32); ++} ++ + inline static QVarLengthArray toSQLTCHAR(const QString &input) + { + QVarLengthArray result; +- result.resize(input.size()); +- switch(sizeof(SQLTCHAR)) { +- case 1: +- memcpy(result.data(), input.toUtf8().data(), input.size()); +- break; +- case 2: +- memcpy(result.data(), input.unicode(), input.size() * 2); +- break; +- case 4: +- memcpy(result.data(), input.toUcs4().data(), input.size() * 4); +- break; +- default: +- qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR))); +- } ++ toSQLTCHARImpl(result, input); + result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't. + return result; + } +@@ -768,6 +784,14 @@ QChar QODBCDriverPrivate::quoteChar() + return quote; + } + ++static SQLRETURN qt_string_SQLSetConnectAttr(SQLHDBC handle, SQLINTEGER attr, const QString &val) ++{ ++ auto encoded = toSQLTCHAR(val); ++ return SQLSetConnectAttr(handle, attr, ++ encoded.data(), ++ SQLINTEGER(encoded.size() * sizeof(SQLTCHAR))); // size in bytes ++} ++ + + bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts) + { +@@ -803,10 +826,7 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts) + v = val.toUInt(); + r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0); + } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) { +- val.utf16(); // 0 terminate +- r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, +- toSQLTCHAR(val).data(), +- val.length()*sizeof(SQLTCHAR)); ++ r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, val); + } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) { + if (val.toUpper() == QLatin1String("SQL_TRUE")) { + v = SQL_TRUE; +@@ -821,10 +841,7 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts) + v = val.toUInt(); + r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0); + } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) { +- val.utf16(); // 0 terminate +- r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, +- toSQLTCHAR(val).data(), +- val.length()*sizeof(SQLTCHAR)); ++ r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, val); + } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) { + if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) { + v = SQL_OPT_TRACE_OFF; +@@ -1027,9 +1044,13 @@ bool QODBCResult::reset (const QString& query) + return false; + } + +- r = SQLExecDirect(d->hStmt, +- toSQLTCHAR(query).data(), +- (SQLINTEGER) query.length()); ++ { ++ auto encoded = toSQLTCHAR(query); ++ r = SQLExecDirect(d->hStmt, ++ encoded.data(), ++ SQLINTEGER(encoded.size())); ++ } ++ + if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) { + setLastError(qMakeError(QCoreApplication::translate("QODBCResult", + "Unable to execute statement"), QSqlError::StatementError, d)); +@@ -1375,9 +1396,12 @@ bool QODBCResult::prepare(const QString& query) + return false; + } + +- r = SQLPrepare(d->hStmt, +- toSQLTCHAR(query).data(), +- (SQLINTEGER) query.length()); ++ { ++ auto encoded = toSQLTCHAR(query); ++ r = SQLPrepare(d->hStmt, ++ encoded.data(), ++ SQLINTEGER(encoded.size())); ++ } + + if (r != SQL_SUCCESS) { + setLastError(qMakeError(QCoreApplication::translate("QODBCResult", +@@ -1405,7 +1429,7 @@ bool QODBCResult::exec() + SQLCloseCursor(d->hStmt); + + QVector& values = boundValues(); +- QVector tmpStorage(values.count(), QByteArray()); // holds temporary buffers ++ QVector tmpStorage(values.count(), QByteArray()); // targets for SQLBindParameter() + QVarLengthArray indicators(values.count()); + memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN)); + +@@ -1582,35 +1606,36 @@ bool QODBCResult::exec() + case QVariant::String: + if (d->unicode) { + QByteArray &ba = tmpStorage[i]; +- QString str = val.toString(); ++ { ++ const auto encoded = toSQLTCHAR(val.toString()); ++ ba = QByteArray(reinterpret_cast(encoded.data()), ++ encoded.size() * sizeof(SQLTCHAR)); ++ } ++ + if (*ind != SQL_NULL_DATA) +- *ind = str.length() * sizeof(SQLTCHAR); +- int strSize = str.length() * sizeof(SQLTCHAR); ++ *ind = ba.size(); + + if (bindValueType(i) & QSql::Out) { +- const QVarLengthArray a(toSQLTCHAR(str)); +- ba = QByteArray((const char *)a.constData(), a.size() * sizeof(SQLTCHAR)); + r = SQLBindParameter(d->hStmt, + i + 1, + qParamType[bindValueType(i) & QSql::InOut], + SQL_C_TCHAR, +- strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR, ++ ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR, + 0, // god knows... don't change this! + 0, +- ba.data(), ++ const_cast(ba.constData()), // don't detach + ba.size(), + ind); + break; + } +- ba = QByteArray ((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR)); + r = SQLBindParameter(d->hStmt, + i + 1, + qParamType[bindValueType(i) & QSql::InOut], + SQL_C_TCHAR, +- strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR, +- strSize, ++ ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR, ++ ba.size(), + 0, +- const_cast(ba.constData()), ++ const_cast(ba.constData()), // don't detach + ba.size(), + ind); + break; +@@ -1718,10 +1743,11 @@ bool QODBCResult::exec() + case QVariant::String: + if (d->unicode) { + if (bindValueType(i) & QSql::Out) { +- const QByteArray &first = tmpStorage.at(i); +- QVarLengthArray array; +- array.append((const SQLTCHAR *)first.constData(), first.size()); +- values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR)); ++ const QByteArray &bytes = tmpStorage.at(i); ++ const auto strSize = bytes.size() / int(sizeof(SQLTCHAR)); ++ QVarLengthArray string(strSize); ++ memcpy(string.data(), bytes.data(), strSize * sizeof(SQLTCHAR)); ++ values[i] = fromSQLTCHAR(string); + } + break; + } +@@ -1968,14 +1993,16 @@ bool QODBCDriver::open(const QString & db, + SQLSMALLINT cb; + QVarLengthArray connOut(1024); + memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR)); +- r = SQLDriverConnect(d->hDbc, +- NULL, +- toSQLTCHAR(connQStr).data(), +- (SQLSMALLINT)connQStr.length(), +- connOut.data(), +- 1024, +- &cb, +- /*SQL_DRIVER_NOPROMPT*/0); ++ { ++ auto encoded = toSQLTCHAR(connQStr); ++ r = SQLDriverConnect(d->hDbc, ++ nullptr, ++ encoded.data(), SQLSMALLINT(encoded.size()), ++ connOut.data(), ++ 1024, ++ &cb, ++ /*SQL_DRIVER_NOPROMPT*/0); ++ } + + if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) { + setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d)); +@@ -2354,17 +2381,15 @@ QStringList QODBCDriver::tables(QSql::TableType type) const + if (tableType.isEmpty()) + return tl; + +- QString joinedTableTypeString = tableType.join(QLatin1Char(',')); ++ { ++ auto joinedTableTypeString = toSQLTCHAR(tableType.join(u',')); + +- r = SQLTables(hStmt, +- NULL, +- 0, +- NULL, +- 0, +- NULL, +- 0, +- toSQLTCHAR(joinedTableTypeString).data(), +- joinedTableTypeString.length() /* characters, not bytes */); ++ r = SQLTables(hStmt, ++ nullptr, 0, ++ nullptr, 0, ++ nullptr, 0, ++ joinedTableTypeString.data(), joinedTableTypeString.size()); ++ } + + if (r != SQL_SUCCESS) + qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d); +@@ -2438,28 +2463,30 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, + SQL_IS_UINTEGER); +- r = SQLPrimaryKeys(hStmt, +- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(), +- catalog.length(), +- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(), +- schema.length(), +- toSQLTCHAR(table).data(), +- table.length() /* in characters, not in bytes */); ++ { ++ auto c = toSQLTCHAR(catalog); ++ auto s = toSQLTCHAR(schema); ++ auto t = toSQLTCHAR(table); ++ r = SQLPrimaryKeys(hStmt, ++ catalog.isEmpty() ? nullptr : c.data(), c.size(), ++ schema.isEmpty() ? nullptr : s.data(), s.size(), ++ t.data(), t.size()); ++ } + + // if the SQLPrimaryKeys() call does not succeed (e.g the driver + // does not support it) - try an alternative method to get hold of + // the primary index (e.g MS Access and FoxPro) + if (r != SQL_SUCCESS) { +- r = SQLSpecialColumns(hStmt, +- SQL_BEST_ROWID, +- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(), +- catalog.length(), +- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(), +- schema.length(), +- toSQLTCHAR(table).data(), +- table.length(), +- SQL_SCOPE_CURROW, +- SQL_NULLABLE); ++ auto c = toSQLTCHAR(catalog); ++ auto s = toSQLTCHAR(schema); ++ auto t = toSQLTCHAR(table); ++ r = SQLSpecialColumns(hStmt, ++ SQL_BEST_ROWID, ++ catalog.isEmpty() ? nullptr : c.data(), c.size(), ++ schema.isEmpty() ? nullptr : s.data(), s.size(), ++ t.data(), t.size(), ++ SQL_SCOPE_CURROW, ++ SQL_NULLABLE); + + if (r != SQL_SUCCESS) { + qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d); +@@ -2540,15 +2567,18 @@ QSqlRecord QODBCDriver::record(const QString& tablename) const + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, + SQL_IS_UINTEGER); +- r = SQLColumns(hStmt, +- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(), +- catalog.length(), +- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(), +- schema.length(), +- toSQLTCHAR(table).data(), +- table.length(), +- NULL, +- 0); ++ { ++ auto c = toSQLTCHAR(catalog); ++ auto s = toSQLTCHAR(schema); ++ auto t = toSQLTCHAR(table); ++ r = SQLColumns(hStmt, ++ catalog.isEmpty() ? nullptr : c.data(), c.size(), ++ schema.isEmpty() ? nullptr : s.data(), s.size(), ++ t.data(), t.size(), ++ nullptr, ++ 0); ++ } ++ + if (r != SQL_SUCCESS) + qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d); + +-- +2.39.1 + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 266d928..4235c74 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 13 +Release: 14 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -41,6 +41,8 @@ Patch6002: CVE-2019-18281.patch Patch6003: CVE-2021-38593.patch # https://build.opensuse.org/package/view_file/SUSE:SLE-15-SP3:Update/libqt5-qtbase/0001-QProcess-Unix-ensure-we-don-t-accidentally-execute-s.patch?expand=1 Patch6004: CVE-2022-25255.patch +# https://download.qt.io/official_releases/qt/5.15/CVE-2023-24607-qtbase-5.15.diff +Patch6005: CVE-2023-24607.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -407,6 +409,9 @@ fi %changelog +* Mon May 22 2023 douyan - 5.11.1-14 +- Fix CVE-2023-24607 + * Tue Jul 26 2022 wangkai - 5.11.1-13 - Fix CVE-2021-38593 and CVE-2022-25255 @@ -425,6 +430,5 @@ fi - SUG:restart - DESC: fix CVE-2018-15518 - * Thu Nov 07 2019 yanzhihua - 5.11.1-8 - Package init -- Gitee From 9208406e6d1a0cd2c159000d70947abed19a804b Mon Sep 17 00:00:00 2001 From: starlet-dx <15929766099@163.com> Date: Wed, 28 Jun 2023 14:16:23 +0800 Subject: [PATCH 06/13] Fix CVE-2023-32762 and CVE-2023-32763 (cherry picked from commit 45b414dafb26cb3f47ad8b053cc463b31ba0bb15) --- CVE-2023-32762-pre.patch | 836 +++++++++++++++++++++++++++++++++++++++ CVE-2023-32762.patch | 50 +++ CVE-2023-32763.patch | 65 +++ qt5-qtbase.spec | 8 +- 4 files changed, 958 insertions(+), 1 deletion(-) create mode 100644 CVE-2023-32762-pre.patch create mode 100644 CVE-2023-32762.patch create mode 100644 CVE-2023-32763.patch diff --git a/CVE-2023-32762-pre.patch b/CVE-2023-32762-pre.patch new file mode 100644 index 0000000..7ab1cd9 --- /dev/null +++ b/CVE-2023-32762-pre.patch @@ -0,0 +1,836 @@ +From cad7100fda1b27ba56c4d9efc6bceba62859dfbc Mon Sep 17 00:00:00 2001 +From: Thiago Macieira +Date: Sun, 13 May 2018 21:53:07 -0700 +Subject: [PATCH] QByteArray: add compare() with case sensitivity options +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Need to do the same for startsWith() and endsWith(). indexOf() is a lot +harder. + +[ChangeLog][QtCore][QByteArray] Added compare(), which takes +Qt::CaseSensitivity as one of the parameters. This function is more +efficient than using toLower() or toUpper() and then comparing. + +Change-Id: Ib48364abee9f464c96c6fffd152e69bde4194df7 +Reviewed-by: Mårten Nordheim +Reviewed-by: Timur Pocheptsov +--- + src/corelib/io/qsettings.cpp | 6 +- + src/corelib/tools/qbytearray.cpp | 123 +++++++++++++++++- + src/corelib/tools/qbytearray.h | 14 ++ + src/corelib/tools/qstring.cpp | 8 +- + src/gui/kernel/qhighdpiscaling.cpp | 3 +- + src/network/access/http2/http2protocol.cpp | 3 +- + src/network/access/qhsts.cpp | 5 +- + src/network/access/qhttp2protocolhandler.cpp | 15 ++- + src/network/access/qhttpnetworkconnection.cpp | 2 +- + src/network/access/qhttpnetworkheader.cpp | 6 +- + src/network/access/qhttpnetworkreply.cpp | 5 +- + src/network/access/qnetworkdiskcache.cpp | 6 +- + src/network/access/qnetworkreplyhttpimpl.cpp | 4 +- + src/network/access/qnetworkrequest.cpp | 20 +-- + src/network/kernel/qauthenticator.cpp | 8 +- + src/network/socket/qhttpsocketengine.cpp | 5 +- + .../platforms/eglfs/api/qeglfsintegration.cpp | 3 +- + .../tools/qbytearray/tst_qbytearray.cpp | 32 ++++- + 18 files changed, 212 insertions(+), 56 deletions(-) + +diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp +index 4b1b9888d81..1134c6bb85e 100644 +--- a/src/corelib/io/qsettings.cpp ++++ b/src/corelib/io/qsettings.cpp +@@ -1694,10 +1694,10 @@ bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data, + + iniSection = iniSection.trimmed(); + +- if (qstricmp(iniSection.constData(), "general") == 0) { ++ if (iniSection.compare("general", Qt::CaseInsensitive) == 0) { + currentSection.clear(); + } else { +- if (qstricmp(iniSection.constData(), "%general") == 0) { ++ if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) { + currentSection = QLatin1String(iniSection.constData() + 1); + } else { + currentSection.clear(); +@@ -1857,7 +1857,7 @@ bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSetti + + if (realSection.isEmpty()) { + realSection = "[General]"; +- } else if (qstricmp(realSection.constData(), "general") == 0) { ++ } else if (realSection.compare("general", Qt::CaseInsensitive) == 0) { + realSection = "[%General]"; + } else { + realSection.prepend('['); +diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp +index 3468580bf14..4d2003334c0 100644 +--- a/src/corelib/tools/qbytearray.cpp ++++ b/src/corelib/tools/qbytearray.cpp +@@ -356,7 +356,8 @@ char *qstrncpy(char *dst, const char *src, uint len) + Special case 2: Returns an arbitrary non-zero value if \a str1 is + nullptr or \a str2 is nullptr (but not both). + +- \sa qstrncmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons} ++ \sa qstrncmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons}, ++ QByteArray::compare() + */ + int qstrcmp(const char *str1, const char *str2) + { +@@ -381,7 +382,8 @@ int qstrcmp(const char *str1, const char *str2) + Special case 2: Returns a random non-zero value if \a str1 is nullptr + or \a str2 is nullptr (but not both). + +- \sa qstrcmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons} ++ \sa qstrcmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons}, ++ QByteArray::compare() + */ + + /*! \relates QByteArray +@@ -400,7 +402,8 @@ int qstrcmp(const char *str1, const char *str2) + Special case 2: Returns a random non-zero value if \a str1 is nullptr + or \a str2 is nullptr (but not both). + +- \sa qstrcmp(), qstrncmp(), qstrnicmp(), {8-bit Character Comparisons} ++ \sa qstrcmp(), qstrncmp(), qstrnicmp(), {8-bit Character Comparisons}, ++ QByteArray::compare() + */ + + int qstricmp(const char *str1, const char *str2) +@@ -434,7 +437,8 @@ int qstricmp(const char *str1, const char *str2) + Special case 2: Returns a random non-zero value if \a str1 is nullptr + or \a str2 is nullptr (but not both). + +- \sa qstrcmp(), qstrncmp(), qstricmp(), {8-bit Character Comparisons} ++ \sa qstrcmp(), qstrncmp(), qstricmp(), {8-bit Character Comparisons}, ++ QByteArray::compare() + */ + + int qstrnicmp(const char *str1, const char *str2, uint len) +@@ -456,6 +460,55 @@ int qstrnicmp(const char *str1, const char *str2, uint len) + + /*! + \internal ++ \since 5.12 ++ ++ A helper for QByteArray::compare. Compares \a len1 bytes from \a str1 to \a ++ len2 bytes from \a str2. If \a len2 is -1, then \a str2 is expected to be ++ null-terminated. ++ */ ++int qstrnicmp(const char *str1, qsizetype len1, const char *str2, qsizetype len2) ++{ ++ Q_ASSERT(str1); ++ Q_ASSERT(len1 >= 0); ++ Q_ASSERT(len2 >= -1); ++ const uchar *s1 = reinterpret_cast(str1); ++ const uchar *s2 = reinterpret_cast(str2); ++ if (!s2) ++ return len1 == 0 ? 0 : 1; ++ ++ int res; ++ uchar c; ++ if (len2 == -1) { ++ // null-terminated str2 ++ qsizetype i; ++ for (i = 0; i < len1; ++i) { ++ c = latin1_lowercased[s2[i]]; ++ if (!c) ++ return 1; ++ ++ res = latin1_lowercased[s1[i]] - c; ++ if (res) ++ return res; ++ } ++ c = latin1_lowercased[s2[i]]; ++ return c ? -1 : 0; ++ } else { ++ // not null-terminated ++ for (qsizetype i = 0; i < qMin(len1, len2); ++i) { ++ c = latin1_lowercased[s2[i]]; ++ res = latin1_lowercased[s1[i]] - c; ++ if (res) ++ return res; ++ } ++ if (len1 == len2) ++ return 0; ++ return len1 < len2 ? -1 : 1; ++ } ++} ++ ++/*! ++ \internal ++ ### Qt6: replace the QByteArray parameter with [pointer,len] pair + */ + int qstrcmp(const QByteArray &str1, const char *str2) + { +@@ -483,6 +536,7 @@ int qstrcmp(const QByteArray &str1, const char *str2) + + /*! + \internal ++ ### Qt6: replace the QByteArray parameter with [pointer,len] pair + */ + int qstrcmp(const QByteArray &str1, const QByteArray &str2) + { +@@ -2863,6 +2917,31 @@ int QByteArray::count(char ch) const + Same as size(). + */ + ++/*! ++ \fn int QByteArray::compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const ++ \since 5.12 ++ ++ Returns an integer less than, equal to, or greater than zero depending on ++ whether this QByteArray sorts before, at the same position, or after the ++ string pointed to by \a c. The comparison is performed according to case ++ sensitivity \a cs. ++ ++ \sa operator== ++*/ ++ ++/*! ++ \fn int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const ++ \overload ++ \since 5.12 ++ ++ Returns an integer less than, equal to, or greater than zero depending on ++ whether this QByteArray sorts before, at the same position, or after the ++ QByteArray \a a. The comparison is performed according to case sensitivity ++ \a cs. ++ ++ \sa operator== ++*/ ++ + /*! + Returns \c true if this byte array starts with byte array \a ba; + otherwise returns \c false. +@@ -3367,6 +3446,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is equal to byte array \a a2; + otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator==(const QByteArray &a1, const char *a2) +@@ -3376,6 +3457,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is equal to string \a a2; + otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator==(const char *a1, const QByteArray &a2) +@@ -3385,6 +3468,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if string \a a1 is equal to byte array \a a2; + otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator!=(const QByteArray &a1, const QByteArray &a2) +@@ -3394,6 +3479,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is not equal to byte array \a a2; + otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator!=(const QByteArray &a1, const char *a2) +@@ -3403,6 +3490,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is not equal to string \a a2; + otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator!=(const char *a1, const QByteArray &a2) +@@ -3412,6 +3501,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if string \a a1 is not equal to byte array \a a2; + otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator<(const QByteArray &a1, const QByteArray &a2) +@@ -3421,6 +3512,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is lexically less than byte array + \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn inline bool operator<(const QByteArray &a1, const char *a2) +@@ -3430,6 +3523,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is lexically less than string + \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator<(const char *a1, const QByteArray &a2) +@@ -3439,6 +3534,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if string \a a1 is lexically less than byte array + \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator<=(const QByteArray &a1, const QByteArray &a2) +@@ -3448,6 +3545,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is lexically less than or equal + to byte array \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator<=(const QByteArray &a1, const char *a2) +@@ -3457,6 +3556,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is lexically less than or equal + to string \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator<=(const char *a1, const QByteArray &a2) +@@ -3466,6 +3567,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if string \a a1 is lexically less than or equal + to byte array \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator>(const QByteArray &a1, const QByteArray &a2) +@@ -3475,6 +3578,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is lexically greater than byte + array \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator>(const QByteArray &a1, const char *a2) +@@ -3484,6 +3589,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is lexically greater than string + \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator>(const char *a1, const QByteArray &a2) +@@ -3493,6 +3600,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if string \a a1 is lexically greater than byte array + \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator>=(const QByteArray &a1, const QByteArray &a2) +@@ -3502,6 +3611,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is lexically greater than or + equal to byte array \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator>=(const QByteArray &a1, const char *a2) +@@ -3511,6 +3622,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if byte array \a a1 is lexically greater than or + equal to string \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn bool operator>=(const char *a1, const QByteArray &a2) +@@ -3520,6 +3633,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) + + Returns \c true if string \a a1 is lexically greater than or + equal to byte array \a a2; otherwise returns \c false. ++ ++ \sa QByteArray::compare() + */ + + /*! \fn const QByteArray operator+(const QByteArray &a1, const QByteArray &a2) +diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h +index bed710c5976..8ee3a29ecc8 100644 +--- a/src/corelib/tools/qbytearray.h ++++ b/src/corelib/tools/qbytearray.h +@@ -99,6 +99,7 @@ inline int qstrncmp(const char *str1, const char *str2, uint len) + } + Q_CORE_EXPORT int qstricmp(const char *, const char *); + Q_CORE_EXPORT int qstrnicmp(const char *, const char *, uint len); ++Q_CORE_EXPORT int qstrnicmp(const char *, qsizetype, const char *, qsizetype = -1); + + // implemented in qvsnprintf.cpp + Q_CORE_EXPORT int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap); +@@ -231,6 +232,9 @@ class Q_CORE_EXPORT QByteArray + int count(const char *a) const; + int count(const QByteArray &a) const; + ++ inline int compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; ++ inline int compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; ++ + Q_REQUIRED_RESULT QByteArray left(int len) const; + Q_REQUIRED_RESULT QByteArray right(int len) const; + Q_REQUIRED_RESULT QByteArray mid(int index, int len = -1) const; +@@ -603,6 +607,16 @@ inline bool QByteArray::contains(const QByteArray &a) const + { return indexOf(a) != -1; } + inline bool QByteArray::contains(char c) const + { return indexOf(c) != -1; } ++inline int QByteArray::compare(const char *c, Qt::CaseSensitivity cs) const ++{ ++ return cs == Qt::CaseSensitive ? qstrcmp(*this, c) : ++ qstrnicmp(data(), size(), c, -1); ++} ++inline int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs) const ++{ ++ return cs == Qt::CaseSensitive ? qstrcmp(*this, a) : ++ qstrnicmp(data(), size(), a.data(), a.size()); ++} + inline bool operator==(const QByteArray &a1, const QByteArray &a2) Q_DECL_NOTHROW + { return (a1.size() == a2.size()) && (memcmp(a1.constData(), a2.constData(), a1.size())==0); } + inline bool operator==(const QByteArray &a1, const char *a2) Q_DECL_NOTHROW +diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp +index 712e058c9c5..c2e62a47f75 100644 +--- a/src/corelib/tools/qstring.cpp ++++ b/src/corelib/tools/qstring.cpp +@@ -1076,14 +1076,12 @@ static int qt_compare_strings(QLatin1String lhs, QStringView rhs, Qt::CaseSensit + + static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW + { ++ if (cs == Qt::CaseInsensitive) ++ return qstrnicmp(lhs.data(), lhs.size(), rhs.data(), rhs.size()); + if (lhs.isEmpty()) + return lencmp(0, rhs.size()); + const auto l = std::min(lhs.size(), rhs.size()); +- int r; +- if (cs == Qt::CaseSensitive) +- r = qstrncmp(lhs.data(), rhs.data(), l); +- else +- r = qstrnicmp(lhs.data(), rhs.data(), l); ++ int r = qstrncmp(lhs.data(), rhs.data(), l); + return r ? r : lencmp(lhs.size(), rhs.size()); + } + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index 8689f9f3b18..a455aa639d5 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -244,7 +244,8 @@ static inline bool usePixelDensity() + return false; + return QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling) + || (screenEnvValueOk && screenEnvValue > 0) +- || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && qgetenv(legacyDevicePixelEnvVar).toLower() == "auto"); ++ || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && ++ qgetenv(legacyDevicePixelEnvVar).compare("auto", Qt::CaseInsensitive) == 0); + } + + void QHighDpiScaling::initHighDpiScaling() +diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp +index f51af4be5c5..0be72042c6a 100644 +--- a/src/network/access/http2/http2protocol.cpp ++++ b/src/network/access/http2/http2protocol.cpp +@@ -287,7 +287,8 @@ bool is_protocol_upgraded(const QHttpNetworkReply &reply) + // Do some minimal checks here - we expect 'Upgrade: h2c' to be found. + const auto &header = reply.header(); + for (const QPair &field : header) { +- if (field.first.toLower() == "upgrade" && field.second.toLower() == "h2c") ++ if (field.first.compare("upgrade", Qt::CaseInsensitive) == 0 && ++ field.second.compare("h2c", Qt::CaseInsensitive) == 0) + return true; + } + } +diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp +index 43a8a3663ec..a015feb0444 100644 +--- a/src/network/access/qhsts.cpp ++++ b/src/network/access/qhsts.cpp +@@ -453,8 +453,7 @@ bool QHstsHeaderParser::processDirective(const QByteArray &name, const QByteArra + { + Q_ASSERT(name.size()); + // RFC6797 6.1/3 Directive names are case-insensitive +- const auto lcName = name.toLower(); +- if (lcName == "max-age") { ++ if (name.compare("max-age", Qt::CaseInsensitive) == 0) { + // RFC 6797, 6.1.1 + // The syntax of the max-age directive's REQUIRED value (after + // quoted-string unescaping, if necessary) is defined as: +@@ -477,7 +476,7 @@ bool QHstsHeaderParser::processDirective(const QByteArray &name, const QByteArra + + maxAge = age; + maxAgeFound = true; +- } else if (lcName == "includesubdomains") { ++ } else if (name.compare("includesubdomains", Qt::CaseInsensitive) == 0) { + // RFC 6797, 6.1.2. The includeSubDomains Directive. + // The OPTIONAL "includeSubDomains" directive is a valueless directive. + +diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp +index c207d6e2404..df7f87efd4c 100644 +--- a/src/network/access/qhttp2protocolhandler.cpp ++++ b/src/network/access/qhttp2protocolhandler.cpp +@@ -97,16 +97,18 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH + if (size.second > maxHeaderListSize) + break; + +- QByteArray key(field.first.toLower()); +- if (key == "connection" || key == "host" || key == "keep-alive" +- || key == "proxy-connection" || key == "transfer-encoding") ++ if (field.first.compare("connection", Qt::CaseInsensitive) == 0 || ++ field.first.compare("host", Qt::CaseInsensitive) == 0 || ++ field.first.compare("keep-alive", Qt::CaseInsensitive) == 0 || ++ field.first.compare("proxy-connection", Qt::CaseInsensitive) == 0 || ++ field.first.compare("transfer-encoding", Qt::CaseInsensitive) == 0) + continue; // Those headers are not valid (section 3.2.1) - from QSpdyProtocolHandler + // TODO: verify with specs, which fields are valid to send .... + // toLower - 8.1.2 .... "header field names MUST be converted to lowercase prior + // to their encoding in HTTP/2. + // A request or response containing uppercase header field names + // MUST be treated as malformed (Section 8.1.2.6)". +- header.push_back(HeaderField(key, field.second)); ++ header.push_back(HeaderField(field.first.toLower(), field.second)); + } + + return header; +@@ -1404,8 +1406,9 @@ bool QHttp2ProtocolHandler::tryReserveStream(const Http2::Frame &pushPromiseFram + return false; + } + +- const auto method = pseudoHeaders[":method"].toLower(); +- if (method != "get" && method != "head") ++ const QByteArray method = pseudoHeaders[":method"]; ++ if (method.compare("get", Qt::CaseInsensitive) != 0 && ++ method.compare("head", Qt::CaseInsensitive) != 0) + return false; + + QUrl url; +diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp +index 0e2c257952b..c58fd24a443 100644 +--- a/src/network/access/qhttpnetworkconnection.cpp ++++ b/src/network/access/qhttpnetworkconnection.cpp +@@ -528,7 +528,7 @@ QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socke + QUrl redirectUrl; + const QList > fields = reply->header(); + for (const QNetworkReply::RawHeaderPair &header : fields) { +- if (header.first.toLower() == "location") { ++ if (header.first.compare("location", Qt::CaseInsensitive) == 0) { + redirectUrl = QUrl::fromEncoded(header.second); + break; + } +diff --git a/src/network/access/qhttpnetworkheader.cpp b/src/network/access/qhttpnetworkheader.cpp +index 3326f89d2fa..8ad01174b48 100644 +--- a/src/network/access/qhttpnetworkheader.cpp ++++ b/src/network/access/qhttpnetworkheader.cpp +@@ -64,7 +64,7 @@ qint64 QHttpNetworkHeaderPrivate::contentLength() const + QList >::ConstIterator it = fields.constBegin(), + end = fields.constEnd(); + for ( ; it != end; ++it) +- if (qstricmp("content-length", it->first) == 0) { ++ if (it->first.compare("content-length", Qt::CaseInsensitive) == 0) { + value = it->second; + break; + } +@@ -95,7 +95,7 @@ QList QHttpNetworkHeaderPrivate::headerFieldValues(const QByteArray + QList >::ConstIterator it = fields.constBegin(), + end = fields.constEnd(); + for ( ; it != end; ++it) +- if (qstricmp(name.constData(), it->first) == 0) ++ if (name.compare(it->first, Qt::CaseInsensitive) == 0) + result += it->second; + + return result; +@@ -104,7 +104,7 @@ QList QHttpNetworkHeaderPrivate::headerFieldValues(const QByteArray + void QHttpNetworkHeaderPrivate::setHeaderField(const QByteArray &name, const QByteArray &data) + { + auto firstEqualsName = [&name](const QPair &header) { +- return qstricmp(name.constData(), header.first) == 0; ++ return name.compare(header.first, Qt::CaseInsensitive) == 0; + }; + fields.erase(std::remove_if(fields.begin(), fields.end(), + firstEqualsName), +diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp +index a6573469581..c9c31723045 100644 +--- a/src/network/access/qhttpnetworkreply.cpp ++++ b/src/network/access/qhttpnetworkreply.cpp +@@ -390,7 +390,8 @@ qint64 QHttpNetworkReplyPrivate::bytesAvailable() const + bool QHttpNetworkReplyPrivate::isCompressed() + { + QByteArray encoding = headerField("content-encoding"); +- return qstricmp(encoding.constData(), "gzip") == 0 || qstricmp(encoding.constData(), "deflate") == 0; ++ return encoding.compare("gzip", Qt::CaseInsensitive) == 0 || ++ encoding.compare("deflate", Qt::CaseInsensitive) == 0; + } + + void QHttpNetworkReplyPrivate::removeAutoDecompressHeader() +@@ -401,7 +402,7 @@ void QHttpNetworkReplyPrivate::removeAutoDecompressHeader() + QList >::Iterator it = fields.begin(), + end = fields.end(); + while (it != end) { +- if (qstricmp(name.constData(), it->first.constData()) == 0) { ++ if (name.compare(it->first, Qt::CaseInsensitive) == 0) { + removedContentLength = strtoull(it->second.constData(), nullptr, 0); + fields.erase(it); + break; +diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp +index c9d658225e5..df2e4902a4b 100644 +--- a/src/network/access/qnetworkdiskcache.cpp ++++ b/src/network/access/qnetworkdiskcache.cpp +@@ -189,7 +189,7 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData) + + const auto headers = metaData.rawHeaders(); + for (const auto &header : headers) { +- if (header.first.toLower() == "content-length") { ++ if (header.first.compare("content-length", Qt::CaseInsensitive) == 0) { + const qint64 size = header.second.toLongLong(); + if (size > (maximumCacheSize() * 3)/4) + return 0; +@@ -642,7 +642,7 @@ bool QCacheItem::canCompress() const + bool typeOk = false; + const auto headers = metaData.rawHeaders(); + for (const auto &header : headers) { +- if (header.first.toLower() == "content-length") { ++ if (header.first.compare("content-length", Qt::CaseInsensitive) == 0) { + qint64 size = header.second.toLongLong(); + if (size > MAX_COMPRESSION_SIZE) + return false; +@@ -650,7 +650,7 @@ bool QCacheItem::canCompress() const + sizeOk = true; + } + +- if (header.first.toLower() == "content-type") { ++ if (header.first.compare("content-type", Qt::CaseInsensitive) == 0) { + QByteArray type = header.second; + if (type.startsWith("text/") + || (type.startsWith("application/") +diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp +index 96016453c24..3c6f4aadfa8 100644 +--- a/src/network/access/qnetworkreplyhttpimpl.cpp ++++ b/src/network/access/qnetworkreplyhttpimpl.cpp +@@ -1318,7 +1318,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QListfirst.constData(), "set-cookie") == 0) ++ if (it->first.compare("set-cookie", Qt::CaseInsensitive) == 0) + value += '\n'; + else + value += ", "; +@@ -1584,7 +1584,7 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData + QUrl redirectUrl; + for ( ; it != end; ++it) { + if (httpRequest.isFollowRedirects() && +- !qstricmp(it->first.toLower().constData(), "location")) ++ !it->first.compare("location", Qt::CaseInsensitive)) + redirectUrl = QUrl::fromEncoded(it->second); + setRawHeader(it->first, it->second); + } +diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp +index 70a7f4e8bdc..c2b388bbce6 100644 +--- a/src/network/access/qnetworkrequest.cpp ++++ b/src/network/access/qnetworkrequest.cpp +@@ -918,11 +918,11 @@ static int parseHeaderName(const QByteArray &headerName) + + switch (tolower(headerName.at(0))) { + case 'c': +- if (qstricmp(headerName.constData(), "content-type") == 0) ++ if (headerName.compare("content-type", Qt::CaseInsensitive) == 0) + return QNetworkRequest::ContentTypeHeader; +- else if (qstricmp(headerName.constData(), "content-length") == 0) ++ else if (headerName.compare("content-length", Qt::CaseInsensitive) == 0) + return QNetworkRequest::ContentLengthHeader; +- else if (qstricmp(headerName.constData(), "cookie") == 0) ++ else if (headerName.compare("cookie", Qt::CaseInsensitive) == 0) + return QNetworkRequest::CookieHeader; + else if (qstricmp(headerName.constData(), "content-disposition") == 0) + return QNetworkRequest::ContentDispositionHeader; +@@ -943,21 +943,21 @@ static int parseHeaderName(const QByteArray &headerName) + break; + + case 'l': +- if (qstricmp(headerName.constData(), "location") == 0) ++ if (headerName.compare("location", Qt::CaseInsensitive) == 0) + return QNetworkRequest::LocationHeader; +- else if (qstricmp(headerName.constData(), "last-modified") == 0) ++ else if (headerName.compare("last-modified", Qt::CaseInsensitive) == 0) + return QNetworkRequest::LastModifiedHeader; + break; + + case 's': +- if (qstricmp(headerName.constData(), "set-cookie") == 0) ++ if (headerName.compare("set-cookie", Qt::CaseInsensitive) == 0) + return QNetworkRequest::SetCookieHeader; +- else if (qstricmp(headerName.constData(), "server") == 0) ++ else if (headerName.compare("server", Qt::CaseInsensitive) == 0) + return QNetworkRequest::ServerHeader; + break; + + case 'u': +- if (qstricmp(headerName.constData(), "user-agent") == 0) ++ if (headerName.compare("user-agent", Qt::CaseInsensitive) == 0) + return QNetworkRequest::UserAgentHeader; + break; + } +@@ -1100,7 +1100,7 @@ QNetworkHeadersPrivate::findRawHeader(const QByteArray &key) const + RawHeadersList::ConstIterator it = rawHeaders.constBegin(); + RawHeadersList::ConstIterator end = rawHeaders.constEnd(); + for ( ; it != end; ++it) +- if (qstricmp(it->first.constData(), key.constData()) == 0) ++ if (it->first.compare(key, Qt::CaseInsensitive) == 0) + return it; + + return end; // not found +@@ -1181,7 +1181,7 @@ void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders heade + void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const QByteArray &value) + { + auto firstEqualsKey = [&key](const RawHeaderPair &header) { +- return qstricmp(header.first.constData(), key.constData()) == 0; ++ return header.first.compare(key, Qt::CaseInsensitive) == 0; + }; + rawHeaders.erase(std::remove_if(rawHeaders.begin(), rawHeaders.end(), + firstEqualsKey), +diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp +index a3ccf13e82f..11ea40dbce6 100644 +--- a/src/network/kernel/qauthenticator.cpp ++++ b/src/network/kernel/qauthenticator.cpp +@@ -412,7 +412,7 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList ¤t = values.at(i); +- if (current.first.toLower() != search) ++ if (current.first.compare(search, Qt::CaseInsensitive) != 0) + continue; + QByteArray str = current.second.toLower(); + if (method < Basic && str.startsWith("basic")) { +@@ -443,7 +443,7 @@ void QAuthenticatorPrivate::parseHttpResponse(const QListoptions[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); +- if (options.value("stale").toLower() == "true") ++ if (options.value("stale").compare("true", Qt::CaseInsensitive) == 0) + phase = Start; + if (user.isEmpty() && password.isEmpty()) + phase = Done; +@@ -630,7 +630,7 @@ static QByteArray digestMd5ResponseHelper( + hash.addData(":", 1); + hash.addData(password); + QByteArray ha1 = hash.result(); +- if (alg.toLower() == "md5-sess") { ++ if (alg.compare("md5-sess", Qt::CaseInsensitive) == 0) { + hash.reset(); + // RFC 2617 contains an error, it was: + // hash.addData(ha1); +@@ -650,7 +650,7 @@ static QByteArray digestMd5ResponseHelper( + hash.addData(method); + hash.addData(":", 1); + hash.addData(digestUri); +- if (qop.toLower() == "auth-int") { ++ if (qop.compare("auth-int", Qt::CaseInsensitive) == 0) { + hash.addData(":", 1); + hash.addData(hEntity); + } +diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp +index b543ea79810..9427c3b00d8 100644 +--- a/src/network/socket/qhttpsocketengine.cpp ++++ b/src/network/socket/qhttpsocketengine.cpp +@@ -627,10 +627,9 @@ void QHttpSocketEngine::slotSocketReadNotification() + // from http spec is also allowed. + if (proxyConnectionHeader.isEmpty()) + proxyConnectionHeader = d->reply->headerField("Connection"); +- proxyConnectionHeader = proxyConnectionHeader.toLower(); +- if (proxyConnectionHeader == "close") { ++ if (proxyConnectionHeader.compare("close", Qt::CaseSensitive) == 0) { + willClose = true; +- } else if (proxyConnectionHeader == "keep-alive") { ++ } else if (proxyConnectionHeader.compare("keep-alive", Qt::CaseInsensitive) == 0) { + willClose = false; + } else { + // no Proxy-Connection header, so use the default +diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +index 33878a5f50f..43f2e31a49e 100644 +--- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp ++++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +@@ -415,8 +415,7 @@ static void *eglContextForContext(QOpenGLContext *context) + QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource) + { + #ifndef QT_NO_OPENGL +- QByteArray lowerCaseResource = resource.toLower(); +- if (lowerCaseResource == "get_egl_context") ++ if (resource.compare("get_egl_context", Qt::CaseInsensitive) == 0) + return NativeResourceForContextFunction(eglContextForContext); + #else + Q_UNUSED(resource); +diff --git a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp +index ee01a632d0f..a6ab49a004a 100644 +--- a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp ++++ b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp +@@ -858,15 +858,32 @@ void tst_QByteArray::qstricmp() + if ( actual != 0 ) { + actual = (actual < 0 ? -1 : 1); + } +- QCOMPARE(expected, actual); ++ QCOMPARE(actual, expected); ++ ++ actual = str1.toLatin1().compare(str2.toLatin1(), Qt::CaseInsensitive); ++ if ( actual != 0 ) { ++ actual = (actual < 0 ? -1 : 1); ++ } ++ QCOMPARE(actual, expected); ++ ++ actual = str1.toLatin1().compare(str2.toLatin1().constData(), Qt::CaseInsensitive); ++ if ( actual != 0 ) { ++ actual = (actual < 0 ? -1 : 1); ++ } ++ QCOMPARE(actual, expected); + } + + void tst_QByteArray::qstricmp_singularities() + { + QCOMPARE(::qstricmp(0, 0), 0); +- QVERIFY(::qstricmp(0, "a") != 0); +- QVERIFY(::qstricmp("a", 0) != 0); ++ QVERIFY(::qstricmp(0, "a") < 0); ++ QVERIFY(::qstricmp("a", 0) > 0); + QCOMPARE(::qstricmp("", ""), 0); ++ QCOMPARE(QByteArray().compare(nullptr, Qt::CaseInsensitive), 0); ++ QCOMPARE(QByteArray().compare("", Qt::CaseInsensitive), 0); ++ QVERIFY(QByteArray("a").compare(nullptr, Qt::CaseInsensitive) > 0); ++ QVERIFY(QByteArray("a").compare("", Qt::CaseInsensitive) > 0); ++ QVERIFY(QByteArray().compare("a", Qt::CaseInsensitive) < 0); + } + + void tst_QByteArray::qstrnicmp_singularities() +@@ -876,6 +893,9 @@ void tst_QByteArray::qstrnicmp_singularities() + QVERIFY(::qstrnicmp("a", 0, 123) != 0); + QCOMPARE(::qstrnicmp("", "", 123), 0); + QCOMPARE(::qstrnicmp("a", "B", 0), 0); ++ QCOMPARE(QByteArray().compare(QByteArray(), Qt::CaseInsensitive), 0); ++ QVERIFY(QByteArray().compare(QByteArray("a"), Qt::CaseInsensitive) < 0); ++ QVERIFY(QByteArray("a").compare(QByteArray(), Qt::CaseInsensitive) > 0); + } + + void tst_QByteArray::chop_data() +@@ -1759,6 +1779,12 @@ void tst_QByteArray::compare() + const bool isLess = result < 0; + const bool isGreater = result > 0; + ++ int cmp = str1.compare(str2); ++ if (cmp) ++ cmp = (cmp < 0 ? -1 : 1); ++ ++ QCOMPARE(cmp, result); ++ + // basic tests: + QCOMPARE(str1 == str2, isEqual); + QCOMPARE(str1 < str2, isLess); diff --git a/CVE-2023-32762.patch b/CVE-2023-32762.patch new file mode 100644 index 0000000..33686d9 --- /dev/null +++ b/CVE-2023-32762.patch @@ -0,0 +1,50 @@ +From 1b736a815be0222f4b24289cf17575fc15707305 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= +Date: Fri, 5 May 2023 11:07:26 +0200 +Subject: [PATCH] Hsts: match header names case insensitively + +Header field names are always considered to be case-insensitive. + +Pick-to: 6.5 6.5.1 6.2 5.15 +Fixes: QTBUG-113392 +Change-Id: Ifb4def4bb7f2ac070416cdc76581a769f1e52b43 +Reviewed-by: Qt CI Bot +Reviewed-by: Edward Welbourne +Reviewed-by: Volker Hilsheimer +--- + src/network/access/qhsts.cpp | 4 ++-- + tests/auto/network/access/hsts/tst_qhsts.cpp | 6 ++++++ + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp +index 39905f354807..82deede17298 100644 +--- a/src/network/access/qhsts.cpp ++++ b/src/network/access/qhsts.cpp +@@ -327,8 +327,8 @@ quoted-pair = "\" CHAR + bool QHstsHeaderParser::parse(const QList> &headers) + { + for (const auto &h : headers) { +- // We use '==' since header name was already 'trimmed' for us: +- if (h.first == "Strict-Transport-Security") { ++ // We compare directly because header name was already 'trimmed' for us: ++ if (h.first.compare("Strict-Transport-Security", Qt::CaseInsensitive) == 0) { + header = h.second; + // RFC6797, 8.1: + // +diff --git a/tests/auto/network/access/hsts/tst_qhsts.cpp b/tests/auto/network/access/hsts/tst_qhsts.cpp +index 252f5e8f5792..97a2d2889e57 100644 +--- a/tests/auto/network/access/hsts/tst_qhsts.cpp ++++ b/tests/auto/network/access/hsts/tst_qhsts.cpp +@@ -216,6 +216,12 @@ void tst_QHsts::testSTSHeaderParser() + QVERIFY(parser.expirationDate() > QDateTime::currentDateTimeUtc()); + QVERIFY(parser.includeSubDomains()); + ++ list.pop_back(); ++ list << Header("strict-transport-security", "includeSubDomains;max-age=1000"); ++ QVERIFY(parser.parse(list)); ++ QVERIFY(parser.expirationDate() > QDateTime::currentDateTimeUtc()); ++ QVERIFY(parser.includeSubDomains()); ++ + list.pop_back(); + // Invalid (includeSubDomains twice): + list << Header("Strict-Transport-Security", "max-age = 1000 ; includeSubDomains;includeSubDomains"); diff --git a/CVE-2023-32763.patch b/CVE-2023-32763.patch new file mode 100644 index 0000000..f3ef013 --- /dev/null +++ b/CVE-2023-32763.patch @@ -0,0 +1,65 @@ +From 16a18de0e297a21b87808270f7a06953be519d62 Mon Sep 17 00:00:00 2001 +From: starlet-dx <15929766099@163.com> +Date: Wed, 28 Jun 2023 14:11:54 +0800 +Subject: [PATCH 1/1] Fix CVE-2023-32763 + +Origin: +https://download.qt.io/official_releases/qt/5.15/CVE-2023-32763-qtbase-5.15.diff + +--- + src/gui/painting/qfixed_p.h | 9 +++++++++ + src/gui/text/qtextlayout.cpp | 9 ++++++--- + 2 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/src/gui/painting/qfixed_p.h b/src/gui/painting/qfixed_p.h +index 84659288..57d750a4 100644 +--- a/src/gui/painting/qfixed_p.h ++++ b/src/gui/painting/qfixed_p.h +@@ -54,6 +54,7 @@ + #include + #include "QtCore/qdebug.h" + #include "QtCore/qpoint.h" ++#include + #include "QtCore/qsize.h" + + QT_BEGIN_NAMESPACE +@@ -182,6 +183,14 @@ Q_DECL_CONSTEXPR inline bool operator<(int i, const QFixed &f) { return i * 64 < + Q_DECL_CONSTEXPR inline bool operator>(const QFixed &f, int i) { return f.value() > i * 64; } + Q_DECL_CONSTEXPR inline bool operator>(int i, const QFixed &f) { return i * 64 > f.value(); } + ++inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r) ++{ ++ int val; ++ bool result = add_overflow(v1.value(), v2.value(), &val); ++ r->setValue(val); ++ return result; ++} ++ + #ifndef QT_NO_DEBUG_STREAM + inline QDebug &operator<<(QDebug &dbg, const QFixed &f) + { return dbg << f.toReal(); } +diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp +index 6e824b2e..b4231a8a 100644 +--- a/src/gui/text/qtextlayout.cpp ++++ b/src/gui/text/qtextlayout.cpp +@@ -2051,11 +2051,14 @@ found: + eng->maxWidth = qMax(eng->maxWidth, line.textWidth); + } else { + eng->minWidth = qMax(eng->minWidth, lbh.minw); +- eng->maxWidth += line.textWidth; ++ if (qAddOverflow(eng->maxWidth, line.textWidth, &eng->maxWidth)) ++ eng->maxWidth = QFIXED_MAX; + } + +- if (line.textWidth > 0 && item < eng->layoutData->items.size()) +- eng->maxWidth += lbh.spaceData.textWidth; ++ if (line.textWidth > 0 && item < eng->layoutData->items.size()) { ++ if (qAddOverflow(eng->maxWidth, lbh.spaceData.textWidth, &eng->maxWidth)) ++ eng->maxWidth = QFIXED_MAX; ++ } + if (eng->option.flags() & QTextOption::IncludeTrailingSpaces) + line.textWidth += lbh.spaceData.textWidth; + if (lbh.spaceData.length) { +-- +2.30.0 + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 4235c74..8573875 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 14 +Release: 15 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -43,6 +43,9 @@ Patch6003: CVE-2021-38593.patch Patch6004: CVE-2022-25255.patch # https://download.qt.io/official_releases/qt/5.15/CVE-2023-24607-qtbase-5.15.diff Patch6005: CVE-2023-24607.patch +Patch6006: CVE-2023-32762-pre.patch +Patch6007: CVE-2023-32762.patch +Patch6008: CVE-2023-32763.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -409,6 +412,9 @@ fi %changelog +* Wed Jun 28 2023 yaoxin - 5.11.1-15 +- Fix CVE-2023-32762 and CVE-2023-32763 + * Mon May 22 2023 douyan - 5.11.1-14 - Fix CVE-2023-24607 -- Gitee From 71e5139b56dca2a56d7f023fafcb3a4c910549af Mon Sep 17 00:00:00 2001 From: wk333 <13474090681@163.com> Date: Fri, 1 Sep 2023 11:26:00 +0800 Subject: [PATCH 07/13] Fix CVE-2023-37369 (cherry picked from commit 25df666b59dd54e774940a1aa057832f8d2d30c2) --- CVE-2023-37369-pre.patch | 32 ++++++ CVE-2023-37369.patch | 203 +++++++++++++++++++++++++++++++++++++++ qt5-qtbase.spec | 9 +- 3 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 CVE-2023-37369-pre.patch create mode 100644 CVE-2023-37369.patch diff --git a/CVE-2023-37369-pre.patch b/CVE-2023-37369-pre.patch new file mode 100644 index 0000000..c806d4d --- /dev/null +++ b/CVE-2023-37369-pre.patch @@ -0,0 +1,32 @@ +From d76b11a0d55f40e964686564bac512e5895147b6 Mon Sep 17 00:00:00 2001 +From: Allan Sandfeld Jensen +Date: Wed, 14 Apr 2021 22:13:32 +0200 +Subject: [PATCH] Don't parse XML symbols longer than 4096 characters + +It is slow and will use too much memory. + +Fixes: QTBUG-91889 +Change-Id: I45c5e6038357c87bbb85b1ace17ef39a2a814ea0 +Reviewed-by: Thiago Macieira +(cherry picked from commit 38e111158a38507c63fd70f9ee18b9116b537976) +Reviewed-by: Qt Cherry-pick Bot +--- + src/corelib/serialization/qxmlstream.cpp | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp +index 9a3e306f424..a38720b370f 100644 +--- a/src/corelib/serialization/qxmlstream.cpp ++++ b/src/corelib/serialization/qxmlstream.cpp +@@ -1307,6 +1307,11 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix) + int n = 0; + uint c; + while ((c = getChar()) != StreamEOF) { ++ if (n >= 4096) { ++ // This is too long to be a sensible name, and ++ // can exhaust memory ++ return 0; ++ } + switch (c) { + case '\n': + case ' ': diff --git a/CVE-2023-37369.patch b/CVE-2023-37369.patch new file mode 100644 index 0000000..9c6305d --- /dev/null +++ b/CVE-2023-37369.patch @@ -0,0 +1,203 @@ +diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp +index 7cd457ba3a..11d162cb79 100644 +--- a/src/corelib/serialization/qxmlstream.cpp ++++ b/src/corelib/serialization/qxmlstream.cpp +@@ -1302,15 +1302,18 @@ inline int QXmlStreamReaderPrivate::fastScanContentCharList() + return n; + } + +-inline int QXmlStreamReaderPrivate::fastScanName(int *prefix) ++// Fast scan an XML attribute name (e.g. "xml:lang"). ++inline QXmlStreamReaderPrivate::FastScanNameResult ++QXmlStreamReaderPrivate::fastScanName(Value *val) + { + int n = 0; + uint c; + while ((c = getChar()) != StreamEOF) { + if (n >= 4096) { + // This is too long to be a sensible name, and +- // can exhaust memory +- return 0; ++ // can exhaust memory, or the range of decltype(*prefix) ++ raiseNamePrefixTooLongError(); ++ return {}; + } + switch (c) { + case '\n': +@@ -1339,23 +1342,23 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix) + case '+': + case '*': + putChar(c); +- if (prefix && *prefix == n+1) { +- *prefix = 0; ++ if (val && val->prefix == n + 1) { ++ val->prefix = 0; + putChar(':'); + --n; + } +- return n; ++ return FastScanNameResult(n); + case ':': +- if (prefix) { +- if (*prefix == 0) { +- *prefix = n+2; ++ if (val) { ++ if (val->prefix == 0) { ++ val->prefix = n + 2; + } else { // only one colon allowed according to the namespace spec. + putChar(c); +- return n; ++ return FastScanNameResult(n); + } + } else { + putChar(c); +- return n; ++ return FastScanNameResult(n); + } + Q_FALLTHROUGH(); + default: +@@ -1364,12 +1367,12 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix) + } + } + +- if (prefix) +- *prefix = 0; ++ if (val) ++ val->prefix = 0; + int pos = textBuffer.size() - n; + putString(textBuffer, pos); + textBuffer.resize(pos); +- return 0; ++ return FastScanNameResult(0); + } + + enum NameChar { NameBeginning, NameNotBeginning, NotName }; +@@ -1878,6 +1881,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message) + raiseError(QXmlStreamReader::NotWellFormedError, message); + } + ++void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError() ++{ ++ // TODO: add a ImplementationLimitsExceededError and use it instead ++ raiseError(QXmlStreamReader::NotWellFormedError, ++ QXmlStream::tr("Length of XML attribute name exceeds implemnetation limits (4KiB " ++ "characters).")); ++} ++ + void QXmlStreamReaderPrivate::parseError() + { + +diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g +index 4321fed68a..8c6a1a5887 100644 +--- a/src/corelib/serialization/qxmlstream.g ++++ b/src/corelib/serialization/qxmlstream.g +@@ -516,7 +516,16 @@ public: + int fastScanLiteralContent(); + int fastScanSpace(); + int fastScanContentCharList(); +- int fastScanName(int *prefix = 0); ++ ++ struct FastScanNameResult { ++ FastScanNameResult() : ok(false) {} ++ explicit FastScanNameResult(int len) : addToLen(len), ok(true) { } ++ operator bool() { return ok; } ++ int operator*() { Q_ASSERT(ok); return addToLen; } ++ int addToLen; ++ bool ok; ++ }; ++ FastScanNameResult fastScanName(Value *val = 0); + inline int fastScanNMTOKEN(); + + +@@ -525,6 +534,7 @@ public: + + void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); + void raiseWellFormedError(const QString &message); ++ void raiseNamePrefixTooLongError(); + + QXmlStreamEntityResolver *entityResolver; + +@@ -1811,7 +1821,12 @@ space_opt ::= space; + qname ::= LETTER; + /. + case $rule_number: { +- sym(1).len += fastScanName(&sym(1).prefix); ++ Value &val = sym(1); ++ if (auto res = fastScanName(&val)) ++ val.len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume($rule_number); + return false; +@@ -1822,7 +1837,11 @@ qname ::= LETTER; + name ::= LETTER; + /. + case $rule_number: +- sym(1).len += fastScanName(); ++ if (auto res = fastScanName()) ++ sym(1).len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume($rule_number); + return false; +diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h +index e5bde7b98e..b01484cac3 100644 +--- a/src/corelib/serialization/qxmlstream_p.h ++++ b/src/corelib/serialization/qxmlstream_p.h +@@ -1005,7 +1005,16 @@ public: + int fastScanLiteralContent(); + int fastScanSpace(); + int fastScanContentCharList(); +- int fastScanName(int *prefix = 0); ++ ++ struct FastScanNameResult { ++ FastScanNameResult() : ok(false) {} ++ explicit FastScanNameResult(int len) : addToLen(len), ok(true) { } ++ operator bool() { return ok; } ++ int operator*() { Q_ASSERT(ok); return addToLen; } ++ int addToLen; ++ bool ok; ++ }; ++ FastScanNameResult fastScanName(Value *val = 0); + inline int fastScanNMTOKEN(); + + +@@ -1014,6 +1023,7 @@ public: + + void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); + void raiseWellFormedError(const QString &message); ++ void raiseNamePrefixTooLongError(); + + QXmlStreamEntityResolver *entityResolver; + +@@ -1939,7 +1949,12 @@ bool QXmlStreamReaderPrivate::parse() + break; + + case 262: { +- sym(1).len += fastScanName(&sym(1).prefix); ++ Value &val = sym(1); ++ if (auto res = fastScanName(&val)) ++ val.len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume(262); + return false; +@@ -1947,7 +1962,11 @@ bool QXmlStreamReaderPrivate::parse() + } break; + + case 263: +- sym(1).len += fastScanName(); ++ if (auto res = fastScanName()) ++ sym(1).len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume(263); + return false; diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 8573875..eeb5f56 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 15 +Release: 16 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -46,6 +46,10 @@ Patch6005: CVE-2023-24607.patch Patch6006: CVE-2023-32762-pre.patch Patch6007: CVE-2023-32762.patch Patch6008: CVE-2023-32763.patch +# https://github.com/qt/qtbase/commit/d76b11a +# https://download.qt.io/official_releases/qt/5.15/CVE-2023-37369-qtbase-5.15.diff +Patch6009: CVE-2023-37369-pre.patch +Patch6010: CVE-2023-37369.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -412,6 +416,9 @@ fi %changelog +* Fri Sep 01 2023 wangkai <13474090681@163.com> - 5.11.1-16 +- Fix CVE-2023-37369 + * Wed Jun 28 2023 yaoxin - 5.11.1-15 - Fix CVE-2023-32762 and CVE-2023-32763 -- Gitee From 289c10cf237e518bf928e91229b8871a0a200ee2 Mon Sep 17 00:00:00 2001 From: peijiankang Date: Wed, 1 Nov 2023 15:39:39 +0800 Subject: [PATCH 08/13] fix CVE-2023-33285 (cherry picked from commit 1a7cf281468fbabc6743b21e58a3bd399b27f727) --- CVE-2023-33285.patch | 73 ++++++++++++++++++++++++++++++++++++++++++++ qt5-qtbase.spec | 9 ++++-- 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 CVE-2023-33285.patch diff --git a/CVE-2023-33285.patch b/CVE-2023-33285.patch new file mode 100644 index 0000000..8346573 --- /dev/null +++ b/CVE-2023-33285.patch @@ -0,0 +1,73 @@ +diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp +index 12b40fc3..99e999d4 100644 +--- a/src/network/kernel/qdnslookup_unix.cpp ++++ b/src/network/kernel/qdnslookup_unix.cpp +@@ -227,7 +227,6 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN + // responseLength in case of error, we still can extract the + // exact error code from the response. + HEADER *header = (HEADER*)response; +- const int answerCount = ntohs(header->ancount); + switch (header->rcode) { + case NOERROR: + break; +@@ -260,18 +259,31 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN + return; + } + +- // Skip the query host, type (2 bytes) and class (2 bytes). + char host[PACKETSZ], answer[PACKETSZ]; + unsigned char *p = response + sizeof(HEADER); +- int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); +- if (status < 0) { ++ int status; ++ ++ if (ntohs(header->qdcount) == 1) { ++ // Skip the query host, type (2 bytes) and class (2 bytes). ++ status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); ++ if (status < 0) { ++ reply->error = QDnsLookup::InvalidReplyError; ++ reply->errorString = tr("Could not expand domain name"); ++ return; ++ } ++ if ((p - response) + status + 4 >= responseLength) ++ header->qdcount = 0xffff; // invalid reply below ++ else ++ p += status + 4; ++ } ++ if (ntohs(header->qdcount) > 1) { + reply->error = QDnsLookup::InvalidReplyError; +- reply->errorString = tr("Could not expand domain name"); ++ reply->errorString = tr("Invalid reply received"); + return; + } +- p += status + 4; + + // Extract results. ++ const int answerCount = ntohs(header->ancount); + int answerIndex = 0; + while ((p < response + responseLength) && (answerIndex < answerCount)) { + status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); +@@ -283,6 +295,11 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN + const QString name = QUrl::fromAce(host); + + p += status; ++ ++ if ((p - response) + 10 > responseLength) { ++ // probably just a truncated reply, return what we have ++ return; ++ } + const quint16 type = (p[0] << 8) | p[1]; + p += 2; // RR type + p += 2; // RR class +@@ -290,6 +307,8 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN + p += 4; + const quint16 size = (p[0] << 8) | p[1]; + p += 2; ++ if ((p - response) + size > responseLength) ++ return; // truncated + + if (type == QDnsLookup::A) { + if (size != 4) { +-- +2.27.0 + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index eeb5f56..3952340 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 16 +Release: 17 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -50,6 +50,7 @@ Patch6008: CVE-2023-32763.patch # https://download.qt.io/official_releases/qt/5.15/CVE-2023-37369-qtbase-5.15.diff Patch6009: CVE-2023-37369-pre.patch Patch6010: CVE-2023-37369.patch +Patch6011: CVE-2023-33285.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -112,7 +113,8 @@ The qt5-qtbase-devel contains libraries and header files for qt5-qtbase. %package mysql Summary: MySQL driver for Qt5's SQL classes -BuildRequires: mysql-devel +BuildRequires: mariadb-connector-c-devel +#BuildRequires: mysql-devel Requires: %{name} = %{version}-%{release} %description mysql Qt5-qtbase-mysql provides MySQL driver for Qt5's SQL classes. @@ -416,6 +418,9 @@ fi %changelog +* Wed Nov 01 2023 peijiankang - 5.11.1-17 +- Fix CVE-2023-33285.patch + * Fri Sep 01 2023 wangkai <13474090681@163.com> - 5.11.1-16 - Fix CVE-2023-37369 -- Gitee From 836cd6d2ed60960e8fafd9d61f25529844eb5b92 Mon Sep 17 00:00:00 2001 From: peijiankang Date: Thu, 2 Nov 2023 15:24:47 +0800 Subject: [PATCH 09/13] fix CVE-2023-34410 (cherry picked from commit 2704daf4975fe94a78e3e50c90a378536670cc7d) --- qt5-qtbase.spec | 6 +++++- qtbase5.11.1-CVE-2023-34410.patch | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 qtbase5.11.1-CVE-2023-34410.patch diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 3952340..b6f698e 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 17 +Release: 18 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -51,6 +51,7 @@ Patch6008: CVE-2023-32763.patch Patch6009: CVE-2023-37369-pre.patch Patch6010: CVE-2023-37369.patch Patch6011: CVE-2023-33285.patch +Patch6012: qtbase5.11.1-CVE-2023-34410.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -418,6 +419,9 @@ fi %changelog +* Thu Nov 02 2023 peijiankang - 5.11.1-18 +- Fix CVE-2023-34410 + * Wed Nov 01 2023 peijiankang - 5.11.1-17 - Fix CVE-2023-33285.patch diff --git a/qtbase5.11.1-CVE-2023-34410.patch b/qtbase5.11.1-CVE-2023-34410.patch new file mode 100644 index 0000000..23049c8 --- /dev/null +++ b/qtbase5.11.1-CVE-2023-34410.patch @@ -0,0 +1,24 @@ +diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp +index 4273904c..8d064ba0 100644 +--- a/src/network/ssl/qsslsocket.cpp ++++ b/src/network/ssl/qsslsocket.cpp +@@ -2053,6 +2053,10 @@ QSslSocketPrivate::QSslSocketPrivate() + , flushTriggered(false) + { + QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration); ++ // If the global configuration doesn't allow root certificates to be loaded ++ // on demand then we have to disable it for this socket as well. ++ if (!configuration.allowRootCertOnDemandLoading) ++ allowRootCertOnDemandLoading = false; + } + + /*! +@@ -2252,6 +2256,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri + ptr->sessionProtocol = global->sessionProtocol; + ptr->ciphers = global->ciphers; + ptr->caCertificates = global->caCertificates; ++ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading; + ptr->protocol = global->protocol; + ptr->peerVerifyMode = global->peerVerifyMode; + ptr->peerVerifyDepth = global->peerVerifyDepth; + -- Gitee From da1c9c4d0658a3bc64c1349f6f6091c8b0c9ea9b Mon Sep 17 00:00:00 2001 From: hua_yadong Date: Fri, 24 Nov 2023 14:14:40 +0800 Subject: [PATCH 10/13] qtbase5.11.1-CVE-2023-38197 --- qt5-qtbase.spec | 7 +- qtbase5.11.1-CVE-2023-38197.patch | 366 ++++++++++++++++++++++++++++++ 2 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 qtbase5.11.1-CVE-2023-38197.patch diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index b6f698e..8c9a402 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 18 +Release: 19 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -52,6 +52,8 @@ Patch6009: CVE-2023-37369-pre.patch Patch6010: CVE-2023-37369.patch Patch6011: CVE-2023-33285.patch Patch6012: qtbase5.11.1-CVE-2023-34410.patch +#https://codereview.qt-project.org/c/qt/qtbase/+/488960 +Patch6013: qtbase5.11.1-CVE-2023-38197.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -419,6 +421,9 @@ fi %changelog +* Fri Nov 24 2023 hua_yadong - 5.11.1-19 +- Fix qtbase5.11.1-CVE-2023-38197.patch + * Thu Nov 02 2023 peijiankang - 5.11.1-18 - Fix CVE-2023-34410 diff --git a/qtbase5.11.1-CVE-2023-38197.patch b/qtbase5.11.1-CVE-2023-38197.patch new file mode 100644 index 0000000..58ec54a --- /dev/null +++ b/qtbase5.11.1-CVE-2023-38197.patch @@ -0,0 +1,366 @@ +From 6d909527f97c8a43085bcbdfc5c67a5425837c37 Mon Sep 17 00:00:00 2001 +From: hua_yadong +Date: Fri, 24 Nov 2023 14:12:19 +0800 +Subject: [PATCH] qtbase5.11.1-CVE-2023-38197 + +--- + src/corelib/serialization/qxmlstream.cpp | 139 +++++++++++++++++- + src/corelib/serialization/qxmlstream_p.h | 11 ++ + .../qxmlstream/tokenError/dtdInBody.xml | 21 +++ + .../qxmlstream/tokenError/multipleDtd.xml | 21 +++ + .../qxmlstream/tokenError/wellFormed.xml | 16 ++ + .../qxmlstream/tst_qxmlstream.cpp | 39 +++++ + 6 files changed, 239 insertions(+), 8 deletions(-) + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml + +diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp +index 325a3436..e9fbbb4a 100644 +--- a/src/corelib/serialization/qxmlstream.cpp ++++ b/src/corelib/serialization/qxmlstream.cpp +@@ -155,7 +155,7 @@ enum { StreamEOF = ~0U }; + addData() or by waiting for it to arrive on the device(). + + \value UnexpectedElementError The parser encountered an element +- that was different to those it expected. ++ or token that was different to those it expected. + + */ + +@@ -292,13 +292,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const + + QXmlStreamReader is a well-formed XML 1.0 parser that does \e not + include external parsed entities. As long as no error occurs, the +- application code can thus be assured that the data provided by the +- stream reader satisfies the W3C's criteria for well-formed XML. For +- example, you can be certain that all tags are indeed nested and +- closed properly, that references to internal entities have been +- replaced with the correct replacement text, and that attributes have +- been normalized or added according to the internal subset of the +- DTD. ++ application code can thus be assured, that ++ \list ++ \li the data provided by the stream reader satisfies the W3C's ++ criteria for well-formed XML, ++ \li tokens are provided in a valid order. ++ \endlist ++ ++ Unless QXmlStreamReader raises an error, it guarantees the following: ++ \list ++ \li All tags are nested and closed properly. ++ \li References to internal entities have been replaced with the ++ correct replacement text. ++ \li Attributes have been normalized or added according to the ++ internal subset of the \l DTD. ++ \li Tokens of type \l StartDocument happen before all others, ++ aside from comments and processing instructions. ++ \li At most one DOCTYPE element (a token of type \l DTD) is present. ++ \li If present, the DOCTYPE appears before all other elements, ++ aside from StartDocument, comments and processing instructions. ++ \endlist ++ ++ In particular, once any token of type \l StartElement, \l EndElement, ++ \l Characters, \l EntityReference or \l EndDocument is seen, no ++ tokens of type StartDocument or DTD will be seen. If one is present in ++ the input stream, out of order, an error is raised. ++ ++ \note The token types \l Comment and \l ProcessingInstruction may appear ++ anywhere in the stream. + + If an error occurs while parsing, atEnd() and hasError() return + true, and error() returns the error that occurred. The functions +@@ -617,6 +638,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext() + d->token = -1; + return readNext(); + } ++ d->checkToken(); + return d->type; + } + +@@ -736,6 +758,9 @@ static const short QXmlStreamReader_tokenTypeString_indices[] = { + 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0 + }; + ++static const char QXmlStreamReader_XmlContextString[] = ++ "Prolog\0" ++ "Body\0"; + + /*! + \property QXmlStreamReader::namespaceProcessing +@@ -772,6 +797,16 @@ QString QXmlStreamReader::tokenString() const + QXmlStreamReader_tokenTypeString_indices[d->type]); + } + ++/*! ++ \internal ++ \return \param loc (Prolog/Body) as a string. ++ */ ++static const QLatin1String contextString(QXmlStreamReaderPrivate::XmlContext ctxt) ++{ ++ return QLatin1String(QXmlStreamReader_XmlContextString + ++ QXmlStreamReader_XmlContextString[static_cast(ctxt)]); ++} ++ + #endif // QT_NO_XMLSTREAMREADER + + QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack() +@@ -863,6 +898,8 @@ void QXmlStreamReaderPrivate::init() + + type = QXmlStreamReader::NoToken; + error = QXmlStreamReader::NoError; ++ currentContext = XmlContext::Prolog; ++ foundDTD = false; + } + + /* +@@ -4046,6 +4083,92 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader) + } + } + ++static bool isTokenAllowedInContext(QXmlStreamReader::TokenType type, ++ QXmlStreamReaderPrivate::XmlContext loc) ++{ ++ switch (type) { ++ case QXmlStreamReader::StartDocument: ++ case QXmlStreamReader::DTD: ++ return loc == QXmlStreamReaderPrivate::XmlContext::Prolog; ++ ++ case QXmlStreamReader::StartElement: ++ case QXmlStreamReader::EndElement: ++ case QXmlStreamReader::Characters: ++ case QXmlStreamReader::EntityReference: ++ case QXmlStreamReader::EndDocument: ++ return loc == QXmlStreamReaderPrivate::XmlContext::Body; ++ ++ case QXmlStreamReader::Comment: ++ case QXmlStreamReader::ProcessingInstruction: ++ return true; ++ ++ case QXmlStreamReader::NoToken: ++ case QXmlStreamReader::Invalid: ++ return false; ++ } ++ ++ return false; ++} ++ ++/*! ++ \internal ++ \brief QXmlStreamReader::isValidToken ++ \return \c true if \param type is a valid token type. ++ \return \c false if \param type is an unexpected token, ++ which indicates a non-well-formed or invalid XML stream. ++ */ ++bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type) ++{ ++ // Don't change currentContext, if Invalid or NoToken occur in the prolog ++ if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken) ++ return false; ++ ++ // If a token type gets rejected in the body, there is no recovery ++ const bool result = isTokenAllowedInContext(type, currentContext); ++ if (result || currentContext == XmlContext::Body) ++ return result; ++ ++ // First non-Prolog token observed => switch context to body and check again. ++ currentContext = XmlContext::Body; ++ return isTokenAllowedInContext(type, currentContext); ++} ++ ++/*! ++ \internal ++ Checks token type and raises an error, if it is invalid ++ in the current context (prolog/body). ++ */ ++void QXmlStreamReaderPrivate::checkToken() ++{ ++ Q_Q(QXmlStreamReader); ++ ++ // The token type must be consumed, to keep track if the body has been reached. ++ const XmlContext context = currentContext; ++ const bool ok = isValidToken(type); ++ ++ // Do nothing if an error has been raised already (going along with an unexpected token) ++ if (error != QXmlStreamReader::Error::NoError) ++ return; ++ ++ if (!ok) { ++ raiseError(QXmlStreamReader::UnexpectedElementError, ++ QStringLiteral("Unexpected token type %1 in %2.") ++ .arg(q->tokenString(), contextString(context))); ++ return; ++ } ++ ++ if (type != QXmlStreamReader::DTD) ++ return; ++ ++ // Raise error on multiple DTD tokens ++ if (foundDTD) { ++ raiseError(QXmlStreamReader::UnexpectedElementError, ++ QStringLiteral("Found second DTD token in %1.").arg(contextString(context))); ++ } else { ++ foundDTD = true; ++ } ++} ++ + /*! + \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const + \since 4.5 +diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h +index 60ba2175..e15ddc35 100644 +--- a/src/corelib/serialization/qxmlstream_p.h ++++ b/src/corelib/serialization/qxmlstream_p.h +@@ -804,6 +804,17 @@ public: + #endif + bool atEnd; + ++ enum class XmlContext ++ { ++ Prolog, ++ Body, ++ }; ++ ++ XmlContext currentContext = XmlContext::Prolog; ++ bool foundDTD = false; ++ bool isValidToken(QXmlStreamReader::TokenType type); ++ void checkToken(); ++ + /*! + \sa setType() + */ +diff --git a/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml b/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml +new file mode 100644 +index 00000000..68ef2962 +--- /dev/null ++++ b/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml +@@ -0,0 +1,21 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ ++ ++ ++ ]> ++ ++ +diff --git a/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml b/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml +new file mode 100644 +index 00000000..1dbe75c4 +--- /dev/null ++++ b/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml +@@ -0,0 +1,21 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ ++ +diff --git a/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml b/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml +new file mode 100644 +index 00000000..9dfbc0f9 +--- /dev/null ++++ b/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml +@@ -0,0 +1,16 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ ++ +diff --git a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +index 16a4200b..1f633b6d 100644 +--- a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp ++++ b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +@@ -578,6 +578,9 @@ private slots: + void hasError() const; + void readBack() const; + ++ void tokenErrorHandling_data() const; ++ void tokenErrorHandling() const; ++ + private: + static QByteArray readFile(const QString &filename); + +@@ -1741,5 +1744,41 @@ void tst_QXmlStream::readBack() const + } + } + ++void tst_QXmlStream::tokenErrorHandling_data() const ++{ ++ QTest::addColumn("fileName"); ++ QTest::addColumn("expectedError"); ++ QTest::addColumn("errorKeyWord"); ++ ++ constexpr auto invalid = QXmlStreamReader::Error::UnexpectedElementError; ++ constexpr auto valid = QXmlStreamReader::Error::NoError; ++ QTest::newRow("DtdInBody") << "dtdInBody.xml" << invalid << "DTD"; ++ QTest::newRow("multipleDTD") << "multipleDtd.xml" << invalid << "second DTD"; ++ QTest::newRow("wellFormed") << "wellFormed.xml" << valid << ""; ++} ++ ++void tst_QXmlStream::tokenErrorHandling() const ++{ ++ QFETCH(const QString, fileName); ++ QFETCH(const QXmlStreamReader::Error, expectedError); ++ QFETCH(const QString, errorKeyWord); ++ ++ const QDir dir(QFINDTESTDATA("tokenError")); ++ QFile file(dir.absoluteFilePath(fileName)); ++ ++ // Cross-compiling: File will be on host only ++ if (!file.exists()) ++ QSKIP("Testfile not found."); ++ ++ file.open(QIODevice::ReadOnly); ++ QXmlStreamReader reader(&file); ++ while (!reader.atEnd()) ++ reader.readNext(); ++ ++ QCOMPARE(reader.error(), expectedError); ++ if (expectedError != QXmlStreamReader::Error::NoError) ++ QVERIFY(reader.errorString().contains(errorKeyWord)); ++} ++ + #include "tst_qxmlstream.moc" + // vim: et:ts=4:sw=4:sts=4 +-- +2.41.0 + -- Gitee From f77458fcd067e106cae229f698efb8726e3bca45 Mon Sep 17 00:00:00 2001 From: hua_yadong Date: Sat, 25 Nov 2023 11:46:17 +0800 Subject: [PATCH 11/13] qt-CVE-2023-43114 --- qt5-qtbase.spec | 7 +- qtbase5.11.1-CVE-2023-43114.patch | 129 ++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 qtbase5.11.1-CVE-2023-43114.patch diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 8c9a402..558e708 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 19 +Release: 20 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -54,6 +54,8 @@ Patch6011: CVE-2023-33285.patch Patch6012: qtbase5.11.1-CVE-2023-34410.patch #https://codereview.qt-project.org/c/qt/qtbase/+/488960 Patch6013: qtbase5.11.1-CVE-2023-38197.patch +#https://codereview.qt-project.org/c/qt/qtbase/+/503026 +Patch6014: qtbase5.11.1-CVE-2023-43114.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -421,6 +423,9 @@ fi %changelog +* Sat Nov 25 2023 hua_yadong - 5.11.1-20 +- Fix qtbase5.11.1-CVE-2023-43114.patch + * Fri Nov 24 2023 hua_yadong - 5.11.1-19 - Fix qtbase5.11.1-CVE-2023-38197.patch diff --git a/qtbase5.11.1-CVE-2023-43114.patch b/qtbase5.11.1-CVE-2023-43114.patch new file mode 100644 index 0000000..a771303 --- /dev/null +++ b/qtbase5.11.1-CVE-2023-43114.patch @@ -0,0 +1,129 @@ +From 20eb208612f2ea3601151a058bcfa743ab9ff3ac Mon Sep 17 00:00:00 2001 +From: hua_yadong +Date: Sat, 25 Nov 2023 11:43:09 +0800 +Subject: [PATCH] qtbase5.11.1-CVE-2023-43114 + +--- + .../windows/qwindowsfontdatabase.cpp | 67 ++++++++++++++----- + 1 file changed, 51 insertions(+), 16 deletions(-) + +diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +index aab1ab98..a541326a 100644 +--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp ++++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +@@ -1463,36 +1463,70 @@ QT_WARNING_POP + return fontEngine; + } + +-static QList getTrueTypeFontOffsets(const uchar *fontData) ++static QList getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel) + { + QList offsets; +- const quint32 headerTag = *reinterpret_cast(fontData); ++ if (fileEndSentinel - fontData < 12) { ++ qCWarning(lcQpaFonts) << "Corrupted font data detected"; ++ return offsets; ++ } ++ ++ const quint32 headerTag = qFromUnaligned(fontData); + if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) { + if (headerTag != MAKE_TAG(0, 1, 0, 0) + && headerTag != MAKE_TAG('O', 'T', 'T', 'O') + && headerTag != MAKE_TAG('t', 'r', 'u', 'e') +- && headerTag != MAKE_TAG('t', 'y', 'p', '1')) ++ && headerTag != MAKE_TAG('t', 'y', 'p', '1')) { + return offsets; ++ } + offsets << 0; + return offsets; + } ++ ++ const quint32 maximumNumFonts = 0xffff; + const quint32 numFonts = qFromBigEndian(fontData + 8); +- for (uint i = 0; i < numFonts; ++i) { +- offsets << qFromBigEndian(fontData + 12 + i * 4); ++ if (numFonts > maximumNumFonts) { ++ qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting."; ++ return offsets; + } ++ ++ if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) { ++ for (quint32 i = 0; i < numFonts; ++i) ++ offsets << qFromBigEndian(fontData + 12 + i * 4); ++ } else { ++ qCWarning(lcQpaFonts) << "Corrupted font data detected"; ++ } ++ + return offsets; + } + +-static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length) ++static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length) + { +- const quint16 numTables = qFromBigEndian(data + 4); +- for (uint i = 0; i < numTables; ++i) { +- const quint32 offset = 12 + 16 * i; +- if (*reinterpret_cast(data + offset) == tag) { +- *table = fileBegin + qFromBigEndian(data + offset + 8); +- *length = qFromBigEndian(data + offset + 12); +- return; ++ if (fileEndSentinel - data >= 6) { ++ const quint16 numTables = qFromBigEndian(data + 4); ++ if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) { ++ for (quint32 i = 0; i < numTables; ++i) { ++ const quint32 offset = 12 + 16 * i; ++ if (qFromUnaligned(data + offset) == tag) { ++ const quint32 tableOffset = qFromBigEndian(data + offset + 8); ++ if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) { ++ qCWarning(lcQpaFonts) << "Corrupted font data detected"; ++ break; ++ } ++ *table = fileBegin + tableOffset; ++ *length = qFromBigEndian(data + offset + 12); ++ if (quintptr(fileEndSentinel - *table) < *length) { ++ qCWarning(lcQpaFonts) << "Corrupted font data detected"; ++ break; ++ } ++ return; ++ } ++ } ++ } else { ++ qCWarning(lcQpaFonts) << "Corrupted font data detected"; + } ++ } else { ++ qCWarning(lcQpaFonts) << "Corrupted font data detected"; + } + *table = 0; + *length = 0; +@@ -1504,8 +1538,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, + QVector *signatures) + { + const uchar *data = reinterpret_cast(fontData.constData()); ++ const uchar *dataEndSentinel = data + fontData.size(); + +- QList offsets = getTrueTypeFontOffsets(data); ++ QList offsets = getTrueTypeFontOffsets(data, dataEndSentinel); + if (offsets.isEmpty()) + return; + +@@ -1513,7 +1548,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, + const uchar *font = data + offsets.at(i); + const uchar *table; + quint32 length; +- getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); ++ getFontTable(data, dataEndSentinel, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); + if (!table) + continue; + FontNames names = qt_getCanonicalFontNames(table, length); +@@ -1524,7 +1559,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, + + if (signatures) { + FONTSIGNATURE signature; +- getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); ++ getFontTable(data, dataEndSentinel, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); + if (table && length >= 86) { + // Offsets taken from OS/2 table in the TrueType spec + signature.fsUsb[0] = qFromBigEndian(table + 42); +-- +2.41.0 + -- Gitee From 1251bb79127494212d90017de3a8a775ec47abe5 Mon Sep 17 00:00:00 2001 From: peijiankang Date: Wed, 31 Jan 2024 13:47:02 +0800 Subject: [PATCH 12/13] qtbase5.11.1-CVE-2023-51714 --- qt5-qtbase.spec | 6 ++++- qtbase5.11.1-CVE-2023-51714.patch | 38 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 qtbase5.11.1-CVE-2023-51714.patch diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 558e708..908ef08 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 20 +Release: 21 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -56,6 +56,7 @@ Patch6012: qtbase5.11.1-CVE-2023-34410.patch Patch6013: qtbase5.11.1-CVE-2023-38197.patch #https://codereview.qt-project.org/c/qt/qtbase/+/503026 Patch6014: qtbase5.11.1-CVE-2023-43114.patch +Patch6015: qtbase5.11.1-CVE-2023-51714.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -423,6 +424,9 @@ fi %changelog +* Wed Jan 31 2024 douyan - 5.11.1-21 +- add qtbase5.11.1-CVE-2023-51714.patch + * Sat Nov 25 2023 hua_yadong - 5.11.1-20 - Fix qtbase5.11.1-CVE-2023-43114.patch diff --git a/qtbase5.11.1-CVE-2023-51714.patch b/qtbase5.11.1-CVE-2023-51714.patch new file mode 100644 index 0000000..24f2077 --- /dev/null +++ b/qtbase5.11.1-CVE-2023-51714.patch @@ -0,0 +1,38 @@ +From 7743b020c54b4ac7152be1305ad61c6a8fdc604d Mon Sep 17 00:00:00 2001 +From: peijiankang +Date: Wed, 31 Jan 2024 13:43:57 +0800 +Subject: [PATCH] qtbase5.11.1-CVE-2023-51714 + +--- + src/network/access/http2/hpacktable.cpp | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/network/access/http2/hpacktable.cpp b/src/network/access/http2/hpacktable.cpp +index a90ee72d..4f452ad0 100644 +--- a/src/network/access/http2/hpacktable.cpp ++++ b/src/network/access/http2/hpacktable.cpp +@@ -40,6 +40,7 @@ + #include "hpacktable_p.h" + + #include ++#include + + #include + #include +@@ -60,9 +61,10 @@ HeaderSize entry_size(const QByteArray &name, const QByteArray &value) + // to reference the name and the value of the entry and two 64-bit integers + // for counting the number of references to the name and value would have + // 32 octets of overhead." +- +- const unsigned sum = unsigned(name.size()) + value.size(); +- if (std::numeric_limits::max() - 32 < sum) ++ size_t sum; ++ if (add_overflow(size_t(name.size()), size_t(value.size()), &sum)) ++ return HeaderSize(); ++ if (sum > (std::numeric_limits::max() - 32)) + return HeaderSize(); + return HeaderSize(true, quint32(sum + 32)); + } +-- +2.41.0 + -- Gitee From b1cad792c813e4ba4a0ce3457c5b390d84f3aacd Mon Sep 17 00:00:00 2001 From: lvfei Date: Sun, 28 Apr 2024 09:47:31 +0800 Subject: [PATCH 13/13] Fix CVE-2023-45935 --- CVE-2023-45935.patch | 31 +++++++++++++++++++++++++++++++ qt5-qtbase.spec | 6 +++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 CVE-2023-45935.patch diff --git a/CVE-2023-45935.patch b/CVE-2023-45935.patch new file mode 100644 index 0000000..3a42886 --- /dev/null +++ b/CVE-2023-45935.patch @@ -0,0 +1,31 @@ +From e876e91e829f6f0d6b9942ae4de80f8323f750ca Mon Sep 17 00:00:00 2001 +From: Liang Qi +Date: 2023-07-31 05:35:11 +0200 +Subject: [PATCH] CVE-2023-45935 + +port invokeMethodImpl() from QScopeGuard to SlotObjUniquePtr + +--- + src/plugins/platforms/xcb/qxcbconnection.cpp | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp +index 5fd1fc6a..2ec668a6 100644 +--- a/src/plugins/platforms/xcb/qxcbconnection.cpp ++++ b/src/plugins/platforms/xcb/qxcbconnection.cpp +@@ -2051,8 +2051,10 @@ void QXcbConnection::initializeAllAtoms() { + + for (i = 0; i < QXcbAtom::NAtoms; ++i) { + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0); +- m_allAtoms[i] = reply->atom; +- free(reply); ++ if (reply) { ++ m_allAtoms[i] = reply->atom; ++ free(reply); ++ } + } + } + +-- +2.27.0 + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 908ef08..32fc6ba 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -13,7 +13,7 @@ Name: qt5-qtbase Summary: Core component of Qt toolkit Version: 5.11.1 -Release: 21 +Release: 22 License: LGPLv2 with exceptions or GPLv3 with exceptions Url: http://qt-project.org/ Source0: https://download.qt.io/new_archive/qt/5.11/%{version}/submodules/qtbase-everywhere-src-%{version}.tar.xz @@ -57,6 +57,7 @@ Patch6013: qtbase5.11.1-CVE-2023-38197.patch #https://codereview.qt-project.org/c/qt/qtbase/+/503026 Patch6014: qtbase5.11.1-CVE-2023-43114.patch Patch6015: qtbase5.11.1-CVE-2023-51714.patch +Patch6016: CVE-2023-45935.patch BuildRequires: pkgconfig(libsystemd) cups-devel desktop-file-utils findutils BuildRequires: libjpeg-devel libmng-devel libtiff-devel pkgconfig(alsa) @@ -424,6 +425,9 @@ fi %changelog +* Wed Apr 24 2024 lvfei - 5.11.1-22 +- Fix CVE-2023-45935 + * Wed Jan 31 2024 douyan - 5.11.1-21 - add qtbase5.11.1-CVE-2023-51714.patch -- Gitee