diff --git a/CVE-2025-5455-qtbase-6.8.patch b/CVE-2025-5455-qtbase-6.8.patch new file mode 100644 index 0000000000000000000000000000000000000000..808f41fe9cf9602ca7d96f4d1078898628017725 --- /dev/null +++ b/CVE-2025-5455-qtbase-6.8.patch @@ -0,0 +1,21 @@ +diff --git a/src/corelib/io/qdataurl.cpp b/src/corelib/io/qdataurl.cpp +index 65b934b3f67..c5ecca8fb82 100644 +--- a/src/corelib/io/qdataurl.cpp ++++ b/src/corelib/io/qdataurl.cpp +@@ -47,10 +47,10 @@ Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray + QLatin1StringView textPlain; + constexpr auto charset = "charset"_L1; + if (QLatin1StringView{data}.startsWith(charset, Qt::CaseInsensitive)) { +- qsizetype i = charset.size(); +- while (data.at(i) == ' ') +- ++i; +- if (data.at(i) == '=') ++ QByteArrayView copy = data.sliced(charset.size()); ++ while (copy.startsWith(' ')) ++ copy.slice(1); ++ if (copy.startsWith('=')) + textPlain = "text/plain;"_L1; + } + + + diff --git a/CVE-2025-6338-qtbase-6.8.patch b/CVE-2025-6338-qtbase-6.8.patch new file mode 100644 index 0000000000000000000000000000000000000000..9257481b80d4cf69e7ab458a6ea71da475c4e308 --- /dev/null +++ b/CVE-2025-6338-qtbase-6.8.patch @@ -0,0 +1,263 @@ +diff --git a/src/plugins/tls/schannel/qtls_schannel.cpp b/src/plugins/tls/schannel/qtls_schannel.cpp +index c7f4a67ea9c0..9d14ed560bf8 100644 +--- a/src/plugins/tls/schannel/qtls_schannel.cpp ++++ b/src/plugins/tls/schannel/qtls_schannel.cpp +@@ -7,6 +7,7 @@ + #include "qtlskey_schannel_p.h" + #include "qx509_schannel_p.h" + #include "qtls_schannel_p.h" ++#include "../shared/qasn1element_p.h" + + #include + #include +@@ -126,8 +127,9 @@ using namespace Qt::StringLiterals; + Q_LOGGING_CATEGORY(lcTlsBackendSchannel, "qt.tlsbackend.schannel"); + + // Defined in qsslsocket_qt.cpp. +-QByteArray _q_makePkcs12(const QList &certs, const QSslKey &key, ++extern QByteArray _q_makePkcs12(const QList &certs, const QSslKey &key, + const QString &passPhrase); ++extern QAsn1Element _q_PKCS12_key(const QSslKey &key); + + namespace { + bool supportsTls13(); +@@ -1008,7 +1010,6 @@ TlsCryptographSchannel::~TlsCryptographSchannel() + closeCertificateStores(); + deallocateContext(); + freeCredentialsHandle(); +- CertFreeCertificateContext(localCertContext); + } + + void TlsCryptographSchannel::init(QSslSocket *qObj, QSslSocketPrivate *dObj) +@@ -1103,12 +1104,6 @@ bool TlsCryptographSchannel::acquireCredentialsHandle() + return false; + } + +- const CERT_CHAIN_CONTEXT *chainContext = nullptr; +- auto freeCertChain = qScopeGuard([&chainContext]() { +- if (chainContext) +- CertFreeCertificateChain(chainContext); +- }); +- + DWORD certsCount = 0; + // Set up our certificate stores before trying to use one... + initializeCertificateStores(); +@@ -1119,36 +1114,11 @@ bool TlsCryptographSchannel::acquireCredentialsHandle() + if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore) + return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect + ++ PCCERT_CONTEXT localCertificate = nullptr; + if (localCertificateStore != nullptr) { +- CERT_CHAIN_FIND_BY_ISSUER_PARA findParam; +- ZeroMemory(&findParam, sizeof(findParam)); +- findParam.cbSize = sizeof(findParam); +- findParam.pszUsageIdentifier = isClient ? szOID_PKIX_KP_CLIENT_AUTH : szOID_PKIX_KP_SERVER_AUTH; +- +- // There should only be one chain in our store, so.. we grab that one. +- chainContext = CertFindChainInStore(localCertificateStore.get(), +- X509_ASN_ENCODING, +- 0, +- CERT_CHAIN_FIND_BY_ISSUER, +- &findParam, +- nullptr); +- if (!chainContext) { +- const QString message = isClient +- ? QSslSocket::tr("The certificate provided cannot be used for a client.") +- : QSslSocket::tr("The certificate provided cannot be used for a server."); +- setErrorAndEmit(d, QAbstractSocket::SocketError::SslInvalidUserDataError, message); +- return false; +- } +- Q_ASSERT(chainContext->cChain == 1); +- Q_ASSERT(chainContext->rgpChain[0]); +- Q_ASSERT(chainContext->rgpChain[0]->cbSize >= 1); +- Q_ASSERT(chainContext->rgpChain[0]->rgpElement[0]); +- Q_ASSERT(!localCertContext); +- localCertContext = CertDuplicateCertificateContext(chainContext->rgpChain[0] +- ->rgpElement[0] +- ->pCertContext); + certsCount = 1; +- Q_ASSERT(localCertContext); ++ localCertificate = static_cast(configuration.localCertificate().handle()); ++ Q_ASSERT(localCertificate); + } + + const QList ciphers = configuration.ciphers(); +@@ -1172,7 +1142,7 @@ bool TlsCryptographSchannel::acquireCredentialsHandle() + SCH_CREDENTIALS_VERSION, + 0, + certsCount, +- &localCertContext, ++ &localCertificate, + nullptr, + 0, + nullptr, +@@ -1729,9 +1699,6 @@ void TlsCryptographSchannel::reset() + connectionInfo = {}; + streamSizes = {}; + +- CertFreeCertificateContext(localCertContext); +- localCertContext = nullptr; +- + contextAttributes = 0; + intermediateBuffer.clear(); + schannelState = SchannelState::InitializeHandshake; +@@ -2241,6 +2208,70 @@ bool TlsCryptographSchannel::checkSslErrors() + return true; + } + ++static void attachPrivateKeyToCertificate(const QSslCertificate &certificate, ++ const QSslKey &privateKey) ++{ ++ QAsn1Element elem = _q_PKCS12_key(privateKey); ++ QByteArray buffer; ++ QDataStream stream(&buffer, QDataStream::WriteOnly); ++ elem.write(stream); ++ NCRYPT_PROV_HANDLE provider = 0; ++ SECURITY_STATUS status = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0); ++ if (status != SEC_E_OK) { ++ qCWarning(lcTlsBackendSchannel()) ++ << "Failed to open ncrypt storage provider:" << schannelErrorToString(status); ++ return; ++ } ++ const auto freeProvider = qScopeGuard([provider]() { NCryptFreeObject(provider); }); ++ ++ const QString certName = certificate.subjectInfo(QSslCertificate::CommonName).front(); ++ QSpan nameSpan(certName); ++ NCryptBuffer nbuffer{ ULONG(nameSpan.size_bytes() + sizeof(char16_t)), ++ NCRYPTBUFFER_PKCS_KEY_NAME, ++ const_reinterpret_cast(nameSpan.data()) }; ++ NCryptBufferDesc bufferDesc{ NCRYPTBUFFER_VERSION, 1, &nbuffer }; ++ NCRYPT_KEY_HANDLE ncryptKey = 0; ++ status = NCryptImportKey(provider, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, &bufferDesc, &ncryptKey, ++ PBYTE(buffer.data()), buffer.size(), 0); ++ if (status != SEC_E_OK) { ++ qCWarning(lcTlsBackendSchannel()) ++ << "Failed to import private key:" << schannelErrorToString(status); ++ return; ++ } ++ const auto freeKey = qScopeGuard([ncryptKey]() { NCryptFreeObject(ncryptKey); }); ++ ++ CERT_CONTEXT *context = PCERT_CONTEXT(certificate.handle()); ++ Q_ASSERT(context); ++ ++ CRYPT_DATA_BLOB keyBlob = { sizeof(ncryptKey), PBYTE(&ncryptKey) }; ++ BOOL ok = ++ CertSetCertificateContextProperty(context, CERT_NCRYPT_KEY_HANDLE_PROP_ID, 0, &keyBlob); ++ if (!ok) { ++ auto error = GetLastError(); ++ if (lcTlsBackendSchannel().isWarningEnabled()) ++ qErrnoWarning(int(error), "Failed to set ncrypt handle property."); ++ return; ++ } ++ ++ CRYPT_KEY_PROV_INFO provInfo{ ++ const_reinterpret_cast(certName.constData()), ++ const_cast(MS_KEY_STORAGE_PROVIDER), ++ 0, ++ CERT_SET_KEY_PROV_HANDLE_PROP_ID | CERT_SET_KEY_CONTEXT_PROP_ID, ++ 0, ++ nullptr, ++ 0, ++ }; ++ ok = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID, ++ CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, &provInfo); ++ if (!ok) { ++ auto error = GetLastError(); ++ if (lcTlsBackendSchannel().isWarningEnabled()) ++ qErrnoWarning(int(error), "Failed to set key provider info property."); ++ return; ++ } ++} ++ + void TlsCryptographSchannel::initializeCertificateStores() + { + //// helper function which turns a chain into a certificate store +@@ -2257,7 +2288,10 @@ void TlsCryptographSchannel::initializeCertificateStores() + CRYPT_DATA_BLOB pfxBlob; + pfxBlob.cbData = DWORD(pkcs12.length()); + pfxBlob.pbData = reinterpret_cast(pkcs12.data()); +- return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0)); ++ // ALWAYS_CNG to import using "Cryptography API: Next Generation (CNG)" ++ // NO_PERSIST_KEY to request not persisting anything imported to disk ++ constexpr DWORD flags = PKCS12_ALWAYS_CNG_KSP | PKCS12_NO_PERSIST_KEY; ++ return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, flags)); + }; + + if (!configuration.localCertificateChain().isEmpty()) { +@@ -2267,10 +2301,34 @@ void TlsCryptographSchannel::initializeCertificateStores() + return; + } + if (localCertificateStore == nullptr) { +- localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(), +- configuration.privateKey()); +- if (localCertificateStore == nullptr) ++ localCertificateStore = ++ createStoreFromCertificateChain(configuration.localCertificateChain(), {}); ++ if (localCertificateStore) { ++ const CERT_CONTEXT *certificateContext = CertFindCertificateInStore( ++ localCertificateStore.get(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, ++ CERT_FIND_ANY, nullptr, nullptr); ++ if (certificateContext) { ++ auto *backend = QTlsBackend::backend( ++ configuration.localCertificate()); ++ backend->certificateContext.reset( ++ CertDuplicateCertificateContext(certificateContext)); ++ ++ DWORD keySpec = 0; ++ BOOL mustFree = FALSE; ++ NCRYPT_KEY_HANDLE testKey = 0; ++ BOOL ok = CryptAcquireCertificatePrivateKey( ++ certificateContext, CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, nullptr, ++ &testKey, &keySpec, &mustFree); ++ if (mustFree) ++ NCryptFreeObject(testKey); ++ if (!ok) { ++ attachPrivateKeyToCertificate(configuration.localCertificate(), ++ configuration.privateKey()); ++ } ++ } ++ } else { + qCWarning(lcTlsBackendSchannel, "Failed to load certificate chain!"); ++ } + } + } + +diff --git a/src/plugins/tls/schannel/qtls_schannel_p.h b/src/plugins/tls/schannel/qtls_schannel_p.h +index fab877724920..9bb225b06d10 100644 +--- a/src/plugins/tls/schannel/qtls_schannel_p.h ++++ b/src/plugins/tls/schannel/qtls_schannel_p.h +@@ -106,8 +106,6 @@ private: + QHCertStorePointer peerCertificateStore = nullptr; + QHCertStorePointer caCertificateStore = nullptr; + +- const CERT_CONTEXT *localCertContext = nullptr; +- + ULONG contextAttributes = 0; + qint64 missingData = 0; + +diff --git a/src/plugins/tls/schannel/qx509_schannel_p.h b/src/plugins/tls/schannel/qx509_schannel_p.h +index caf2a914f65d..4f856ba019d6 100644 +--- a/src/plugins/tls/schannel/qx509_schannel_p.h ++++ b/src/plugins/tls/schannel/qx509_schannel_p.h +@@ -40,7 +40,7 @@ public: + static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert, + QList *caCertificates, + const QByteArray &passPhrase); +-private: ++ + const CERT_CONTEXT *certificateContext = nullptr; + + Q_DISABLE_COPY_MOVE(X509CertificateSchannel); +diff --git a/src/plugins/tls/shared/qsslsocket_qt.cpp b/src/plugins/tls/shared/qsslsocket_qt.cpp +index f55b3e3ded7a..7e108dceca45 100644 +--- a/src/plugins/tls/shared/qsslsocket_qt.cpp ++++ b/src/plugins/tls/shared/qsslsocket_qt.cpp +@@ -134,7 +134,7 @@ static QByteArray _q_PKCS12_certBag(const QSslCertificate &cert) + return ba; + } + +-static QAsn1Element _q_PKCS12_key(const QSslKey &key) ++QAsn1Element _q_PKCS12_key(const QSslKey &key) + { + Q_ASSERT(key.algorithm() == QSsl::Rsa || key.algorithm() == QSsl::Dsa); + diff --git a/qt6-qtbase.spec b/qt6-qtbase.spec index d680d98bcc10315d057c5e12be1a310808270170..918a5f51aad97d7858f3588a2eaf827ceb0e4dc8 100644 --- a/qt6-qtbase.spec +++ b/qt6-qtbase.spec @@ -2,7 +2,7 @@ %global multilib_archs x86_64 %{ix86} %{?mips} ppc64 ppc s390x s390 sparc64 sparcv9 riscv64 loongarch64 %global multilib_basearchs x86_64 %{?mips64} ppc64 s390x sparc64 riscv64 loongarch64 -%bcond_without doc +%bcond_with doc %ifarch s390x ppc64le aarch64 armv7hl riscv64 loongarch64 %global no_sse2 1 @@ -22,8 +22,8 @@ Name: qt6-qtbase Summary: Qt6 - QtBase components -Version: 6.8.2 -Release: 4 +Version: 6.8.3 +Release: 1 License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0 Url: https://www.qt.io @@ -78,6 +78,8 @@ Patch100: fix-riscv-configure-tests.patch Patch103: qt6-qtbase-add-sw64-support.patch Patch6001: CVE-2025-3512-qtbase-6.8.diff +Patch6002: CVE-2025-5455-qtbase-6.8.patch +Patch6003: CVE-2025-6338-qtbase-6.8.patch # Do not check any files in %%{_qt6_plugindir}/platformthemes/ for requires. # Those themes are there for platform integration. If the required libraries are @@ -149,7 +151,7 @@ BuildRequires: pkgconfig(zlib) BuildRequires: perl BuildRequires: perl-generators BuildRequires: python3 -BuildRequires: qt6-rpm-macros >= %{version} +BuildRequires: qt6-rpm-macros >= %{majmin} %if 0%{?tests} BuildRequires: dbus-x11 @@ -192,7 +194,7 @@ Requires: pkgconfig(gl) %if 0%{?vulkan} Requires: pkgconfig(vulkan) %endif -Requires: qt6-rpm-macros >= %{version} +Requires: qt6-rpm-macros >= %{majmin} %if 0%{?use_clang} Requires: clang >= 3.7.0 %endif @@ -724,10 +726,15 @@ make check -k ||: %dir %{_qt6_libdir}/cmake/Qt6EglFSDeviceIntegrationPrivate %dir %{_qt6_libdir}/cmake/Qt6EglFsKmsGbmSupportPrivate %dir %{_qt6_libdir}/cmake/Qt6EglFsKmsSupportPrivate +%dir %{_qt6_libdir}/cmake/Qt6TestInternalsPrivate +%dir %{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/3rdparty +%dir %{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/3rdparty/cmake %dir %{_qt6_libdir}/cmake/Qt6XcbQpaPrivate %{_qt6_libdir}/cmake/Qt6EglFSDeviceIntegrationPrivate/*.cmake %{_qt6_libdir}/cmake/Qt6EglFsKmsGbmSupportPrivate/*.cmake %{_qt6_libdir}/cmake/Qt6EglFsKmsSupportPrivate/*.cmake +%{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/*.cmake +%{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/3rdparty/cmake/*.cmake %{_qt6_libdir}/cmake/Qt6XcbQpaPrivate/*.cmake %if 0%{?egl} %{_qt6_libdir}/libQt6EglFsKmsSupport.prl @@ -740,6 +747,7 @@ make check -k ||: %{_qt6_descriptionsdir}/EglFSDeviceIntegrationPrivate.json %{_qt6_descriptionsdir}/EglFsKmsGbmSupportPrivate.json %{_qt6_descriptionsdir}/EglFsKmsSupportPrivate.json +%{_qt6_descriptionsdir}/TestInternalsPrivate.json %{_qt6_descriptionsdir}/XcbQpaPrivate.json %{_qt6_metatypesdir}/qt6eglfsdeviceintegrationprivate_*_metatypes.json %{_qt6_metatypesdir}/qt6eglfskmsgbmsupportprivate_*_metatypes.json @@ -865,6 +873,9 @@ make check -k ||: %{_docdir}/qt6/* %changelog +* Wed Jun 04 2025 Funda Wang - 6.8.3-1 +- update to 6.8.3 + * Thu May 01 2025 Funda Wang - 6.8.2-4 - fix CVE-2025-3512 diff --git a/qtbase-everywhere-src-6.8.2.tar.xz b/qtbase-everywhere-src-6.8.3.tar.xz similarity index 32% rename from qtbase-everywhere-src-6.8.2.tar.xz rename to qtbase-everywhere-src-6.8.3.tar.xz index 5b8ba1c9f3b6b46ace361b1f9bb01a5a7d44c929..c3aa40ab770768fd8cf6e0f0982569faf728eb9d 100644 --- a/qtbase-everywhere-src-6.8.2.tar.xz +++ b/qtbase-everywhere-src-6.8.3.tar.xz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 -size 48264736 +oid sha256:56001b905601bb9023d399f3ba780d7fa940f3e4861e496a7c490331f49e0b80 +size 48426536