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

MQTT 5: Add Maximum Packet Size check

Disconnect with reason code 0x95 (Packet too large) if a packet
exceeds the Maximum Packet Size limit, as required by section 3.1.2.11.4
of the MQTT 5 spec.

Note: This fix doesn't protect against memory exhaustion in user apps.
It just implements the spec requirement about message limit.

Task-number: QTBUG-149866
Change-Id: I2baa8ceb95e4a045437e2caa51e5508b2fa8b2eb
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
(cherry picked from commit 1316c02fe7)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Tatiana Borisova 2026-09-15 21:18:40 +02:00 committed by Qt Cherry-pick Bot
parent b15db02d09
commit a65d55378c
2 changed files with 28 additions and 6 deletions

View File

@ -726,7 +726,7 @@ bool QMqttConnection::sendControlPingRequest(bool isAuto)
return true;
}
bool QMqttConnection::sendControlDisconnect()
bool QMqttConnection::sendControlDisconnect(std::optional<QMqtt::ReasonCode> reasonCode)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO;
@ -738,7 +738,13 @@ bool QMqttConnection::sendControlDisconnect()
m_receiveAliases.clear();
m_publishAliases.clear();
const QMqttControlPacket packet(QMqttControlPacket::DISCONNECT);
QMqttControlPacket packet(QMqttControlPacket::DISCONNECT);
if (m_clientPrivate->m_protocolVersion == QMqttClient::MQTT_5_0 && reasonCode) {
// MQTT-3.14.2 The Disconnect Reason Code is a part of the variable header.
// Reason codes exist in MQTT 5.0 only, so this is never used for an older version.
packet.append(char(quint8(*reasonCode)));
packet.append(char(0)); // MQTT-3.14.2.2 property length, we send no properties
}
if (!writePacketToTransport(packet)) {
qCDebug(lcMqttConnection) << "Failed to write DISCONNECT to transport.";
return false;
@ -1935,11 +1941,26 @@ void QMqttConnection::finalize_pingresp()
bool QMqttConnection::processDataHelper()
{
if (m_missingData > 0) {
if ((m_readBuffer.size() - m_readPosition) < m_missingData)
return false;
// MQTT-2.1.4 The remaining length in the fixed header says where the message ends.
const qint64 packetEnd = qint64(m_readPosition) + m_missingData;
// 3.1.2.11.4 Maximum Packet Size
// If client receives a packet whose size exceeds this limit,
// this is a Protocol Error, the Client uses DISCONNECT with
// Reason Code 0x95 (Packet too large),
if (m_clientPrivate->m_protocolVersion == QMqttClient::MQTT_5_0
&& (m_internalState == BrokerConnected
|| m_internalState == BrokerWaitForConnectAck)) {
const quint32 maxSize = m_clientPrivate->m_connectionProperties.maximumPacketSize();
if (maxSize > 0 && packetEnd > maxSize) {
qCDebug(lcMqttConnection) << "Packet size exceeds the announced maximum.";
m_clientPrivate->m_client->setError(QMqttClient::ProtocolViolation);
sendControlDisconnect(QMqtt::ReasonCode::PacketTooLarge);
return false;
}
}
if ((m_readBuffer.size() - m_readPosition) < m_missingData)
return false;
switch (m_currentPacket & 0xF0) {
case QMqttControlPacket::AUTH:

View File

@ -28,6 +28,7 @@
#include <QtCore/QtEndian>
#include <memory>
#include <optional>
QT_BEGIN_NAMESPACE
@ -67,7 +68,7 @@ public:
QMqttSubscription *sendControlSubscribe(const QMqttTopicFilter &topic, quint8 qos, const QMqttSubscriptionProperties &properties);
bool sendControlUnsubscribe(const QMqttTopicFilter &topic, const QMqttUnsubscriptionProperties &properties);
bool sendControlPingRequest(bool isAuto = true);
bool sendControlDisconnect();
bool sendControlDisconnect(std::optional<QMqtt::ReasonCode> reasonCode = std::nullopt);
void setClientPrivate(QMqttClientPrivate *clientPrivate);