diff -Nru quassel-0.10.0/debian/changelog quassel-0.10.0/debian/changelog --- quassel-0.10.0/debian/changelog 2015-05-04 15:08:32.000000000 -0400 +++ quassel-0.10.0/debian/changelog 2018-04-27 20:32:30.000000000 -0400 @@ -1,3 +1,18 @@ +quassel (0.10.0-0ubuntu2.3) trusty-security; urgency=medium + + * SECURITY UPDATE: quasselcore, corruption of heap metadata caused by + qdatastream + - debian/patches/Implement_custom_deserializer.patch: Original patch from + upstream 0.12.5 release, adapted for non-C++ 11 systems by Felix Geyer + - CVE requested by upstream + * SECURITY UPDATE: quasselcore, denial of service for unconfigure core + - debian/patches/Reject_clients_that_attempt_to_login_before_the_core_is + _configured.patch: Original patch from upstream 0.12.5 release, adapted + for non-C++ 11 systems by Felix Geyer + - CVE requested by upstream + + -- Scott Kitterman Fri, 27 Apr 2018 20:25:50 -0400 + quassel (0.10.0-0ubuntu2.2) trusty-security; urgency=medium * SECURITY UPDATE: stack consumption vulnerability in message splitting code diff -Nru quassel-0.10.0/debian/patches/Implement_custom_deserializer.patch quassel-0.10.0/debian/patches/Implement_custom_deserializer.patch --- quassel-0.10.0/debian/patches/Implement_custom_deserializer.patch 1969-12-31 19:00:00.000000000 -0500 +++ quassel-0.10.0/debian/patches/Implement_custom_deserializer.patch 2018-04-27 19:11:10.000000000 -0400 @@ -0,0 +1,892 @@ +Backported from 0.12 branch: + +From 18389a713a6810f57ab237b945e8ee03df857b8b Mon Sep 17 00:00:00 2001 +From: Janne Koschinski +Date: Mon, 2 Apr 2018 22:26:34 +0200 +Subject: [PATCH] Implement custom deserializer to add our own sanity checks + +This is a rough first implementation in preparation of writing +proper serializers independently of QDataStream. + +Thanks to @chaign_c (https://twitter.com/chaign_c/) for finding +issues with QDataStream that prompted this change. + +(cherry picked from commit 2b777e99fc9f74d4ed21491710260664a1721d1f)) +--- + src/common/CMakeLists.txt | 2 + + src/common/protocols/datastream/datastreampeer.cpp | 4 +- + src/common/protocols/legacy/legacypeer.cpp | 19 +- + src/common/serializers/serializers.cpp | 676 +++++++++++++++++++++ + src/common/serializers/serializers.h | 117 ++++ + 5 files changed, 812 insertions(+), 6 deletions(-) + create mode 100644 src/common/serializers/serializers.cpp + create mode 100644 src/common/serializers/serializers.h + +diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt +index bb3aef27a..4ad9d1c55 100644 +--- a/src/common/CMakeLists.txt ++++ b/src/common/CMakeLists.txt +@@ -39,6 +39,8 @@ set(SOURCES + syncableobject.cpp + util.cpp + ++ serializers/serializers.cpp ++ + protocols/datastream/datastreampeer.cpp + protocols/legacy/legacypeer.cpp + ) +diff --git a/src/common/protocols/datastream/datastreampeer.cpp b/src/common/protocols/datastream/datastreampeer.cpp +index cddd06719..c3d9f7f07 100644 +--- a/src/common/protocols/datastream/datastreampeer.cpp ++++ b/src/common/protocols/datastream/datastreampeer.cpp +@@ -25,6 +25,7 @@ + + #include "datastreampeer.h" + #include "quassel.h" ++#include "serializers/serializers.h" + + using namespace Protocol; + +@@ -59,7 +60,8 @@ void DataStreamPeer::processMessage(const QByteArray &msg) + QDataStream stream(msg); + stream.setVersion(QDataStream::Qt_4_2); + QVariantList list; +- stream >> list; ++ if (!Serializers::deserialize(stream, list)) ++ close("Peer sent corrupt data, closing down!"); + if (stream.status() != QDataStream::Ok) { + close("Peer sent corrupt data, closing down!"); + return; +diff --git a/src/common/protocols/legacy/legacypeer.cpp b/src/common/protocols/legacy/legacypeer.cpp +index 2a9764117..2a6a776cf 100644 +--- a/src/common/protocols/legacy/legacypeer.cpp ++++ b/src/common/protocols/legacy/legacypeer.cpp +@@ -23,6 +23,7 @@ + + #include "legacypeer.h" + #include "quassel.h" ++#include "serializers/serializers.h" + + /* version.inc is no longer used for this */ + const uint protocolVersion = 10; +@@ -62,7 +63,10 @@ void LegacyPeer::processMessage(const QByteArray &msg) + QVariant item; + if (_useCompression) { + QByteArray rawItem; +- stream >> rawItem; ++ if (!Serializers::deserialize(stream, rawItem)) { ++ close("Peer sent corrupt data: unable to load QVariant!"); ++ return; ++ } + + int nbytes = rawItem.size(); + if (nbytes <= 4) { +@@ -77,10 +81,15 @@ void LegacyPeer::processMessage(const QByteArray &msg) + + QDataStream itemStream(&rawItem, QIODevice::ReadOnly); + itemStream.setVersion(QDataStream::Qt_4_2); +- itemStream >> item; +- } +- else { +- stream >> item; ++ if (!Serializers::deserialize(itemStream, item)) { ++ close("Peer sent corrupt data: unable to load QVariant!"); ++ return; ++ } ++ } else { ++ if (!Serializers::deserialize(stream, item)) { ++ close("Peer sent corrupt data: unable to load QVariant!"); ++ return; ++ } + } + + if (stream.status() != QDataStream::Ok || !item.isValid()) { +diff --git a/src/common/serializers/serializers.cpp b/src/common/serializers/serializers.cpp +new file mode 100644 +index 000000000..dbba9a8e5 +--- /dev/null ++++ b/src/common/serializers/serializers.cpp +@@ -0,0 +1,658 @@ ++/*************************************************************************** ++ * Copyright (C) 2005-2018 by the Quassel Project * ++ * devel@quassel-irc.org * ++ * * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) version 3. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ++ ***************************************************************************/ ++ ++#include "serializers.h" ++ ++bool checkStreamValid(QDataStream &stream) ++{ ++ if (stream.status() != QDataStream::Ok) { ++ qWarning() << "Peer sent corrupt data"; ++ return false; ++ } ++ ++ return true; ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QVariantList &data) ++{ ++ uint32_t size; ++ if (!deserialize(stream, size)) ++ return false; ++ if (size > 4 * 1024 * 1024) { ++ qWarning() << "Peer sent too large QVariantList: " << size; ++ return false; ++ } ++ for (uint32_t i = 0; i < size; i++) { ++ QVariant element; ++ if (!deserialize(stream, element)) ++ return false; ++ data << element; ++ } ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QVariantMap &data) ++{ ++ uint32_t size; ++ if (!deserialize(stream, size)) ++ return false; ++ if (size > 4 * 1024 * 1024) { ++ qWarning() << "Peer sent too large QVariantMap: " << size; ++ return false; ++ } ++ for (uint32_t i = 0; i < size; i++) { ++ QString key; ++ QVariant value; ++ if (!deserialize(stream, key)) ++ return false; ++ if (!deserialize(stream, value)) ++ return false; ++ data[key] = value; ++ } ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QVariant &data) ++{ ++ quint32 type; ++ int8_t isNull; ++ if (!deserializeVariantType(stream, type)) ++ return false; ++ if (!deserialize(stream, isNull)) ++ return false; ++ if (type == Types::VariantType::UserType) { ++ QByteArray name; ++ if (!deserialize(stream, name)) ++ return false; ++ while (name.length() > 0 && name.at(name.length() - 1) == 0) ++ name.chop(1); ++ if (!deserializeQuasselType(stream, data, Types::fromName(name))) ++ return false; ++ } else { ++ if (!deserializeVariantType(stream, data, type)) ++ return false; ++ } ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserializeVariantType(QDataStream &stream, QVariant &data, quint32 type) ++{ ++ switch (type) { ++ case Types::VariantType::Void: { ++ return true; ++ } ++ case Types::VariantType::Bool: { ++ bool content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::Int: { ++ int32_t content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::UInt: { ++ uint32_t content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QChar: { ++ QChar content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QVariantMap: { ++ QVariantMap content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QVariantList: { ++ QVariantList content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QString: { ++ QString content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QStringList: { ++ QStringList content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QByteArray: { ++ QByteArray content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QDate: { ++ QDate content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QTime: { ++ QTime content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QDateTime: { ++ QDateTime content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::Long: { ++ qlonglong content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::Short: { ++ int16_t content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::Char: { ++ int8_t content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::ULong: { ++ qulonglong content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::UShort: { ++ uint16_t content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::UChar: { ++ uint8_t content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ case Types::VariantType::QVariant: { ++ QVariant content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = QVariant(content); ++ return true; ++ } ++ default: { ++ qWarning() << "Usertype should have been caught earlier already"; ++ return false; ++ } ++ } ++} ++ ++bool Serializers::deserializeQuasselType(QDataStream &stream, QVariant &data, Types::QuasselType::Enum type) ++{ ++ switch (type) { ++ case Types::QuasselType::BufferId: { ++ BufferId content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ case Types::QuasselType::BufferInfo: { ++ BufferInfo content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ case Types::QuasselType::Identity: { ++ Identity content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ case Types::QuasselType::IdentityId: { ++ IdentityId content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ case Types::QuasselType::Message: { ++ Message content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ case Types::QuasselType::MsgId: { ++ MsgId content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ case Types::QuasselType::NetworkId: { ++ NetworkId content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ case Types::QuasselType::NetworkInfo: { ++ NetworkInfo content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ case Types::QuasselType::Network_Server: { ++ Network::Server content; ++ if (!deserialize(stream, content)) ++ return false; ++ data = qVariantFromValue(content); ++ return true; ++ } ++ default: { ++ qWarning() << "Invalid QType"; ++ return false; ++ } ++ } ++} ++ ++bool Serializers::deserializeVariantType(QDataStream &stream, quint32 &data) ++{ ++ uint32_t raw; ++ if (!deserialize(stream, raw)) ++ return false; ++ data = static_cast(raw); ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QStringList &data) ++{ ++ uint32_t size; ++ if (!deserialize(stream, size)) ++ return false; ++ for (uint32_t i = 0; i < size; i++) { ++ QString element; ++ if (!deserialize(stream, element)) ++ return false; ++ data << element; ++ } ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, Network::Server &server) ++{ ++ QVariantMap serverMap; ++ if (!deserialize(stream, serverMap)) ++ return false; ++ server.host = serverMap["Host"].toString(); ++ server.port = serverMap["Port"].toUInt(); ++ server.password = serverMap["Password"].toString(); ++ server.useSsl = serverMap["UseSSL"].toBool(); ++ server.sslVersion = serverMap["sslVersion"].toInt(); ++ server.useProxy = serverMap["UseProxy"].toBool(); ++ server.proxyType = serverMap["ProxyType"].toInt(); ++ server.proxyHost = serverMap["ProxyHost"].toString(); ++ server.proxyPort = serverMap["ProxyPort"].toUInt(); ++ server.proxyUser = serverMap["ProxyUser"].toString(); ++ server.proxyPass = serverMap["ProxyPass"].toString(); ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, Identity &data) ++{ ++ QVariantMap raw; ++ if (!deserialize(stream, raw)) ++ return false; ++ data.fromVariantMap(raw); ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, NetworkInfo &info) ++{ ++ QVariantMap i; ++ if (!deserialize(stream, i)) ++ return false; ++ info.networkId = i["NetworkId"].value(); ++ info.networkName = i["NetworkName"].toString(); ++ info.identity = i["Identity"].value(); ++ info.codecForServer = i["CodecForServer"].toByteArray(); ++ info.codecForEncoding = i["CodecForEncoding"].toByteArray(); ++ info.codecForDecoding = i["CodecForDecoding"].toByteArray(); ++ info.serverList = fromVariantList(i["ServerList"].toList()); ++ info.useRandomServer = i["UseRandomServer"].toBool(); ++ info.perform = i["Perform"].toStringList(); ++ info.useAutoIdentify = i["UseAutoIdentify"].toBool(); ++ info.autoIdentifyService = i["AutoIdentifyService"].toString(); ++ info.autoIdentifyPassword = i["AutoIdentifyPassword"].toString(); ++ info.useSasl = i["UseSasl"].toBool(); ++ info.saslAccount = i["SaslAccount"].toString(); ++ info.saslPassword = i["SaslPassword"].toString(); ++ info.useAutoReconnect = i["UseAutoReconnect"].toBool(); ++ info.autoReconnectInterval = i["AutoReconnectInterval"].toUInt(); ++ info.autoReconnectRetries = i["AutoReconnectRetries"].toInt(); ++ info.unlimitedReconnectRetries = i["UnlimitedReconnectRetries"].toBool(); ++ info.rejoinChannels = i["RejoinChannels"].toBool(); ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QByteArray &data) ++{ ++ data.clear(); ++ uint32_t length; ++ if (!deserialize(stream, length)) ++ return false; ++ // -1 - or 0xffffffff - is used for an empty byte array ++ if (length == 0xffffffff) { ++ return true; ++ } ++ ++ // 64 MB should be enough ++ if (length > 64 * 1024 * 1024) { ++ qWarning() << "Peer sent too large QByteArray: " << length; ++ return false; ++ } ++ ++ const uint32_t Step = 1024 * 1024; ++ uint32_t allocated = 0; ++ do { ++ int blockSize = qMin(Step, length - allocated); ++ data.resize(allocated + blockSize); ++ if (stream.readRawData(data.data() + allocated, blockSize) != blockSize) { ++ data.clear(); ++ qWarning() << "BufferUnderFlow while reading QByteArray"; ++ return false; ++ } ++ allocated += blockSize; ++ } while (allocated < length); ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QString &data) ++{ ++ uint32_t bytes = 0; ++ // read size of string ++ if (!deserialize(stream, bytes)) ++ return false; ++ ++ // empty string ++ if (bytes == 0) { ++ return true; ++ } ++ ++ // null string ++ if (bytes == 0xffffffff) { ++ data.clear(); ++ return true; ++ } ++ ++ // 64 MB should be enough ++ if (bytes > 64 * 1024 * 1024) { ++ qWarning() << "Peer sent too large QString: " << bytes; ++ return false; ++ } ++ ++ if (bytes & 0x1) { ++ data.clear(); ++ qWarning() << "Read corrupted data: UTF-6 String with odd length: " << bytes; ++ return false; ++ } ++ const uint32_t step = 1024 * 1024; ++ uint32_t length = bytes / 2; ++ uint32_t allocated = 0; ++ while (allocated < length) { ++ int blockSize = qMin(step, length - allocated); ++ data.resize(allocated + blockSize); ++ if (stream.readRawData(reinterpret_cast(data.data()) + allocated * 2, blockSize * 2) != blockSize * 2) { ++ data.clear(); ++ qWarning() << "BufferUnderFlow while reading QString"; ++ return false; ++ } ++ allocated += blockSize; ++ } ++ if ((stream.byteOrder() == QDataStream::BigEndian) != (QSysInfo::ByteOrder == QSysInfo::BigEndian)) { ++ uint16_t *rawData = reinterpret_cast(data.data()); ++ while (length--) { ++ *rawData = qbswap(*rawData); ++ ++rawData; ++ } ++ } ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QChar &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QDate &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QTime &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, QDateTime &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, int32_t &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, uint32_t &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, int16_t &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, uint16_t &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, int8_t &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, uint8_t &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, qlonglong &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, qulonglong &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, bool &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, BufferInfo &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, Message &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, NetworkId &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, IdentityId &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, BufferId &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++bool Serializers::deserialize(QDataStream &stream, MsgId &data) ++{ ++ stream >> data; ++ return checkStreamValid(stream); ++} ++ ++quint32 Serializers::Types::variantType(Serializers::Types::QuasselType::Enum type) ++{ ++ switch (type) { ++ case QuasselType::BufferId: ++ return VariantType::UserType; ++ case QuasselType::BufferInfo: ++ return VariantType::UserType; ++ case QuasselType::Identity: ++ return VariantType::UserType; ++ case QuasselType::IdentityId: ++ return VariantType::UserType; ++ case QuasselType::Message: ++ return VariantType::UserType; ++ case QuasselType::MsgId: ++ return VariantType::UserType; ++ case QuasselType::NetworkId: ++ return VariantType::UserType; ++ case QuasselType::NetworkInfo: ++ return VariantType::UserType; ++ case QuasselType::Network_Server: ++ return VariantType::UserType; ++ default: ++ return VariantType::UserType; ++ } ++} ++ ++QString Serializers::Types::toName(Serializers::Types::QuasselType::Enum type) ++{ ++ switch (type) { ++ case QuasselType::BufferId: ++ return QString("BufferId"); ++ case QuasselType::BufferInfo: ++ return QString("BufferInfo"); ++ case QuasselType::Identity: ++ return QString("Identity"); ++ case QuasselType::IdentityId: ++ return QString("IdentityId"); ++ case QuasselType::Message: ++ return QString("Message"); ++ case QuasselType::MsgId: ++ return QString("MsgId"); ++ case QuasselType::NetworkId: ++ return QString("NetworkId"); ++ case QuasselType::NetworkInfo: ++ return QString("NetworkInfo"); ++ case QuasselType::Network_Server: ++ return QString("Network::Server"); ++ default: ++ return QString("Invalid Type"); ++ } ++} ++ ++Serializers::Types::QuasselType::Enum Serializers::Types::fromName(::QByteArray &name) ++{ ++ if (qstrcmp(name, "BufferId") == 0) return QuasselType::BufferId; ++ else if (qstrcmp(name, "BufferInfo") == 0) return QuasselType::BufferInfo; ++ else if (qstrcmp(name, "Identity") == 0) return QuasselType::Identity; ++ else if (qstrcmp(name, "IdentityId") == 0) return QuasselType::IdentityId; ++ else if (qstrcmp(name, "Message") == 0) return QuasselType::Message; ++ else if (qstrcmp(name, "MsgId") == 0) return QuasselType::MsgId; ++ else if (qstrcmp(name, "NetworkId") == 0) return QuasselType::NetworkId; ++ else if (qstrcmp(name, "NetworkInfo") == 0) return QuasselType::NetworkInfo; ++ else if (qstrcmp(name, "Network::Server") == 0) return QuasselType::Network_Server; ++ else { ++ qWarning() << "Type name is not valid: " << name; ++ return QuasselType::Invalid; ++ } ++} +diff --git a/src/common/serializers/serializers.h b/src/common/serializers/serializers.h +new file mode 100644 +index 000000000..7401dad96 +--- /dev/null ++++ b/src/common/serializers/serializers.h +@@ -0,0 +1,119 @@ ++/*************************************************************************** ++ * Copyright (C) 2005-2018 by the Quassel Project * ++ * devel@quassel-irc.org * ++ * * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) version 3. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ++ ***************************************************************************/ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bufferinfo.h" ++#include "identity.h" ++#include "message.h" ++#include "network.h" ++ ++namespace Serializers { ++ namespace Types { ++ namespace VariantType { ++ enum Enum { ++ Void = 0, ++ Bool = 1, ++ Int = 2, ++ UInt = 3, ++ ++ QChar = 7, ++ QVariantMap = 8, ++ QVariantList = 9, ++ QString = 10, ++ QStringList = 11, ++ QByteArray = 12, ++ ++ QDate = 14, ++ QTime = 15, ++ QDateTime = 16, ++ ++ Long = 129, ++ Short = 130, ++ Char = 131, ++ ULong = 132, ++ UShort = 133, ++ UChar = 134, ++ ++ QVariant = 138, ++ ++ UserType = 127 ++ }; ++ } ++ ++ namespace QuasselType { ++ enum Enum { ++ Invalid, ++ BufferId, ++ BufferInfo, ++ Identity, ++ IdentityId, ++ Message, ++ MsgId, ++ NetworkId, ++ NetworkInfo, ++ Network_Server ++ }; ++ } ++ ++ quint32 variantType(QuasselType::Enum type); ++ QString toName(QuasselType::Enum type); ++ Types::QuasselType::Enum fromName(::QByteArray &name); ++ } ++ ++ bool deserialize(QDataStream &stream, QVariant &data); ++ bool deserialize(QDataStream &stream, QVariantList &list); ++ bool deserialize(QDataStream &stream, QVariantMap &data); ++ bool deserializeVariantType(QDataStream &stream, QVariant &data, quint32 type); ++ bool deserializeQuasselType(QDataStream &stream, QVariant &data, Types::QuasselType::Enum type); ++ bool deserialize(QDataStream &stream, bool &data); ++ bool deserialize(QDataStream &stream, int8_t &data); ++ bool deserialize(QDataStream &stream, uint8_t &data); ++ bool deserialize(QDataStream &stream, int16_t &data); ++ bool deserialize(QDataStream &stream, uint16_t &data); ++ bool deserialize(QDataStream &stream, int32_t &data); ++ bool deserialize(QDataStream &stream, uint32_t &data); ++ bool deserialize(QDataStream &stream, qlonglong &data); ++ bool deserialize(QDataStream &stream, qulonglong &data); ++ bool deserializeVariantType(QDataStream &stream, quint32 &data); ++ bool deserialize(QDataStream &stream, QChar &data); ++ bool deserialize(QDataStream &stream, QString &data); ++ bool deserialize(QDataStream &stream, QTime &data); ++ bool deserialize(QDataStream &stream, QDate &data); ++ bool deserialize(QDataStream &stream, QDateTime &data); ++ bool deserialize(QDataStream &stream, QByteArray &data); ++ bool deserialize(QDataStream &stream, QStringList &data); ++ bool deserialize(QDataStream &stream, Message &data); ++ bool deserialize(QDataStream &stream, BufferInfo &data); ++ bool deserialize(QDataStream &stream, BufferId &data); ++ bool deserialize(QDataStream &stream, IdentityId &data); ++ bool deserialize(QDataStream &stream, NetworkId &data); ++ bool deserialize(QDataStream &stream, MsgId &data); ++ bool deserialize(QDataStream &stream, NetworkInfo &data); ++ bool deserialize(QDataStream &stream, Identity &data); ++ bool deserialize(QDataStream &stream, Network::Server &data); ++}; diff -Nru quassel-0.10.0/debian/patches/Reject_clients_that_attempt_to_login_before_the_core_is_configured.patch quassel-0.10.0/debian/patches/Reject_clients_that_attempt_to_login_before_the_core_is_configured.patch --- quassel-0.10.0/debian/patches/Reject_clients_that_attempt_to_login_before_the_core_is_configured.patch 1969-12-31 19:00:00.000000000 -0500 +++ quassel-0.10.0/debian/patches/Reject_clients_that_attempt_to_login_before_the_core_is_configured.patch 2018-04-27 19:12:37.000000000 -0400 @@ -0,0 +1,36 @@ +Backported from 0.12 branch: + +From 08bace4e9ecf08273f094c0c6aa8b3363d38ac3e Mon Sep 17 00:00:00 2001 +From: Michael Marley +Date: Mon, 2 Apr 2018 19:11:31 -0400 +Subject: [PATCH] Reject clients that attempt to login before the core is + configured + +Properly-implemented clients should never try to do this, but if it +is done, this patch prevents it from crashing the core. + +Thanks to @chaign_c (https://twitter.com/chaign_c/) for finding this +issue. + +(cherry picked from commit e17fca767d60c06ca02bc5898ced04f06d3670bd) +--- + src/core/coreauthhandler.cpp | 6 ++++++ + 1 file changed, 6 insertions(+) + +Index: quassel-0.10.0/src/core/coreauthhandler.cpp +=================================================================== +--- quassel-0.10.0.orig/src/core/coreauthhandler.cpp 2018-04-27 19:12:25.862655957 -0400 ++++ quassel-0.10.0/src/core/coreauthhandler.cpp 2018-04-27 19:12:25.854655957 -0400 +@@ -197,6 +197,12 @@ + if (!checkClientRegistered()) + return; + ++ if (!Core::isConfigured()) { ++ qWarning() << qPrintable(tr("Client")) << qPrintable(socket()->peerAddress().toString()) << qPrintable(tr("attempted to login before the core was configured, rejecting.")); ++ _peer->dispatch(ClientDenied(tr("Attempted to login before core was configured!
The core must be configured before attempting to login."))); ++ return; ++ } ++ + UserId uid = Core::validateUser(msg.user, msg.password); + if (uid == 0) { + _peer->dispatch(LoginFailed(tr("Invalid username or password!
The username/password combination you supplied could not be found in the database."))); diff -Nru quassel-0.10.0/debian/patches/series quassel-0.10.0/debian/patches/series --- quassel-0.10.0/debian/patches/series 2015-05-04 15:08:32.000000000 -0400 +++ quassel-0.10.0/debian/patches/series 2018-04-27 19:12:21.000000000 -0400 @@ -3,3 +3,5 @@ CVE-2014-8483.patch CVE-2015-2778.patch CVE-2015-3427.patch +Implement_custom_deserializer.patch +Reject_clients_that_attempt_to_login_before_the_core_is_configured.patch