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 7  
8 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 11 fd(fd),
  12 + fuzzMode(fuzzMode),
12 13 initialBufferSize(settings->clientInitialBufferSize), // The client is constructed in the main thread, so we need to use its settings copy
13 14 maxPacketSize(settings->maxPacketSize), // Same as initialBufferSize comment.
14 15 ioWrapper(ssl, websocket, initialBufferSize, this),
... ... @@ -264,6 +265,11 @@ void Client::resetBuffersIfEligible()
264 265 // Call this from a place you know the writeBufMutex is locked, or we're still only doing SSL accept.
265 266 void Client::setReadyForWriting(bool val)
266 267 {
  268 +#ifndef NDEBUG
  269 + if (fuzzMode)
  270 + return;
  271 +#endif
  272 +
267 273 if (disconnecting)
268 274 return;
269 275  
... ... @@ -286,6 +292,11 @@ void Client::setReadyForWriting(bool val)
286 292  
287 293 void Client::setReadyForReading(bool val)
288 294 {
  295 +#ifndef NDEBUG
  296 + if (fuzzMode)
  297 + return;
  298 +#endif
  299 +
289 300 if (disconnecting)
290 301 return;
291 302  
... ...
client.h
... ... @@ -29,6 +29,7 @@ class Client
29 29 friend class IoWrapper;
30 30  
31 31 int fd;
  32 + bool fuzzMode = false;
32 33  
33 34 ProtocolVersion protocolVersion = ProtocolVersion::None;
34 35  
... ... @@ -70,7 +71,7 @@ class Client
70 71 void setReadyForReading(bool val);
71 72  
72 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 75 Client(const Client &other) = delete;
75 76 Client(Client &&other) = delete;
76 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 185 puts(" -h, --help Print help");
186 186 puts(" -c, --config-file <flashmq.conf> Configuration file.");
187 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 191 puts(" -V, --version Show version");
189 192 puts(" -l, --license Show license");
190 193 }
... ... @@ -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 267 void MainApp::initMainApp(int argc, char *argv[])
260 268 {
261 269 if (instance != nullptr)
... ... @@ -266,17 +274,19 @@ void MainApp::initMainApp(int argc, char *argv[])
266 274 {"help", no_argument, nullptr, 'h'},
267 275 {"config-file", required_argument, nullptr, 'c'},
268 276 {"test-config", no_argument, nullptr, 't'},
  277 + {"fuzz-file", required_argument, nullptr, 'z'},
269 278 {"version", no_argument, nullptr, 'V'},
270 279 {"license", no_argument, nullptr, 'l'},
271 280 {nullptr, 0, nullptr, 0}
272 281 };
273 282  
274 283 std::string configFile;
  284 + std::string fuzzFile;
275 285  
276 286 int option_index = 0;
277 287 int opt;
278 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 291 switch(opt)
282 292 {
... ... @@ -289,6 +299,9 @@ void MainApp::initMainApp(int argc, char *argv[])
289 299 case 'V':
290 300 MainApp::showLicense();
291 301 exit(0);
  302 + case 'z':
  303 + fuzzFile = optarg;
  304 + break;
292 305 case 'h':
293 306 MainApp::doHelp(argv[0]);
294 307 exit(16);
... ... @@ -325,6 +338,7 @@ void MainApp::initMainApp(int argc, char *argv[])
325 338 }
326 339  
327 340 instance = new MainApp(configFile);
  341 + instance->setFuzzFile(fuzzFile);
328 342 }
329 343  
330 344  
... ... @@ -365,6 +379,37 @@ void MainApp::start()
365 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 413 uint next_thread_index = 0;
369 414  
370 415 struct epoll_event events[MAX_EVENTS];
... ...
mainapp.h
... ... @@ -39,6 +39,7 @@ class MainApp
39 39 std::shared_ptr<Settings> settings;
40 40 std::list<std::shared_ptr<Listener>> listeners;
41 41 std::mutex quitMutex;
  42 + std::string fuzzFilePath;
42 43  
43 44 Logger *logger = Logger::getInstance();
44 45  
... ... @@ -49,6 +50,7 @@ class MainApp
49 50 int createListenSocket(const std::shared_ptr<Listener> &listener);
50 51 void wakeUpThread();
51 52 void queueKeepAliveCheckAtAllThreads();
  53 + void setFuzzFile(const std::string &fuzzFilePath);
52 54  
53 55 MainApp(const std::string &configFilePath);
54 56 public:
... ...