Commit d6af7d82ca171683275649722f7019c0a1776392
1 parent
6e92c053
Add fuzz mode by feeding a client from a file
This can be called by a fuzzer like afl-fuzz.
Showing
8 changed files
with
62 additions
and
3 deletions
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: | ... | ... |