diff --git a/CVE-2024-39936-qtbase-5.15.patch b/CVE-2024-39936-qtbase-5.15.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e546254ac01448d4c58d6bf5bd242919213a696 --- /dev/null +++ b/CVE-2024-39936-qtbase-5.15.patch @@ -0,0 +1,211 @@ +From e2ef083289e8fc0bbf3390795055047090c0fee9 Mon Sep 17 00:00:00 2001 +From: xiaoyunzhao +Date: Mon, 22 Jul 2024 11:44:41 +0800 +Subject: [PATCH] CVE-2024-39936.patch + +--- + src/network/access/qhttp2protocolhandler.cpp | 6 +-- + .../access/qhttpnetworkconnectionchannel.cpp | 42 ++++++++++++++++-- + .../access/qhttpnetworkconnectionchannel_p.h | 6 +++ + tests/auto/network/access/http2/tst_http2.cpp | 44 +++++++++++++++++++ + 4 files changed, 92 insertions(+), 6 deletions(-) + +diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp +index 39dd4608..bc1dac68 100644 +--- a/src/network/access/qhttp2protocolhandler.cpp ++++ b/src/network/access/qhttp2protocolhandler.cpp +@@ -371,12 +371,12 @@ bool QHttp2ProtocolHandler::sendRequest() + } + } + +- if (!prefaceSent && !sendClientPreface()) +- return false; +- + if (!requests.size()) + return true; + ++ if (!prefaceSent && !sendClientPreface()) ++ return false; ++ + m_channel->state = QHttpNetworkConnectionChannel::WritingState; + // Check what was promised/pushed, maybe we do not have to send a request + // and have a response already? +diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp +index 7620ca16..c09091c7 100644 +--- a/src/network/access/qhttpnetworkconnectionchannel.cpp ++++ b/src/network/access/qhttpnetworkconnectionchannel.cpp +@@ -255,6 +255,10 @@ void QHttpNetworkConnectionChannel::abort() + bool QHttpNetworkConnectionChannel::sendRequest() + { + Q_ASSERT(!protocolHandler.isNull()); ++ if (waitingForPotentialAbort) { ++ needInvokeSendRequest = true; ++ return false; // this return value is unused ++ } + return protocolHandler->sendRequest(); + } + +@@ -267,21 +271,28 @@ bool QHttpNetworkConnectionChannel::sendRequest() + void QHttpNetworkConnectionChannel::sendRequestDelayed() + { + QMetaObject::invokeMethod(this, [this] { +- Q_ASSERT(!protocolHandler.isNull()); + if (reply) +- protocolHandler->sendRequest(); ++ sendRequest(); + }, Qt::ConnectionType::QueuedConnection); + } + + void QHttpNetworkConnectionChannel::_q_receiveReply() + { + Q_ASSERT(!protocolHandler.isNull()); ++ if (waitingForPotentialAbort) { ++ needInvokeReceiveReply = true; ++ return; ++ } + protocolHandler->_q_receiveReply(); + } + + void QHttpNetworkConnectionChannel::_q_readyRead() + { + Q_ASSERT(!protocolHandler.isNull()); ++ if (waitingForPotentialAbort) { ++ needInvokeReadyRead = true; ++ return; ++ } + protocolHandler->_q_readyRead(); + } + +@@ -1289,10 +1300,13 @@ void QHttpNetworkConnectionChannel::_q_encrypted() + // Similar to HTTP/1.1 counterpart below: + const auto &pairs = spdyRequestsToSend.values(); // (request, reply) + const auto &pair = pairs.first(); ++ waitingForPotentialAbort = true; + emit pair.second->encrypted(); + // In case our peer has sent us its settings (window size, max concurrent streams etc.) + // let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection). +- QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); ++ QMetaObject::invokeMethod(this, ++ &QHttpNetworkConnectionChannel::checkAndResumeCommunication, ++ Qt::QueuedConnection); + } + } else { // HTTP + if (!reply) +@@ -1316,6 +1330,28 @@ void QHttpNetworkConnectionChannel::requeueSpdyRequests() + spdyRequestsToSend.clear(); + } + ++ ++void QHttpNetworkConnectionChannel::checkAndResumeCommunication() ++{ ++ Q_ASSERT(connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 ++ || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct); ++ ++ // Because HTTP/2 requires that we send a SETTINGS frame as the first thing we do, and respond ++ // to a SETTINGS frame with an ACK, we need to delay any handling until we can ensure that any ++ // effects from emitting encrypted() have been processed. ++ // This function is called after encrypted() was emitted, so check for changes. ++ ++ if (!reply && spdyRequestsToSend.isEmpty()) ++ abort(); ++ waitingForPotentialAbort = false; ++ if (needInvokeReadyRead) ++ _q_readyRead(); ++ if (needInvokeReceiveReply) ++ _q_receiveReply(); ++ if (needInvokeSendRequest) ++ sendRequest(); ++} ++ + void QHttpNetworkConnectionChannel::_q_sslErrors(const QList &errors) + { + if (!socket) +diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h +index d8ac3979..eac44464 100644 +--- a/src/network/access/qhttpnetworkconnectionchannel_p.h ++++ b/src/network/access/qhttpnetworkconnectionchannel_p.h +@@ -107,6 +107,10 @@ public: + QAbstractSocket *socket; + bool ssl; + bool isInitialized; ++ bool waitingForPotentialAbort = false; ++ bool needInvokeReceiveReply = false; ++ bool needInvokeReadyRead = false; ++ bool needInvokeSendRequest = false; + ChannelState state; + QHttpNetworkRequest request; // current request, only used for HTTP + QHttpNetworkReply *reply; // current reply for this request, only used for HTTP +@@ -187,6 +191,8 @@ public: + void closeAndResendCurrentRequest(); + void resendCurrentRequest(); + ++ void checkAndResumeCommunication(); ++ + bool isSocketBusy() const; + bool isSocketWriting() const; + bool isSocketWaiting() const; +diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp +index bf8c7799..4daeece4 100644 +--- a/tests/auto/network/access/http2/tst_http2.cpp ++++ b/tests/auto/network/access/http2/tst_http2.cpp +@@ -118,6 +118,8 @@ private slots: + void redirect_data(); + void redirect(); + ++ void abortOnEncrypted(); ++ + protected slots: + // Slots to listen to our in-process server: + void serverStarted(quint16 port); +@@ -1024,6 +1026,48 @@ void tst_Http2::redirect() + QTRY_VERIFY(serverGotSettingsACK); + } + ++void tst_Http2::abortOnEncrypted() ++{ ++#if !QT_CONFIG(ssl) ++ QSKIP("TLS support is needed for this test"); ++#else ++ clearHTTP2State(); ++ serverPort = 0; ++ ++ ServerPtr targetServer(newServer(defaultServerSettings, H2Type::h2Direct)); ++ ++ QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); ++ runEventLoop(); ++ ++ nRequests = 1; ++ nSentRequests = 0; ++ ++ const auto url = requestUrl(H2Type::h2Direct); ++ QNetworkRequest request(url); ++ request.setAttribute(QNetworkRequest::Http2DirectAttribute, true); ++ ++ std::unique_ptr reply{manager->get(request)}; ++ reply->ignoreSslErrors(); ++ connect(reply.get(), &QNetworkReply::encrypted, reply.get(), [reply = reply.get()](){ ++ reply->abort(); ++ }); ++ connect(reply.get(), &QNetworkReply::errorOccurred, this, &tst_Http2::replyFinishedWithError); ++ ++ runEventLoop(); ++ STOP_ON_FAILURE ++ ++ QCOMPARE(nRequests, 0); ++ QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError); ++ ++ const bool res = QTest::qWaitFor( ++ [this, server = targetServer.get()]() { ++ return serverGotSettingsACK || prefaceOK || nSentRequests > 0; ++ }, ++ 500); ++ QVERIFY(!res); ++#endif // QT_CONFIG(ssl) ++} ++ + void tst_Http2::serverStarted(quint16 port) + { + serverPort = port; +-- +2.45.2.windows.1 + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index 393d0194a05e20542155e2bce2b82086766b9138..7ed5f22a787d09e9a8d915249f36b254c10e01ba 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -27,7 +27,7 @@ Summary: Qt5 - QtBase components Name: qt5-qtbase Version: 5.15.11 -Release: 4%{?dist} +Release: 5%{?dist} License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0 Url: http://qt-project.org/ %global majmin %(echo %{version} | cut -d. -f1-2) @@ -60,6 +60,7 @@ Patch3018: CVE-2024-25580-qtbase-5.15.patch Patch3019: qtbase-use-qgnomeplatform-as-default-platform-theme-on-gnome.patch Patch3020: CVE-2023-51714.diff Patch3021: qtbase-5.15.11-add-loongarch64-support-for-Double-Conversion.patch +Patch3022: CVE-2024-39936-qtbase-5.15.patch %if 0%{?use_clang} BuildRequires: clang >= 3.7.0 @@ -822,6 +823,10 @@ fi %changelog + +* Fri Jul 19 2024 xiaoyunzhao - 5.15.11-5 +- Fix CVE-2024-39939 + * Wed Jun 12 2024 Pengda Dou - 5.15.11-4 - [Type] other - [DESC] add loongarch64 support for Double-Conversion