1
0
mirror of https://github.com/qt/qtmqtt.git synced 2026-10-25 16:16:26 +00:00

Protect topic from overflow

While QString can store longer content, a topic only can hold 2 byte
long names. For publishing, truncate the message topic to allow sending.
In case a subscription uses wildcards, it is still able to receive it.

For subscriptions forbid long topic names and return null.

Change-Id: I914c03210b22a2d521d4d10f4a4f643201183137
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
This commit is contained in:
Maurice Kalinowski 2017-05-04 16:07:49 +02:00
parent 760b868f21
commit 8413dc4ade
2 changed files with 87 additions and 3 deletions

View File

@ -247,7 +247,13 @@ qint32 QMqttConnection::sendControlPublish(const QString &topic, const QByteArra
QSharedPointer<QMqttControlPacket> packet(new QMqttControlPacket(header));
packet->append(topic.toUtf8());
QByteArray topicArray = topic.toUtf8();
if (topicArray.size() > UINT16_MAX) {
qWarning("Published topic is too long. Need to truncate");
topicArray.truncate(UINT16_MAX);
}
packet->append(topicArray);
quint16 identifier = 0;
if (qos > 0) {
// Add Packet Identifier
@ -320,7 +326,14 @@ QSharedPointer<QMqttSubscription> QMqttConnection::sendControlSubscribe(const QS
const quint16 identifier = qrand();
packet.append(identifier);
packet.append(topic.toUtf8());
// Overflow protection
QByteArray topicArray = topic.toUtf8();
if (topicArray.size() > UINT16_MAX) {
qWarning("Subscribed topic is too long.");
return QSharedPointer<QMqttSubscription>();
}
packet.append(topicArray);
switch (qos) {
case 0: packet.append(char(0x0)); break;
@ -330,7 +343,7 @@ QSharedPointer<QMqttSubscription> QMqttConnection::sendControlSubscribe(const QS
}
QSharedPointer<QMqttSubscription> result(new QMqttSubscription);
result->setTopic(topic);
result->setTopic(topicArray);
result->setClient(m_client);
result->setQos(qos);
result->setState(QMqttSubscription::SubscriptionPending);

View File

@ -46,6 +46,9 @@ private Q_SLOTS:
void sendReceive();
void retainMessage();
void willMessage();
void longTopic_data();
void longTopic();
void subscribeLongTopic();
private:
QString m_testBroker;
quint16 m_port{1883};
@ -263,6 +266,74 @@ void Tst_QMqttClient::willMessage()
}
}
void Tst_QMqttClient::longTopic_data()
{
QTest::addColumn<QString>("topic");
QTest::newRow("simple") << QString::fromLatin1("topic");
QTest::newRow("subPath") << QString::fromLatin1("topic/subtopic");
// ### TODO: This test does not work as socket::read() is not able to handle such large buffers.
// For this we need to redo th whole reading part.
// QString l;
// l.fill(QLatin1Char('T'), UINT16_MAX);
// QTest::newRow("maxSize") << l;
// l.fill(QLatin1Char('M'), 2 * UINT16_MAX);
// QTest::newRow("overflow") << l;
}
void Tst_QMqttClient::longTopic()
{
QFETCH(QString, topic);
QString truncTopic = topic;
truncTopic.truncate(UINT16_MAX);
QMqttClient publisher;
publisher.setClientId(QLatin1String("publisher"));
publisher.setHostname(m_testBroker);
publisher.setPort(m_port);
publisher.connectToHost();
QTRY_COMPARE(publisher.state(), QMqttClient::Connected);
QMqttClient subscriber;
subscriber.setClientId(QLatin1String("subscriber"));
subscriber.setHostname(m_testBroker);
subscriber.setPort(m_port);
subscriber.connectToHost();
QTRY_COMPARE(subscriber.state(), QMqttClient::Connected);
bool received = false;
bool verified = false;
connect(&subscriber, &QMqttClient::messageReceived, [&](const QByteArray &, const QString &t) {
received = true;
verified = t == truncTopic;
});
auto client1Sub = subscriber.subscribe(truncTopic, 1);
QTRY_COMPARE(client1Sub->state(), QMqttSubscription::Subscribed);
publisher.publish(topic, QByteArray("Msgs"), 1);
QTRY_VERIFY2(received, "Subscriber did not receive message");
QVERIFY2(verified, "Subscriber received different message");
}
void Tst_QMqttClient::subscribeLongTopic()
{
QMqttClient subscriber;
subscriber.setClientId(QLatin1String("subscriber"));
subscriber.setHostname(m_testBroker);
subscriber.setPort(m_port);
subscriber.connectToHost();
QTRY_COMPARE(subscriber.state(), QMqttClient::Connected);
QString topic;
topic.fill(QLatin1Char('s'), 2 * UINT16_MAX);
auto sub = subscriber.subscribe(topic);
QVERIFY(sub.isNull());
}
QTEST_MAIN(Tst_QMqttClient)
#include "tst_qmqttclient.moc"