[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#972204: kdeconnect: CVE-2020-26164



Package: kdeconnect
Version: 1.3.3-2
Severity: grave
Tags: security, patch

Dear maintainers,

on the oss-security mailing list[1], severe bugs in kdeconnect were
published with links to commits that fix them. Find attached backports of
those patches fitting the version of kdeconnect in debian/stable (buster).

Please have a careful look at CVE-2020-26164_g_ssl_validation_checks.patch
and check, whether those two disconnect() calls should really be disabled;
while testing the patches I could not find any adverse effects.

best regards,
    Adi Kriegisch

[1] https://www.openwall.com/lists/oss-security/2020/10/13/4
From b279c52101d3f7cc30a26086d58de0b5f1c547fa Mon Sep 17 00:00:00 2001
From: Albert Vaca Cintora <albertvaka@gmail.com>
Date: Thu, 24 Sep 2020 17:01:03 +0200
Subject: [PATCH] Do not leak the local user in the device name.

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/kdeconnectconfig.cpp | 8 +-------
 1 file changed, 1 insertion(+), 1 deletions(-)

--- a/core/kdeconnectconfig.cpp	2020-10-14 08:57:39.290290968 +0200
+++ b/core/kdeconnectconfig.cpp	2020-10-14 08:57:57.650342491 +0200
@@ -148,7 +148,7 @@
 
 QString KdeConnectConfig::name()
 {
-    QString defaultName = qgetenv("USER") + '@' + QHostInfo::localHostName();
+    QString defaultName = QHostInfo::localHostName();
     QString name = d->m_config->value(QStringLiteral("name"), defaultName).toString();
     return name;
 }
From d35b88c1b25fe13715f9170f18674d476ca9acdc Mon Sep 17 00:00:00 2001
From: Matthias Gerstner <mgerstner@suse.de>
Date: Thu, 24 Sep 2020 17:03:06 +0200
Subject: [PATCH] Fix use after free in LanLinkProvider::connectError()

If QSslSocket::connectToHost() hasn't finished running.

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/lanlinkprovider.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/lanlinkprovider.cpp
+++ kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
@@ -224,7 +224,7 @@ void LanLinkProvider::connectError()
     //The socket we created didn't work, and we didn't manage
     //to create a LanDeviceLink from it, deleting everything.
     delete m_receivedIdentityPackets.take(socket).np;
-    delete socket;
+    socket->deleteLater();
 }
 
 //We received a UDP packet and answered by connecting to them by TCP. This gets called on a succesful connection.
From 721ba9faafb79aac73973410ee1dd3624ded97a5 Mon Sep 17 00:00:00 2001
From: Aleix Pol <aleixpol@kde.org>
Date: Wed, 16 Sep 2020 02:27:13 +0200
Subject: [PATCH] Don't brute-force reading the socket

The package will arrive eventually, and dataReceived will be emitted.
Otherwise we just end up calling dataReceived to no end.

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/socketlinereader.cpp |  8 -------
 tests/testsocketlinereader.cpp         | 31 ++++++++++++++++++++++++--
 2 files changed, 29 insertions(+), 10 deletions(-)

Index: kdeconnect-1.3.3/core/backends/lan/socketlinereader.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/socketlinereader.cpp
+++ kdeconnect-1.3.3/core/backends/lan/socketlinereader.cpp
@@ -38,14 +38,6 @@ void SocketLineReader::dataReceived()
         }
     }
 
-    //If we still have things to read from the socket, call dataReceived again
-    //We do this manually because we do not trust readyRead to be emitted again
-    //So we call this method again just in case.
-    if (m_socket->bytesAvailable() > 0) {
-        QMetaObject::invokeMethod(this, "dataReceived", Qt::QueuedConnection);
-        return;
-    }
-
     //If we have any packets, tell it to the world.
     if (!m_packets.isEmpty()) {
         Q_EMIT readyRead();
Index: kdeconnect-1.3.3/tests/testsocketlinereader.cpp
===================================================================
--- kdeconnect-1.3.3.orig/tests/testsocketlinereader.cpp
+++ kdeconnect-1.3.3/tests/testsocketlinereader.cpp
@@ -24,16 +24,19 @@
 #include <QProcess>
 #include <QEventLoop>
 #include <QTimer>
+#include <QSignalSpy>
 
 class TestSocketLineReader : public QObject
 {
     Q_OBJECT
 public Q_SLOTS:
-    void initTestCase();
+    void init();
+    void cleanup() { delete m_server; }
     void newPacket();
 
 private Q_SLOTS:
     void socketLineReader();
+    void badData();
 
 private:
     QTimer m_timer;
@@ -44,8 +47,9 @@ private:
     SocketLineReader* m_reader;
 };
 
-void TestSocketLineReader::initTestCase()
+void TestSocketLineReader::init()
 {
+    m_packets.clear();
     m_server = new Server(this);
 
     QVERIFY2(m_server->listen(QHostAddress::LocalHost, 8694), "Failed to create local tcp server");
@@ -96,6 +100,29 @@ void TestSocketLineReader::socketLineRea
     }
 }
 
+void TestSocketLineReader::badData()
+{
+    const QList<QByteArray> dataToSend = { "data1\n", "data" }; //does not end in a \n
+    for (const QByteArray& line : qAsConst(dataToSend)) {
+        m_conn->write(line);
+    }
+    m_conn->flush();
+
+    QSignalSpy spy(m_server, &QTcpServer::newConnection);
+    QVERIFY(m_server->hasPendingConnections() || spy.wait(1000));
+    QSslSocket* sock = m_server->nextPendingConnection();
+
+    QVERIFY2(sock != nullptr, "Could not open a connection to the client");
+
+    m_reader = new SocketLineReader(sock, this);
+    connect(m_reader, &SocketLineReader::readyRead, this, &TestSocketLineReader::newPacket);
+    m_timer.start();
+    m_loop.exec();
+
+    QCOMPARE(m_packets.count(), 1);
+    QCOMPARE(m_packets[0], dataToSend[0]);
+}
+
 void TestSocketLineReader::newPacket()
 {
     if (!m_reader->bytesAvailable()) {
From b496e66899e5bc9547b6537a7f44ab44dd0aaf38 Mon Sep 17 00:00:00 2001
From: Aleix Pol <aleixpol@kde.org>
Date: Wed, 16 Sep 2020 02:28:58 +0200
Subject: [PATCH] Limit identity packets to 8KiB

Healthy identity packages shouldn't be that big and we don't want to
allow systems around us to send us ever humongous packages that will
just leave us without any memory.

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/lanlinkprovider.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/core/backends/lan/lanlinkprovider.cpp b/core/backends/lan/lanlinkprovider.cpp
index 235c221f..1fd3870e 100644
--- a/core/backends/lan/lanlinkprovider.cpp
+++ b/core/backends/lan/lanlinkprovider.cpp
@@ -351,6 +351,14 @@
 {
     QSslSocket* socket = qobject_cast<QSslSocket*>(sender());
 
+    //the size here is arbitrary and is now at 8192 bytes. It needs to be considerably long as it includes the capabilities but there needs to be a limit
+    //Tested between my systems and I get around 2000 per identity package.
+    if (socket->bytesAvailable() > 8192) {
+        qCWarning(KDECONNECT_CORE) << "LanLinkProvider/newConnection: Suspiciously long identity package received. Closing connection." << socket->peerAddress() << socket->bytesAvailable();
+        socket->disconnectFromHost();
+        return;
+    }
+
     const QByteArray data = socket->readLine();
 
     //qCDebug(KDECONNECT_CORE) << "LanLinkProvider received reply:" << data;
From 5310eae85dbdf92fba30375238a2481f2e34943e Mon Sep 17 00:00:00 2001
From: Aleix Pol <aleixpol@kde.org>
Date: Wed, 16 Sep 2020 02:44:38 +0200
Subject: [PATCH] Do not let lanlink connections stay open for long without
 authenticating

If there's no information received, close the socket to try again.

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/lanlinkprovider.cpp | 10 ++++++++++
 1 file changed, 10 insertions(+)

Index: kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/lanlinkprovider.cpp
+++ kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
@@ -345,6 +345,16 @@ void LanLinkProvider::newConnection()
         connect(socket, &QIODevice::readyRead,
                 this, &LanLinkProvider::dataReceived);
 
+        QTimer* timer = new QTimer(socket);
+        timer->setSingleShot(true);
+        timer->setInterval(1000);
+        connect(socket, &QSslSocket::encrypted,
+                timer, &QObject::deleteLater);
+        connect(timer, &QTimer::timeout, socket, [socket] {
+            qCWarning(KDECONNECT_CORE) << "LanLinkProvider/newConnection: Host timed out without sending any identity." << socket->peerAddress();
+            socket->disconnectFromHost();
+        });
+        timer->start();
     }
 }
 
From ae58b9dec49c809b85b5404cee17946116f8a706 Mon Sep 17 00:00:00 2001
From: Albert Vaca Cintora <albertvaka@gmail.com>
Date: Thu, 24 Sep 2020 17:13:34 +0200
Subject: [PATCH] Limit number of connected sockets from unpaired devices

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/lanlinkprovider.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

Index: kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/lanlinkprovider.cpp
+++ kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
@@ -44,6 +44,8 @@
 
 #define MIN_VERSION_WITH_SSL_SUPPORT 6
 
+static const int MAX_UNPAIRED_CONNECTIONS = 42;
+
 LanLinkProvider::LanLinkProvider(bool testMode)
     : m_testMode(testMode)
 {
@@ -505,6 +507,15 @@ void LanLinkProvider::addLink(const QStr
         deviceLink->reset(socket, connectionOrigin);
     } else {
         deviceLink = new LanDeviceLink(deviceId, this, socket, connectionOrigin);
+        // Socket disconnection will now be handled by LanDeviceLink
+        disconnect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater);
+        bool isDeviceTrusted = KdeConnectConfig::instance()->trustedDevices().contains(deviceId);
+        if (!isDeviceTrusted && m_links.size() > MAX_UNPAIRED_CONNECTIONS) {
+            qCWarning(KDECONNECT_CORE) << "Too many unpaired devices to remember them all. Ignoring " << deviceId;
+            socket->disconnectFromHost();
+            socket->deleteLater();
+            return;
+        }
         connect(deviceLink, &QObject::destroyed, this, &LanLinkProvider::deviceLinkDestroyed);
         m_links[deviceId] = deviceLink;
         if (m_pairingHandlers.contains(deviceId)) {
From 66c768aa9e7fba30b119c8b801efd49ed1270b0a Mon Sep 17 00:00:00 2001
From: Albert Vaca Cintora <albertvaka@gmail.com>
Date: Thu, 24 Sep 2020 17:16:02 +0200
Subject: [PATCH] Do not remember more than a few identity packets at a time

To prevent the kdeconnect process from using too much memory.

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/lanlinkprovider.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

Index: kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/lanlinkprovider.cpp
+++ kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
@@ -45,6 +45,7 @@
 #define MIN_VERSION_WITH_SSL_SUPPORT 6
 
 static const int MAX_UNPAIRED_CONNECTIONS = 42;
+static const int MAX_REMEMBERED_IDENTITY_PACKETS = 42;
 
 LanLinkProvider::LanLinkProvider(bool testMode)
     : m_testMode(testMode)
@@ -200,6 +201,12 @@ void LanLinkProvider::newUdpConnection()
 
         //qCDebug(KDECONNECT_CORE) << "Received Udp identity packet from" << sender << " asking for a tcp connection on port " << tcpPort;
 
+        if (m_receivedIdentityPackets.size() > MAX_REMEMBERED_IDENTITY_PACKETS) {
+            qCWarning(KDECONNECT_CORE) << "Too many remembered identities, ignoring" << receivedPacket->get<QString>(QStringLiteral("deviceId")) << "received via UDP";
+            delete receivedPacket;
+            continue;
+        }
+
         QSslSocket* socket = new QSslSocket(this);
         socket->setProxy(QNetworkProxy::NoProxy);
         m_receivedIdentityPackets[socket].np = receivedPacket;
@@ -388,6 +395,12 @@ void LanLinkProvider::dataReceived()
         delete np;
         return;
     }
+
+    if (m_receivedIdentityPackets.size() > MAX_REMEMBERED_IDENTITY_PACKETS) {
+        qCWarning(KDECONNECT_CORE) << "Too many remembered identities, ignoring" << np->get<QString>(QStringLiteral("deviceId")) << "received via TCP";
+        delete np;
+        return;
+    }
 
     // Needed in "encrypted" if ssl is used, similar to "connected"
     m_receivedIdentityPackets[socket].np = np;
From 85b691e40f525e22ca5cc4ebe79c361d71d7dc05 Mon Sep 17 00:00:00 2001
From: Albert Vaca Cintora <albertvaka@gmail.com>
Date: Thu, 24 Sep 2020 17:18:06 +0200
Subject: [PATCH] Limit the ports we try to connect to to the port range of KDE
 Connect

So we can't trigger connections to other services.

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/lanlinkprovider.cpp | 5 +++++
 1 file changed, 5 insertions(+)

Index: kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/lanlinkprovider.cpp
+++ kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
@@ -198,6 +198,11 @@ void LanLinkProvider::newUdpConnection()
         }
 
         int tcpPort = receivedPacket->get<int>(QStringLiteral("tcpPort"));
+        if (tcpPort < MIN_TCP_PORT || tcpPort > MAX_TCP_PORT) {
+            qCDebug(KDECONNECT_CORE) << "TCP port outside of kdeconnect's range";
+            delete receivedPacket;
+            continue;
+        }
 
         //qCDebug(KDECONNECT_CORE) << "Received Udp identity packet from" << sender << " asking for a tcp connection on port " << tcpPort;
 
From 48180b46552d40729a36b7431e97bbe2b5379306 Mon Sep 17 00:00:00 2001
From: Albert Vaca Cintora <albertvaka@gmail.com>
Date: Thu, 24 Sep 2020 18:46:57 +0200
Subject: [PATCH] Do not replace connections for a given deviceId if the certs
 have changed

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/landevicelink.cpp   | 5 +++++
 core/backends/lan/landevicelink.h     | 1 +
 core/backends/lan/lanlinkprovider.cpp | 6 ++++++
 3 files changed, 12 insertions(+)

Index: kdeconnect-1.3.3/core/backends/lan/landevicelink.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/landevicelink.cpp
+++ kdeconnect-1.3.3/core/backends/lan/landevicelink.cpp
@@ -176,3 +176,8 @@ bool LanDeviceLink::linkShouldBeKeptAliv
     //return (mConnectionSource == ConnectionStarted::Remotely || pairStatus() == Paired);
 
 }
+
+QSslCertificate LanDeviceLink::certificate() const
+{
+    return m_socketLineReader->peerCertificate();
+}
Index: kdeconnect-1.3.3/core/backends/lan/landevicelink.h
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/landevicelink.h
+++ kdeconnect-1.3.3/core/backends/lan/landevicelink.h
@@ -55,6 +55,7 @@ public:
     bool linkShouldBeKeptAlive() override;
 
     QHostAddress hostAddress() const;
+    QSslCertificate certificate() const;
 
 private Q_SLOTS:
     void dataReceived();
Index: kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/lanlinkprovider.cpp
+++ kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
@@ -317,6 +317,12 @@ void LanLinkProvider::encrypted()
     NetworkPacket* receivedPacket = m_receivedIdentityPackets[socket].np;
     const QString& deviceId = receivedPacket->get<QString>(QStringLiteral("deviceId"));
 
+    if (m_links.contains(deviceId) && m_links[deviceId]->certificate() != socket->peerCertificate()) {
+        socket->disconnectFromHost();
+        qCWarning(KDECONNECT_CORE) << "Got connection for the same deviceId but certificates don't match. Ignoring " << deviceId;
+        return;
+    }
+
     addLink(deviceId, socket, receivedPacket, connectionOrigin);
 
     // Copied from connected slot, now delete received packet
From f183b5447bad47655c21af87214579f03bf3a163 Mon Sep 17 00:00:00 2001
From: Albert Vaca Cintora <albertvaka@gmail.com>
Date: Thu, 24 Sep 2020 16:59:22 +0200
Subject: [PATCH] Do not ignore SSL errors, except for self-signed cert errors.

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/lanlinkprovider.cpp | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

Index: kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/lanlinkprovider.cpp
+++ kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
@@ -279,9 +279,7 @@ void LanLinkProvider::connected()
 
             connect(socket, &QSslSocket::encrypted, this, &LanLinkProvider::encrypted);
 
-            if (isDeviceTrusted) {
-                connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
-            }
+                        connect(socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), this, &LanLinkProvider::sslErrors);
 
             socket->startServerEncryption();
 
@@ -308,8 +306,9 @@ void LanLinkProvider::encrypted()
 
     QSslSocket* socket = qobject_cast<QSslSocket*>(sender());
     if (!socket) return;
-    disconnect(socket, &QSslSocket::encrypted, this, &LanLinkProvider::encrypted);
-    disconnect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
+    //TODO: do we need to remove both (CVE-2020-26164)?
+    //disconnect(socket, &QSslSocket::encrypted, this, &LanLinkProvider::encrypted);
+    //disconnect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
 
     Q_ASSERT(socket->mode() != QSslSocket::UnencryptedMode);
     LanDeviceLink::ConnectionStarted connectionOrigin = (socket->mode() == QSslSocket::SslClientMode)? LanDeviceLink::Locally : LanDeviceLink::Remotely;
@@ -337,14 +336,20 @@ void LanLinkProvider::sslErrors(const QL
     disconnect(socket, &QSslSocket::encrypted, this, &LanLinkProvider::encrypted);
     disconnect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
 
-    qCDebug(KDECONNECT_CORE) << "Failing due to " << errors;
-    Device* device = Daemon::instance()->getDevice(socket->peerVerifyName());
-    if (device) {
-        device->unpair();
+    bool fatal = false;
+    for (const QSslError& error : errors) {
+        if (error.error() != QSslError::SelfSignedCertificate) {
+            qCCritical(KDECONNECT_CORE) << "Disconnecting due to fatal SSL Error: " << error;
+            fatal = true;
+        } else {
+            qCDebug(KDECONNECT_CORE) << "Ignoring self-signed cert error";
+        }
     }
 
-    delete m_receivedIdentityPackets.take(socket).np;
-    // Socket disconnects itself on ssl error and will be deleted by deleteLater slot, no need to delete manually
+    if (fatal) {
+        socket->disconnectFromHost();
+        delete m_receivedIdentityPackets.take(socket).np;
+    }
 }
 
 //I'm the new device and this is the answer to my UDP identity packet (no data received yet). They are connecting to us through TCP, and they should send an identity.
From 48180b46552d40729a36b7431e97bbe2b5379306 Mon Sep 17 00:00:00 2001
From: Albert Vaca Cintora <albertvaka@gmail.com>
Date: Thu, 24 Sep 2020 18:46:57 +0200
Subject: [PATCH] Do not replace connections for a given deviceId if the certs
 have changed

Thanks Matthias Gerstner <mgerstner@suse.de> for reporting this.
---
 core/backends/lan/lanlinkprovider.cpp | 6 ++++++
 1 files changed, 6 insertions(+)

Index: kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
===================================================================
--- kdeconnect-1.3.3.orig/core/backends/lan/lanlinkprovider.cpp
+++ kdeconnect-1.3.3/core/backends/lan/lanlinkprovider.cpp
@@ -322,6 +322,12 @@ void LanLinkProvider::encrypted()
         return;
     }
 
+    if (m_links.contains(deviceId) && m_links[deviceId]->certificate() != socket->peerCertificate()) {
+        socket->disconnectFromHost();
+        qCWarning(KDECONNECT_CORE) << "Got connection for the same deviceId but certificates don't match. Ignoring " << deviceId;
+        return;
+    }
+
     addLink(deviceId, socket, receivedPacket, connectionOrigin);
 
     // Copied from connected slot, now delete received packet

Attachment: signature.asc
Description: PGP signature


Reply to: