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,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: |