public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] repo/gentoo:master commit in: dev-qt/qtconnectivity/files/, dev-qt/qtconnectivity/
@ 2025-01-22  9:55 Ionen Wolkens
  0 siblings, 0 replies; only message in thread
From: Ionen Wolkens @ 2025-01-22  9:55 UTC (permalink / raw
  To: gentoo-commits

commit:     90489eceafb66c962bd4f1b48624756590b9a234
Author:     Ionen Wolkens <ionen <AT> gentoo <DOT> org>
AuthorDate: Wed Jan 22 09:51:51 2025 +0000
Commit:     Ionen Wolkens <ionen <AT> gentoo <DOT> org>
CommitDate: Wed Jan 22 09:54:31 2025 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=90489ece

dev-qt/qtconnectivity: fix CVE-2025-23050

Considered waiting for 6.8.2 given release date is "tomorrow",
but odds are it'll be delayed and it'll let us stabilize this
separately either way.

Closes: https://bugs.gentoo.org/948573
Signed-off-by: Ionen Wolkens <ionen <AT> gentoo.org>

 .../qtconnectivity-6.8.1-CVE-2025-23050.patch      | 210 +++++++++++++++++++++
 .../qtconnectivity/qtconnectivity-6.8.1-r1.ebuild  |  89 +++++++++
 2 files changed, 299 insertions(+)

diff --git a/dev-qt/qtconnectivity/files/qtconnectivity-6.8.1-CVE-2025-23050.patch b/dev-qt/qtconnectivity/files/qtconnectivity-6.8.1-CVE-2025-23050.patch
new file mode 100644
index 000000000000..832807a9bb80
--- /dev/null
+++ b/dev-qt/qtconnectivity/files/qtconnectivity-6.8.1-CVE-2025-23050.patch
@@ -0,0 +1,210 @@
+https://bugs.gentoo.org/948573
+https://www.qt.io/blog/security-advisory-qlowenergycontroller-on-linux
+https://codereview.qt-project.org/c/qt/qtconnectivity/+/617004
+From: Ivan Solovev <ivan.solovev@qt.io>
+Date: Thu, 02 Jan 2025 16:48:49 +0100
+Subject: [PATCH] QLowEnergyControllerPrivateBluez: guard against malformed replies
+
+The QLowEnergyControllerPrivateBluez::l2cpReadyRead() slot reads the
+data from a Bluetooth L2CAP socket and then tries to process it
+according to ATT protocol specs.
+
+However, the code was missing length and sanity checks at some
+codepaths in processUnsolicitedReply() and processReply() helper
+methods, simply relying on the data to be in the proper format.
+
+This patch adds some minimal checks to make sure that we do not read
+past the end of the received array and do not divide by zero.
+
+This problem was originally pointed out by Marc Mutz in an unrelated
+patch.
+--- a/src/bluetooth/qlowenergycontroller_bluez.cpp
++++ b/src/bluetooth/qlowenergycontroller_bluez.cpp
+@@ -64,14 +64,15 @@
+ 
+ const int maxPrepareQueueSize = 1024;
+ 
+-static void dumpErrorInformation(const QByteArray &response)
++/* returns false if the format is incorrect */
++static bool dumpErrorInformation(const QByteArray &response)
+ {
+     const char *data = response.constData();
+     if (response.size() != 5
+         || (static_cast<QBluezConst::AttCommand>(data[0])
+             != QBluezConst::AttCommand::ATT_OP_ERROR_RESPONSE)) {
+         qCWarning(QT_BT_BLUEZ) << QLatin1String("Not a valid error response");
+-        return;
++        return false;
+     }
+ 
+     QBluezConst::AttCommand lastCommand = static_cast<QBluezConst::AttCommand>(data[1]);
+@@ -126,6 +127,8 @@
+ 
+     qCDebug(QT_BT_BLUEZ) << "Error:" << errorCode << "Error description:" << errorString
+                          << "last command:" << lastCommand << "handle:" << handle;
++
++    return true;
+ }
+ 
+ static int getUuidSize(const QBluetoothUuid &uuid)
+@@ -903,6 +906,7 @@
+ {
+     Q_ASSERT(charData);
+     Q_ASSERT(data);
++    Q_ASSERT(elementLength >= 5);
+ 
+     QLowEnergyHandle attributeHandle = bt_get_le16(&data[0]);
+     charData->properties =
+@@ -912,7 +916,7 @@
+     // Bluetooth LE data comes as little endian
+     if (elementLength == 7) // 16 bit uuid
+         charData->uuid = QBluetoothUuid(bt_get_le16(&data[5]));
+-    else
++    else if (elementLength == 21) // 128 bit uuid
+         charData->uuid = QUuid::fromBytes(&data[5], QSysInfo::LittleEndian);
+ 
+     qCDebug(QT_BT_BLUEZ) << "Found handle:" << Qt::hex << attributeHandle
+@@ -929,6 +933,7 @@
+ {
+     Q_ASSERT(foundServices);
+     Q_ASSERT(data);
++    Q_ASSERT(elementLength >= 6);
+ 
+     QLowEnergyHandle attributeHandle = bt_get_le16(&data[0]);
+ 
+@@ -938,9 +943,14 @@
+     // data[2] -> included service start handle
+     // data[4] -> included service end handle
+ 
++    // TODO: Spec v. 5.3, Vol. 3, Part G, 4.5.1 mentions that only
++    // 16-bit UUID can be returned here. If the UUID is 128-bit,
++    // then it is omitted from the response, and should be requested
++    // separately with the ATT_READ_REQ command.
++
+     if (elementLength == 8) //16 bit uuid
+         foundServices->append(QBluetoothUuid(bt_get_le16(&data[6])));
+-    else
++    else if (elementLength == 22) // 128 bit uuid
+         foundServices->append(QUuid::fromBytes(&data[6], QSysInfo::LittleEndian));
+ 
+     qCDebug(QT_BT_BLUEZ) << "Found included service: " << Qt::hex
+@@ -949,17 +959,29 @@
+     return attributeHandle;
+ }
+ 
++Q_DECL_COLD_FUNCTION
++static void reportMalformedData(QBluezConst::AttCommand cmd, const QByteArray &response)
++{
++    qCDebug(QT_BT_BLUEZ, "%s malformed data: %s", qt_getEnumName(cmd),
++            response.toHex().constData());
++}
++
+ void QLowEnergyControllerPrivateBluez::processReply(
+         const Request &request, const QByteArray &response)
+ {
+     Q_Q(QLowEnergyController);
+ 
++    // We already have an isEmpty() check at the only calling site that reads
++    // incoming data, so Q_ASSERT is enough.
++    Q_ASSERT(!response.isEmpty());
++
+     QBluezConst::AttCommand command = static_cast<QBluezConst::AttCommand>(response.constData()[0]);
+ 
+     bool isErrorResponse = false;
+     // if error occurred 2. byte is previous request type
+     if (command == QBluezConst::AttCommand::ATT_OP_ERROR_RESPONSE) {
+-        dumpErrorInformation(response);
++        if (!dumpErrorInformation(response))
++            return;
+         command = static_cast<QBluezConst::AttCommand>(response.constData()[1]);
+         isErrorResponse = true;
+     }
+@@ -972,6 +994,10 @@
+         if (isErrorResponse) {
+             mtuSize = ATT_DEFAULT_LE_MTU;
+         } else {
++            if (response.size() < 3) {
++                reportMalformedData(command, response);
++                break;
++            }
+             const char *data = response.constData();
+             quint16 mtu = bt_get_le16(&data[1]);
+             mtuSize = mtu;
+@@ -1000,8 +1026,15 @@
+             break;
+         }
+ 
++        // response[1] == elementLength. According to the spec it should be
++        // at least 4 bytes. See Spec v5.3, Vol 3, Part F, 3.4.4.10
++        if (response.size() < 2 || response[1] < 4) {
++            reportMalformedData(command, response);
++            break;
++        }
++
+         QLowEnergyHandle start = 0, end = 0;
+-        const quint16 elementLength = response.constData()[1];
++        const quint16 elementLength = response.constData()[1]; // value checked above
+         const quint16 numElements = (response.size() - 2) / elementLength;
+         quint16 offset = 2;
+         const char *data = response.constData();
+@@ -1077,16 +1110,25 @@
+         }
+ 
+         /* packet format:
+-         * if GATT_CHARACTERISTIC discovery
++         * if GATT_CHARACTERISTIC discovery (Spec 5.3, Vol. 3, Part G, 4.6)
+          *      <opcode><elementLength>
+          *          [<handle><property><charHandle><uuid>]+
++         * The minimum elementLength is 7 bytes (uuid is always included)
+          *
+-         * if GATT_INCLUDE discovery
++         * if GATT_INCLUDE discovery (Spec 5.3, Vol. 3, Part G, 4.5.1)
+          *      <opcode><elementLength>
+          *          [<handle><startHandle_included><endHandle_included><uuid>]+
++         *  The minimum elementLength is 6 bytes (uuid can be omitted).
+          *
+          *  The uuid can be 16 or 128 bit.
+          */
++
++        const quint8 minimumElementLength = attributeType == GATT_CHARACTERISTIC ? 7 : 6;
++        if (response.size() < 2 || response[1] < minimumElementLength) {
++            reportMalformedData(command, response);
++            break;
++        }
++
+         QLowEnergyHandle lastHandle;
+         const quint16 elementLength = response.constData()[1];
+         const quint16 numElements = (response.size() - 2) / elementLength;
+@@ -1283,6 +1325,12 @@
+             break;
+         }
+ 
++        // Spec 5.3, Vol. 3, Part F, 3.4.3.2
++        if (response.size() < 6) {
++            reportMalformedData(command, response);
++            break;
++        }
++
+         const quint8 format = response[1];
+         quint16 elementLength;
+         switch (format) {
+@@ -1720,9 +1768,18 @@
+ 
+ void QLowEnergyControllerPrivateBluez::processUnsolicitedReply(const QByteArray &payload)
+ {
++    Q_ASSERT(!payload.isEmpty());
++
+     const char *data = payload.constData();
+-    bool isNotification = (static_cast<QBluezConst::AttCommand>(data[0])
++    const auto command = static_cast<QBluezConst::AttCommand>(data[0]);
++    bool isNotification = (command
+                            == QBluezConst::AttCommand::ATT_OP_HANDLE_VAL_NOTIFICATION);
++
++    if (payload.size() < 3) {
++        reportMalformedData(command, payload);
++        return;
++    }
++
+     const QLowEnergyHandle changedHandle = bt_get_le16(&data[1]);
+ 
+     if (QT_BT_BLUEZ().isDebugEnabled()) {

diff --git a/dev-qt/qtconnectivity/qtconnectivity-6.8.1-r1.ebuild b/dev-qt/qtconnectivity/qtconnectivity-6.8.1-r1.ebuild
new file mode 100644
index 000000000000..c0d52a25dace
--- /dev/null
+++ b/dev-qt/qtconnectivity/qtconnectivity-6.8.1-r1.ebuild
@@ -0,0 +1,89 @@
+# Copyright 2023-2025 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit qt6-build
+
+DESCRIPTION="Bluetooth and NFC support library for the Qt6 framework"
+
+if [[ ${QT6_BUILD_TYPE} == release ]]; then
+	KEYWORDS="~amd64 ~arm ~arm64 ~loong ~ppc ~ppc64 ~riscv ~x86"
+fi
+
+IUSE="+bluetooth neard nfc smartcard"
+REQUIRED_USE="
+	|| ( bluetooth nfc )
+	nfc? ( ?? ( neard smartcard ) )
+"
+
+DEPEND="
+	~dev-qt/qtbase-${PV}:6[network]
+	bluetooth? (
+		~dev-qt/qtbase-${PV}:6[dbus]
+		net-wireless/bluez:=
+	)
+	nfc? (
+		neard? ( ~dev-qt/qtbase-${PV}:6[dbus] )
+		smartcard? ( sys-apps/pcsc-lite )
+	)
+"
+RDEPEND="
+	${DEPEND}
+	nfc? (
+		neard? ( net-wireless/neard )
+	)
+"
+
+PATCHES=(
+	"${FILESDIR}"/${P}-CVE-2025-23050.patch
+)
+
+CMAKE_SKIP_TESTS=(
+	# most hardware tests are auto-skipped, but some still misbehave
+	# if bluez/hardware is available (generally tests here may not be
+	# very relevant without hardware, lists may need to be extended)
+	tst_qbluetoothdevicediscoveryagent #936485
+	tst_qbluetoothlocaldevice
+	tst_qbluetoothserver
+	tst_qbluetoothservicediscoveryagent
+	tst_qbluetoothserviceinfo
+	tst_qlowenergycontroller
+)
+
+src_prepare() {
+	qt6-build_src_prepare
+
+	use bluetooth ||
+		sed -i '/add_subdirectory(bluetooth)/d' src/CMakeLists.txt || die
+	use nfc ||
+		sed -i '/add_subdirectory(nfc)/d' src/CMakeLists.txt || die
+}
+
+src_configure() {
+	local mycmakeargs=(
+		$(usev nfc "
+			$(qt_feature neard)
+			$(qt_feature smartcard pcsclite)
+		")
+	)
+
+	qt6-build_src_configure
+}
+
+src_install() {
+	qt6-build_src_install
+
+	# broken (unnecessary) symlink due to add_app() being used over add_tool()
+	use !bluetooth || rm -- "${ED}"/usr/bin/sdpscanner6 || die
+
+	if use test; then
+		local delete=( # sigh
+			"${D}${QT6_BINDIR}"/bluetoothtestdevice
+			"${D}${QT6_BINDIR}"/bttestui
+			"${D}${QT6_BINDIR}"/qlecontroller-server
+		)
+		# using -f given not tracking which tests may be skipped or not
+		rm -f -- "${delete[@]}" || die
+	fi
+}


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2025-01-22  9:55 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-22  9:55 [gentoo-commits] repo/gentoo:master commit in: dev-qt/qtconnectivity/files/, dev-qt/qtconnectivity/ Ionen Wolkens

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox