/****************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtMqtt module. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ******************************************************************************/ #include #include #include #include Q_DECLARE_METATYPE(QMqttSubscription::SubscriptionState) class FakeServer : public QIODevice { Q_OBJECT public: explicit FakeServer(QObject *parent); qint64 readData(char *data, qint64 maxlen) override; qint64 writeData(const char *data, qint64 len) override; int m_messageState{0}; QByteArray m_readBuffer; }; FakeServer::FakeServer(QObject *parent) : QIODevice(parent) { m_messageState = 0; open(QIODevice::ReadWrite | QIODevice::Unbuffered); } qint64 FakeServer::readData(char *data, qint64 maxlen) { const qint64 dataToWrite = qMax(0, qMin(maxlen, m_readBuffer.size())); memcpy(data, m_readBuffer.constData(), static_cast(dataToWrite)); m_readBuffer = m_readBuffer.mid(static_cast(dataToWrite)); return dataToWrite; } void bufferAppend(QByteArray &buffer, quint16 value) { const quint16 msb = qToBigEndian(value); const char * msb_c = reinterpret_cast(&msb); buffer.append(msb_c, 2); } qint64 FakeServer::writeData(const char *data, qint64 len) { if (m_messageState == 0) { // Received CONNECT QByteArray response; response += 0x20; response += quint8(2); // Payload size response += char(0); // ackFlags response += char(0); // result m_readBuffer = response; emit readyRead(); m_messageState = 1; } else if (m_messageState == 1) { // Received SUBSCRIBE // Byte 0 == 0x82 (0x80 SUBSCRIBE 0x02 standard) quint8 msg = reinterpret_cast(data)[0]; if (msg != quint8(0x82)) qFatal("Expected subscribe message"); // Byte 1+2 == ID const quint16 id_big = *reinterpret_cast(&data[2]); const quint16 id = qFromBigEndian(id_big); QMqttControlPacket packet(QMqttControlPacket::SUBACK); packet.append(id); const quint8 qosLevel = 1; packet.append(static_cast(qosLevel)); m_readBuffer = packet.serialize(); // We need to be async to have QMqttConnection prepare its internals QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); m_messageState = 2; } // Ignore any follow up data return len; } extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) { static int argc = 1; static char *argv_1[] = {qstrdup("fuzzprepare")}; static char **argv = argv_1; static QCoreApplication a(argc, argv); FakeServer serv(&a); QMqttClient client; client.setHostname(QLatin1String("localhost")); client.setPort(1883); client.setTransport(&serv, QMqttClient::IODevice); client.connectToHost(); QSignalSpy spy(&client, &QMqttClient::connected); spy.wait(5); if (client.state() != QMqttClient::Connected) { qFatal("Not able to run test propertly"); return -1; } auto sub = client.subscribe(QLatin1String("a"), 1); qRegisterMetaType("SubscriptionState"); QSignalSpy subSpy(sub, &QMqttSubscription::stateChanged); spy.wait(5); if (sub->state() != QMqttSubscription::Subscribed) spy.wait(10); if (sub->state() != QMqttSubscription::Subscribed) qFatal("Could not subscribe"); serv.m_readBuffer = QByteArray(Data, static_cast(Size)); QMetaObject::invokeMethod(&serv, "readyRead"); QCoreApplication::processEvents(); return 0; } #include "main.moc"