From 6693fc760107ef242118e95e20498b3560492e1f Mon Sep 17 00:00:00 2001 From: Carsten Grimm <97085459+carsten-grimm-at-ipolog@users.noreply.github.com> Date: Wed, 24 Jul 2024 07:24:42 +0200 Subject: [PATCH] [qt5-base] add patch for CVE-2024-39936 (#40026) --- .../patches/CVE-2024-39936-qtbase-5.15.patch | 136 ++++++++++++++++++ ports/qt5-base/portfile.cmake | 1 + ports/qt5-base/vcpkg.json | 2 +- versions/baseline.json | 2 +- versions/q-/qt5-base.json | 5 + 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 ports/qt5-base/patches/CVE-2024-39936-qtbase-5.15.patch diff --git a/ports/qt5-base/patches/CVE-2024-39936-qtbase-5.15.patch b/ports/qt5-base/patches/CVE-2024-39936-qtbase-5.15.patch new file mode 100644 index 0000000000..94840f6c7b --- /dev/null +++ b/ports/qt5-base/patches/CVE-2024-39936-qtbase-5.15.patch @@ -0,0 +1,136 @@ +diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp +index d1b5dfda2e2..ee04a1856c6 100644 +--- a/src/network/access/qhttp2protocolhandler.cpp ++++ b/src/network/access/qhttp2protocolhandler.cpp +@@ -375,12 +375,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 bd2f32e3528..6f3bd807a09 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,7 +1300,18 @@ 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(); ++ ++ // We don't send or handle any received data until any effects from ++ // emitting encrypted() have been processed. This is necessary ++ // because the user may have called abort(). We may also abort the ++ // whole connection if the request has been aborted and there is ++ // no more requests to send. ++ QMetaObject::invokeMethod(this, ++ &QHttpNetworkConnectionChannel::checkAndResumeCommunication, ++ Qt::QueuedConnection); ++ + // 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); +@@ -1307,6 +1329,26 @@ void QHttpNetworkConnectionChannel::_q_encrypted() + } + } + ++void QHttpNetworkConnectionChannel::checkAndResumeCommunication() ++{ ++ Q_ASSERT(connection->connectionType() > QHttpNetworkConnection::ConnectionTypeHTTP); ++ ++ // 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::requeueSpdyRequests() + { + QList spdyPairs = spdyRequestsToSend.values(); +diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h +index 6be0c51f9fe..613fda7bc31 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/ports/qt5-base/portfile.cmake b/ports/qt5-base/portfile.cmake index 2efc66bfef..5a874c9c51 100644 --- a/ports/qt5-base/portfile.cmake +++ b/ports/qt5-base/portfile.cmake @@ -55,6 +55,7 @@ qt_download_submodule( OUT_SOURCE_PATH SOURCE_PATH patches/0001-CVE-2023-51714-qtbase-5.15.diff patches/0002-CVE-2023-51714-qtbase-5.15.diff patches/CVE-2024-25580-qtbase-5.15.diff + patches/CVE-2024-39936-qtbase-5.15.patch patches/winmain_pro.patch #Moves qtmain to manual-link patches/windows_prf.patch #fixes the qtmain dependency due to the above move diff --git a/ports/qt5-base/vcpkg.json b/ports/qt5-base/vcpkg.json index a57061b7a0..b0347fa06e 100644 --- a/ports/qt5-base/vcpkg.json +++ b/ports/qt5-base/vcpkg.json @@ -1,7 +1,7 @@ { "name": "qt5-base", "version": "5.15.14", - "port-version": 1, + "port-version": 2, "description": "Qt Base provides the basic non-GUI functionality required by all Qt applications.", "homepage": "https://www.qt.io/", "license": null, diff --git a/versions/baseline.json b/versions/baseline.json index dca11a4cf0..f4b63192c0 100644 --- a/versions/baseline.json +++ b/versions/baseline.json @@ -7238,7 +7238,7 @@ }, "qt5-base": { "baseline": "5.15.14", - "port-version": 1 + "port-version": 2 }, "qt5-canvas3d": { "baseline": "0", diff --git a/versions/q-/qt5-base.json b/versions/q-/qt5-base.json index 202641cb46..6765d5a7fd 100644 --- a/versions/q-/qt5-base.json +++ b/versions/q-/qt5-base.json @@ -1,5 +1,10 @@ { "versions": [ + { + "git-tree": "70b9f2253a8552920bde3808c812936bcf4d66cd", + "version": "5.15.14", + "port-version": 2 + }, { "git-tree": "317554d7e9c175899b3595ef4eb6d54839348e38", "version": "5.15.14",