diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 7f7ff0c72..ea2988f71 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -8,7 +8,15 @@ $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib printsupport -$(package)_patches=mac-qmake.conf mingw-uuidof.patch pidlist_absolute.patch fix-xcb-include-order.patch fix_qfontengine_coretext.patch fix_qt_pkgconfig.patch no-xlib.patch + +$(package)_patches=mac-qmake.conf +$(package)_patches+=mingw-uuidof.patch +$(package)_patches+=pidlist_absolute.patch +$(package)_patches+=fix-xcb-include-order.patch +$(package)_patches+=fix_qfontengine_coretext.patch +$(package)_patches+=fix_qt_pkgconfig.patch +$(package)_patches+=no-xlib.patch +$(package)_patches+=backports-1.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=3a15aebd523c6d89fb97b2d3df866c94149653a26d27a00aac9b6d3020bc5a1d @@ -175,6 +183,7 @@ define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/fix_qfontengine_coretext.patch && \ patch -p1 < $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \ + patch -p1 < $($(package)_patch_dir)/backports-1.patch && \ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ diff --git a/depends/patches/qt/backports-1.patch b/depends/patches/qt/backports-1.patch new file mode 100644 index 000000000..a34407352 --- /dev/null +++ b/depends/patches/qt/backports-1.patch @@ -0,0 +1,483 @@ +From: Patrick Lodder +Date: Sat Oct 28 19:43:22 2023 +0200 +Subject: [patch] Backport high severity Qt patches until 5.15 + +Patch qtbase 5.7.1 to include high severity patches that apply +to Dogecoin Core. + +- Fix possible heap corruption in QXmlStream + see: https://codereview.qt-project.org/c/qt/qtbase/+/236691 + +- do not attempt to load a library relative to $PWD + see: https://codereview.qt-project.org/c/qt/qtbase/+/286795 + +- Fix specific overflow in qtextlayout + see: https://codereview.qt-project.org/c/qt/qtbase/+/476125 + +- QDnsLookup/Unix: Ensure that both the RDATA and the Record header fields + before it fall inside the buffer we have + see: https://codereview.qt-project.org/c/qt/qtbase/+/477644 + +- Fix a crash while parsing an XML file with garbage data + see: https://codereview.qt-project.org/c/qt/qtbase/+/471756 + https://codereview.qt-project.org/c/qt/qtbase/+/455027 + +- Fix crash when reading corrupt font data + see: https://codereview.qt-project.org/c/qt/qtbase/+/503026 + +--------- +diff -dur a/qtbase/src/corelib/plugin/qlibrary_unix.cpp b/qtbase/src/corelib/plugin/qlibrary_unix.cpp +--- a/qtbase/src/corelib/plugin/qlibrary_unix.cpp 2016-12-01 03:17:04 ++++ b/qtbase/src/corelib/plugin/qlibrary_unix.cpp 2023-10-28 13:28:11 +@@ -216,6 +216,10 @@ + for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) { + if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix))) + continue; ++ ++ if (path.isEmpty() && prefixes.at(prefix).contains(QLatin1Char('/'))) ++ continue; ++ + if (!suffixes.at(suffix).isEmpty() && name.endsWith(suffixes.at(suffix))) + continue; + if (loadHints & QLibrary::LoadArchiveMemberHint) { +diff -dur a/qtbase/src/corelib/xml/qxmlstream.cpp b/qtbase/src/corelib/xml/qxmlstream.cpp +--- a/qtbase/src/corelib/xml/qxmlstream.cpp 2016-12-01 03:17:04 ++++ b/qtbase/src/corelib/xml/qxmlstream.cpp 2023-10-29 08:25:30 +@@ -1289,11 +1289,18 @@ + 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) { ++ // can exhaust memory, or the range of decltype(*prefix) ++ raiseNamePrefixTooLongError(); ++ return {}; ++ } + switch (c) { + case '\n': + case ' ': +@@ -1321,23 +1328,23 @@ + 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); + } + // fall through + default: +@@ -1346,12 +1353,12 @@ + } + } + +- 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 }; +@@ -1856,6 +1863,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() +Only in b/qtbase/src/corelib/xml: qxmlstream.cpp.orig +diff -dur a/qtbase/src/corelib/xml/qxmlstream.g b/qtbase/src/corelib/xml/qxmlstream.g +--- a/qtbase/src/corelib/xml/qxmlstream.g 2016-12-01 03:17:04 ++++ b/qtbase/src/corelib/xml/qxmlstream.g 2023-10-29 08:27:05 +@@ -490,7 +490,17 @@ + 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 = nullptr); ++ + inline int fastScanNMTOKEN(); + + +@@ -499,6 +509,7 @@ + + void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); + void raiseWellFormedError(const QString &message); ++ void raiseNamePrefixTooLongError(); + + QXmlStreamEntityResolver *entityResolver; + +@@ -1782,7 +1793,12 @@ + 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; +@@ -1793,7 +1809,11 @@ + 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; +Only in b/qtbase/src/corelib/xml: qxmlstream.g.orig +diff -dur a/qtbase/src/corelib/xml/qxmlstream_p.h b/qtbase/src/corelib/xml/qxmlstream_p.h +--- a/qtbase/src/corelib/xml/qxmlstream_p.h 2016-12-01 03:17:04 ++++ b/qtbase/src/corelib/xml/qxmlstream_p.h 2023-10-29 08:28:31 +@@ -985,7 +985,16 @@ + 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 = nullptr); + inline int fastScanNMTOKEN(); + + +@@ -994,6 +1003,7 @@ + + void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); + void raiseWellFormedError(const QString &message); ++ void raiseNamePrefixTooLongError(); + + QXmlStreamEntityResolver *entityResolver; + +@@ -1239,7 +1249,7 @@ + state_stack[tos] = 0; + return true; + } else if (act > 0) { +- if (++tos == stack_size-1) ++ if (++tos >= stack_size-1) + reallocateStack(); + + Value &val = sym_stack[tos]; +@@ -1914,7 +1924,12 @@ + 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; +@@ -1922,7 +1937,11 @@ + } break; + + case 263: +- sym(1).len += fastScanName(); ++ if (auto res = fastScanName()) ++ sym(1).len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume(263); + return false; +Only in b/qtbase/src/corelib/xml: qxmlstream_p.h.orig +diff -dur a/qtbase/src/gui/painting/qfixed_p.h b/qtbase/src/gui/painting/qfixed_p.h +--- a/qtbase/src/gui/painting/qfixed_p.h 2016-12-01 03:17:04 ++++ b/qtbase/src/gui/painting/qfixed_p.h 2023-10-28 13:28:11 +@@ -53,6 +53,7 @@ + + #include "QtCore/qdebug.h" + #include "QtCore/qpoint.h" ++#include "QtCore/private/qnumeric_p.h" + #include "QtCore/qsize.h" + + QT_BEGIN_NAMESPACE +@@ -167,6 +168,14 @@ + Q_DECL_CONSTEXPR inline QFixed operator+(uint i, const QFixed &d) { return d+i; } + Q_DECL_CONSTEXPR inline QFixed operator-(uint i, const QFixed &d) { return -(d-i); } + // Q_DECL_CONSTEXPR inline QFixed operator*(qreal d, const QFixed &d2) { return d2*d; } ++ ++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; ++} + + 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 f.value() == i * 64; } + +diff -dur a/qtbase/src/gui/text/qtextlayout.cpp b/qtbase/src/gui/text/qtextlayout.cpp +--- a/qtbase/src/gui/text/qtextlayout.cpp 2016-12-01 03:17:04 ++++ b/qtbase/src/gui/text/qtextlayout.cpp 2023-10-28 18:29:14 +@@ -2036,11 +2036,14 @@ + 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) { +diff -dur a/qtbase/src/network/kernel/qdnslookup_unix.cpp b/qtbase/src/network/kernel/qdnslookup_unix.cpp +--- a/qtbase/src/network/kernel/qdnslookup_unix.cpp 2016-12-01 03:17:04 ++++ b/qtbase/src/network/kernel/qdnslookup_unix.cpp 2023-10-28 18:00:41 +@@ -193,7 +193,6 @@ + + // Check the response header. + HEADER *header = (HEADER*)response; +- const int answerCount = ntohs(header->ancount); + switch (header->rcode) { + case NOERROR: + break; +@@ -226,18 +225,31 @@ + 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 = 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)); +@@ -249,6 +261,10 @@ + 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 +@@ -256,6 +272,9 @@ + 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) { +diff -dur a/qtbase/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/qtbase/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +--- a/qtbase/src/plugins/platforms/windows/qwindowsfontdatabase.cpp 2016-12-01 03:17:04 ++++ b/qtbase/src/plugins/platforms/windows/qwindowsfontdatabase.cpp 2023-10-29 07:10:06 +@@ -1342,10 +1342,15 @@ + 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') +@@ -1355,23 +1360,52 @@ + 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; +@@ -1383,8 +1417,9 @@ + 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; + +@@ -1392,7 +1427,7 @@ + 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; + QString name = getEnglishName(table, length); +@@ -1403,7 +1438,7 @@ + + 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);