Commit d6af7d82ca171683275649722f7019c0a1776392

Authored by Wiebe Cazemier
1 parent 6e92c053

Add fuzz mode by feeding a client from a file

This can be called by a fuzzer like afl-fuzz.
client.cpp
@@ -7,8 +7,9 @@ @@ -7,8 +7,9 @@
7 7
8 #include "logger.h" 8 #include "logger.h"
9 9
10 -Client::Client(int fd, ThreadData_p threadData, SSL *ssl, bool websocket, std::shared_ptr<Settings> settings) : 10 +Client::Client(int fd, ThreadData_p threadData, SSL *ssl, bool websocket, std::shared_ptr<Settings> settings, bool fuzzMode) :
11 fd(fd), 11 fd(fd),
  12 + fuzzMode(fuzzMode),
12 initialBufferSize(settings->clientInitialBufferSize), // The client is constructed in the main thread, so we need to use its settings copy 13 initialBufferSize(settings->clientInitialBufferSize), // The client is constructed in the main thread, so we need to use its settings copy
13 maxPacketSize(settings->maxPacketSize), // Same as initialBufferSize comment. 14 maxPacketSize(settings->maxPacketSize), // Same as initialBufferSize comment.
14 ioWrapper(ssl, websocket, initialBufferSize, this), 15 ioWrapper(ssl, websocket, initialBufferSize, this),
@@ -264,6 +265,11 @@ void Client::resetBuffersIfEligible() @@ -264,6 +265,11 @@ void Client::resetBuffersIfEligible()
264 // Call this from a place you know the writeBufMutex is locked, or we're still only doing SSL accept. 265 // Call this from a place you know the writeBufMutex is locked, or we're still only doing SSL accept.
265 void Client::setReadyForWriting(bool val) 266 void Client::setReadyForWriting(bool val)
266 { 267 {
  268 +#ifndef NDEBUG
  269 + if (fuzzMode)
  270 + return;
  271 +#endif
  272 +
267 if (disconnecting) 273 if (disconnecting)
268 return; 274 return;
269 275
@@ -286,6 +292,11 @@ void Client::setReadyForWriting(bool val) @@ -286,6 +292,11 @@ void Client::setReadyForWriting(bool val)
286 292
287 void Client::setReadyForReading(bool val) 293 void Client::setReadyForReading(bool val)
288 { 294 {
  295 +#ifndef NDEBUG
  296 + if (fuzzMode)
  297 + return;
  298 +#endif
  299 +
289 if (disconnecting) 300 if (disconnecting)
290 return; 301 return;
291 302
client.h
@@ -29,6 +29,7 @@ class Client @@ -29,6 +29,7 @@ class Client
29 friend class IoWrapper; 29 friend class IoWrapper;
30 30
31 int fd; 31 int fd;
  32 + bool fuzzMode = false;
32 33
33 ProtocolVersion protocolVersion = ProtocolVersion::None; 34 ProtocolVersion protocolVersion = ProtocolVersion::None;
34 35
@@ -70,7 +71,7 @@ class Client @@ -70,7 +71,7 @@ class Client
70 void setReadyForReading(bool val); 71 void setReadyForReading(bool val);
71 72
72 public: 73 public:
73 - Client(int fd, ThreadData_p threadData, SSL *ssl, bool websocket, std::shared_ptr<Settings> settings); 74 + Client(int fd, ThreadData_p threadData, SSL *ssl, bool websocket, std::shared_ptr<Settings> settings, bool fuzzMode=false);
74 Client(const Client &other) = delete; 75 Client(const Client &other) = delete;
75 Client(Client &&other) = delete; 76 Client(Client &&other) = delete;
76 ~Client(); 77 ~Client();
fuzztests/close.dat 0 → 100644
No preview for this file type
fuzztests/connect-publish-close.dat 0 → 100644
No preview for this file type
fuzztests/connect.dat 0 → 100644
No preview for this file type
fuzztests/publish.dat 0 → 100644
No preview for this file type
mainapp.cpp
@@ -185,6 +185,9 @@ void MainApp::doHelp(const char *arg) @@ -185,6 +185,9 @@ void MainApp::doHelp(const char *arg)
185 puts(" -h, --help Print help"); 185 puts(" -h, --help Print help");
186 puts(" -c, --config-file <flashmq.conf> Configuration file."); 186 puts(" -c, --config-file <flashmq.conf> Configuration file.");
187 puts(" -t, --test-config Test configuration file."); 187 puts(" -t, --test-config Test configuration file.");
  188 +#ifndef NDEBUG
  189 + puts(" -z, --fuzz-file <inputdata.dat> For fuzzing, provides the bytes that would be sent by a client.");
  190 +#endif
188 puts(" -V, --version Show version"); 191 puts(" -V, --version Show version");
189 puts(" -l, --license Show license"); 192 puts(" -l, --license Show license");
190 } 193 }
@@ -256,6 +259,11 @@ void MainApp::queueKeepAliveCheckAtAllThreads() @@ -256,6 +259,11 @@ void MainApp::queueKeepAliveCheckAtAllThreads()
256 } 259 }
257 } 260 }
258 261
  262 +void MainApp::setFuzzFile(const std::string &fuzzFilePath)
  263 +{
  264 + this->fuzzFilePath = fuzzFilePath;
  265 +}
  266 +
259 void MainApp::initMainApp(int argc, char *argv[]) 267 void MainApp::initMainApp(int argc, char *argv[])
260 { 268 {
261 if (instance != nullptr) 269 if (instance != nullptr)
@@ -266,17 +274,19 @@ void MainApp::initMainApp(int argc, char *argv[]) @@ -266,17 +274,19 @@ void MainApp::initMainApp(int argc, char *argv[])
266 {"help", no_argument, nullptr, 'h'}, 274 {"help", no_argument, nullptr, 'h'},
267 {"config-file", required_argument, nullptr, 'c'}, 275 {"config-file", required_argument, nullptr, 'c'},
268 {"test-config", no_argument, nullptr, 't'}, 276 {"test-config", no_argument, nullptr, 't'},
  277 + {"fuzz-file", required_argument, nullptr, 'z'},
269 {"version", no_argument, nullptr, 'V'}, 278 {"version", no_argument, nullptr, 'V'},
270 {"license", no_argument, nullptr, 'l'}, 279 {"license", no_argument, nullptr, 'l'},
271 {nullptr, 0, nullptr, 0} 280 {nullptr, 0, nullptr, 0}
272 }; 281 };
273 282
274 std::string configFile; 283 std::string configFile;
  284 + std::string fuzzFile;
275 285
276 int option_index = 0; 286 int option_index = 0;
277 int opt; 287 int opt;
278 bool testConfig = false; 288 bool testConfig = false;
279 - while((opt = getopt_long(argc, argv, "hc:Vlt", long_options, &option_index)) != -1) 289 + while((opt = getopt_long(argc, argv, "hc:Vltz:", long_options, &option_index)) != -1)
280 { 290 {
281 switch(opt) 291 switch(opt)
282 { 292 {
@@ -289,6 +299,9 @@ void MainApp::initMainApp(int argc, char *argv[]) @@ -289,6 +299,9 @@ void MainApp::initMainApp(int argc, char *argv[])
289 case 'V': 299 case 'V':
290 MainApp::showLicense(); 300 MainApp::showLicense();
291 exit(0); 301 exit(0);
  302 + case 'z':
  303 + fuzzFile = optarg;
  304 + break;
292 case 'h': 305 case 'h':
293 MainApp::doHelp(argv[0]); 306 MainApp::doHelp(argv[0]);
294 exit(16); 307 exit(16);
@@ -325,6 +338,7 @@ void MainApp::initMainApp(int argc, char *argv[]) @@ -325,6 +338,7 @@ void MainApp::initMainApp(int argc, char *argv[])
325 } 338 }
326 339
327 instance = new MainApp(configFile); 340 instance = new MainApp(configFile);
  341 + instance->setFuzzFile(fuzzFile);
328 } 342 }
329 343
330 344
@@ -365,6 +379,37 @@ void MainApp::start() @@ -365,6 +379,37 @@ void MainApp::start()
365 threads.push_back(t); 379 threads.push_back(t);
366 } 380 }
367 381
  382 +#ifndef NDEBUG
  383 + // I fuzzed using afl-fuzz. You need to compile it with their compiler.
  384 + if (!fuzzFilePath.empty())
  385 + {
  386 + int fd = open(fuzzFilePath.c_str(), O_RDONLY);
  387 +
  388 + if (fd < 0)
  389 + return;
  390 +
  391 + try
  392 + {
  393 + std::vector<MqttPacket> packetQueueIn;
  394 +
  395 + Client_p client(new Client(fd, threads[0], nullptr, false, settings, true));
  396 + client->readFdIntoBuffer();
  397 + client->bufferToMqttPackets(packetQueueIn, client);
  398 +
  399 + for (MqttPacket &packet : packetQueueIn)
  400 + {
  401 + packet.handle();
  402 + }
  403 + }
  404 + catch (ProtocolError &ex)
  405 + {
  406 + logger->logf(LOG_ERR, "Expected MqttPacket handling error: %s", ex.what());
  407 + }
  408 +
  409 + running = false;
  410 + }
  411 +#endif
  412 +
368 uint next_thread_index = 0; 413 uint next_thread_index = 0;
369 414
370 struct epoll_event events[MAX_EVENTS]; 415 struct epoll_event events[MAX_EVENTS];
mainapp.h
@@ -39,6 +39,7 @@ class MainApp @@ -39,6 +39,7 @@ class MainApp
39 std::shared_ptr<Settings> settings; 39 std::shared_ptr<Settings> settings;
40 std::list<std::shared_ptr<Listener>> listeners; 40 std::list<std::shared_ptr<Listener>> listeners;
41 std::mutex quitMutex; 41 std::mutex quitMutex;
  42 + std::string fuzzFilePath;
42 43
43 Logger *logger = Logger::getInstance(); 44 Logger *logger = Logger::getInstance();
44 45
@@ -49,6 +50,7 @@ class MainApp @@ -49,6 +50,7 @@ class MainApp
49 int createListenSocket(const std::shared_ptr<Listener> &listener); 50 int createListenSocket(const std::shared_ptr<Listener> &listener);
50 void wakeUpThread(); 51 void wakeUpThread();
51 void queueKeepAliveCheckAtAllThreads(); 52 void queueKeepAliveCheckAtAllThreads();
  53 + void setFuzzFile(const std::string &fuzzFilePath);
52 54
53 MainApp(const std::string &configFilePath); 55 MainApp(const std::string &configFilePath);
54 public: 56 public: