diff options
author | Stephen Morris <stephen@isc.org> | 2019-12-19 11:24:17 +0100 |
---|---|---|
committer | Stephen Morris <stephen@isc.org> | 2019-12-20 18:55:45 +0100 |
commit | 08381e6773c2207dca99b280de006d829ff972b8 (patch) | |
tree | 3c00f4a8d2da7f3cef0fe0f8d8a6b3ea6d582e57 /src/lib/dhcpsrv/fuzz.h | |
parent | [#640] Major refactoring of fuzzing code (diff) | |
download | kea-08381e6773c2207dca99b280de006d829ff972b8.tar.xz kea-08381e6773c2207dca99b280de006d829ff972b8.zip |
[#640] Simplification of fuzzing structure
Instead of using a separate thread to read input from the fuzzer,
the input is now read in the main thread and transferred to the
interface on which Kea is expecting it to appear.
Diffstat (limited to 'src/lib/dhcpsrv/fuzz.h')
-rw-r--r-- | src/lib/dhcpsrv/fuzz.h | 175 |
1 files changed, 59 insertions, 116 deletions
diff --git a/src/lib/dhcpsrv/fuzz.h b/src/lib/dhcpsrv/fuzz.h index bdcbaf0a09..0c6fd93eaa 100644 --- a/src/lib/dhcpsrv/fuzz.h +++ b/src/lib/dhcpsrv/fuzz.h @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -22,112 +22,87 @@ #include <thread> namespace isc { + -/// @brief Helper class to manage synchronization between fuzzing threads +/// @brief AFL Fuzzing +/// +/// Persistent-mode AFL fuzzing has the AFL fuzzer send packets of data to +/// stdin of the program being tested. The program processes the data and +/// signals to AFL that it is complete. +/// +/// To reduce the code changes required, the scheme adopted for Kea is that +/// the AFL data read from stdin is written to an address/port on which Kea +/// is listening. Kea then reads the data from that port and processes it +/// in the usual way. /// -/// This contains the variables and encapsulates the primitives required -/// to manage the condition variables between the two threads. +/// The Fuzz class handles the transfer of data between AFL and Kea. After +/// suitable initialization, its transfer() method is called in the main +/// processing loop, right before Kea waits for input. The method handles the +/// read from stdin and the write to the selected address port. -class FuzzSync { +class Fuzz { public: - /// @brief Constructor - /// - /// Just set the name of the variable for debug message purposes. + /// @brief size of the buffer used to transfer data between AFL and Kea. /// - /// @param name The name of the object, output in debug messages. - FuzzSync(const char* name); + /// This is much larger than the data that will be sent to Kea (so AFL + /// data may be trimmed). However, it does allow for AFL to send quite + /// large packets without resulting in AFL synchronization problems because + /// Kea has not read all the data sent. + static constexpr size_t BUFFER_SIZE = 256 * 1024; - /// @brief Waits for condition notification - /// - /// Called by a thread, this function will wait for another thread to - /// notify it that it can proceed: in other words, this function calls - /// <condition_variable>.wait() and waits for the other to call - /// <condition_variable>.notify(). - /// - /// As it is possible to miss a notification - if one thread reaches the - /// notification point before the other thread reaches the wait point - - /// the operation is mediated by a predicate (in this case, a boolean - /// variable). If this is set when the waiting thread reaches the wait - /// point, the thread does not wait. If it is not set, the thread will - /// wait until it is notified through the condition variable. At this - /// point, if the variable is still not set, the thread will re-enter the - /// wait state. + /// @brief maximum size of packets fuzzing thread will send to Kea /// - /// In both cases, the predicate variable is cleared on exit. - void wait(void); + /// This is below the maximum size of data that we will allow Kea to put + /// into a single UDP datagram so as to avoid any "data too big" errors + /// when trying to send it to the port on which Kea lsutens. + static constexpr size_t MAX_SEND_SIZE = 64000; - /// @brief Notifies other thread to continue + /// @brief Number of packets Kea will process before shutting down. /// - /// Called by a thread, this function will notify another thread that is - /// waiting on the condition variable that it can continue. As noted - /// in the documentation for wait(), the operation is mediated by a - /// predicate variable; in this case, the variable is explicitly set - /// before the notification is sent. - void notify(void); - -private: - std::condition_variable cond_; - std::mutex mutex_; - volatile bool ready_; - std::string name_; -}; - - -/// @brief AFL Fuzzing Functions + /// After the shutdown, AFL will restart it. This safety switch is here for + /// eliminating cases where Kea goes into a weird state and stops + /// processing packets properly. This can be overridden by setting the + /// environment variable FUZZ_AFL_LOOP_MAX. + static constexpr long MAX_LOOP_COUNT = 1000; -class Fuzz { -public: - /// @brief Constructor - /// - /// Initializes member variables. - Fuzz(); /// @brief Constructor /// - /// Initializes fuzzing object and starts the fuzzing thread. + /// Sets up data structures to access the address/port being used to + /// transfer data from AFL to Kea. /// /// @param ipversion Either 4 or 6 depending on what IP version the /// server responds to. - /// @param shutdown Pointer to boolean flag that will be set to true to - /// trigger the shutdown procedure. - Fuzz(int ipversion, volatile bool* shutdown); + /// @param port Port on which the server is listening, and hence the + /// port to which the fuzzer will send input from AFL. + Fuzz(int ipversion, uint16_t port); /// @brief Destructor /// - /// Does some basic checks when going out of scope. The purpose of these - /// checks is to aid diagnosis in the event of problems with the fuzzing. + /// Closes the socket used for transferring data from stdin to the selected + /// interface. ~Fuzz(); - /// @brief Main Kea Fuzzing Function - /// - /// This is the main Kea fuzzing method. It is the entry point for the - /// thread that handles the interface between AFL and Kea. The method - /// receives data from the fuzzing engine via stdin, and then sends it to - /// the configured UDP socket. The main thread of Kea reads it from there, - /// processes it and when processing is complete, calls the - /// packetProcessed() method to notify the fuzzing thread that processing - /// of the packet is complete. + /// @brief Transfer Data /// - /// After a given number of packets, this method will set the flag shut - /// down Kea. This is recommended by the AFL documentation as it avoids - /// any resource leaks (which are not caught by AFL) from getting too large - /// and interfering with the fuzzing. AFL will automatically restart the - /// program to continue fuzzing. - void run(void); - - /// @brief Notify fuzzing thread that processing is complete + /// Called immediately prior to Kea reading data, this reads stdin (where + /// AFL will have sent the packet being tested) and copies the data to the + /// interface on which Kea is listening. + void transfer(void); + + /// @brief Return Max Loop Count /// - /// This function is called by the Kea processing loop running in the main - /// thread when it has finished processing a packet. It raises a SIGSTOP - /// signal, which tells the AFL fuzzer that processing for the data it has - /// just sent has finished; this causes it to send another fuzzed packet - /// to stdin. It also sets a condition variable, so releasing the fuzzing - /// thread to read the next data from AFL. + /// Returns the maximum number of loops (i.e. AFL packets processed) before + /// Kea exits. This is the value of the environment variable + /// FUZZ_AFL_LOOP_MAX, or the class constant MAX_LOOP_COUNT if that is not + /// defined. /// - /// If a shutdown has been initiated, this method waits for the fuzzing - /// thread to exit before allowing the shutdown to continue. - void packetProcessed(void); + /// @return Maximum loop count + long maxLoopCount() const { + return loop_max_; + } +private: /// @brief Populate address structures /// /// Decodes the environment variables used to pass address/port information @@ -140,48 +115,16 @@ public: /// format. void setAddress(int ipversion); - /// @brief size of the buffer used to transfer data between AFL and Kea. - /// - /// This is much larger than the data that will be sent to Kea (so AFL - /// data being trimmed). However, it does allow for AFL to send quite - /// large packets without resulting in timeouts or synchronization - /// problems with the fuzzing thread. - static constexpr size_t BUFFER_SIZE = 128000; - - /// @brief maximum size of packets fuzzing thread will send to Kea - /// - /// This is below the maximum size of data that can be put into a - /// single UDP datagram. - static constexpr size_t MAX_SEND_SIZE = 64000; - - /// @brief Delay before rereading if read from stdin returns an error (us) - static constexpr useconds_t SLEEP_INTERVAL = 50000; - - /// @brief Number of many packets Kea will process until shutting down. - /// - /// After the shutdown, AFL will restart it. This safety switch is here for - /// eliminating cases where Kea goes into a weird state and stops - /// processing packets properly. - static constexpr long LOOP_COUNT = 1000; - - // Condition/mutex variables. The fuzz_XX_ variables are set by the - // fuzzing thread and waited on by the main thread. The main_XX_ variables - // are set by the main thread and waited on by the fuzzing thread. - FuzzSync fuzz_sync_; // Set by fuzzing thread - FuzzSync main_sync_; // Set by main thread - // Other member variables. const char* address_; //< Pointer to address string - std::thread fuzzing_thread_;//< Holds the thread ID const char* interface_; //< Pointer to interface string long loop_max_; //< Maximum number of loop iterations uint16_t port_; //< Port number to use - volatile bool running_; //< Set if the thread is running - struct sockaddr* sockaddr_ptr_; //< Pointer to structure used size_t sockaddr_len_; //< Length of the structure + struct sockaddr* sockaddr_ptr_; //< Pointer to structure used struct sockaddr_in servaddr4_; //< IPv6 address information struct sockaddr_in6 servaddr6_; //< IPv6 address information - volatile bool* shutdown_ptr_; //< Pointer to shutdown flag + int sockfd_; //< Socket used to transfer data }; |