diff options
-rwxr-xr-x | configure.ac | 4 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_srv.cc | 22 | ||||
-rw-r--r-- | src/bin/dhcp6/Makefile.am | 1 | ||||
-rw-r--r-- | src/bin/dhcp6/dhcp6_srv.cc | 36 | ||||
-rw-r--r-- | src/bin/dhcp6/fuzz.cc | 280 | ||||
-rw-r--r-- | src/bin/dhcp6/fuzz.h | 29 | ||||
-rw-r--r-- | src/lib/dhcpsrv/Makefile.am | 17 | ||||
-rw-r--r-- | src/lib/dhcpsrv/fuzz.cc | 339 | ||||
-rw-r--r-- | src/lib/dhcpsrv/fuzz.h | 199 | ||||
-rw-r--r-- | src/lib/dhcpsrv/fuzz_log.cc | 23 | ||||
-rw-r--r-- | src/lib/dhcpsrv/fuzz_log.h | 43 | ||||
-rw-r--r-- | src/lib/dhcpsrv/fuzz_messages.cc | 63 | ||||
-rw-r--r-- | src/lib/dhcpsrv/fuzz_messages.h | 35 | ||||
-rw-r--r-- | src/lib/dhcpsrv/fuzz_messages.mes | 105 |
14 files changed, 865 insertions, 331 deletions
diff --git a/configure.ac b/configure.ac index 0a8075fe00..6f292d6508 100755 --- a/configure.ac +++ b/configure.ac @@ -1464,10 +1464,10 @@ AC_ARG_ENABLE(fuzz, [AC_HELP_STRING([--enable-fuzz], [indicates that the code will be built with AFL (American Fuzzy Lop) support. Code built this way is unusable as a regular server. [default=no]])], enable_fuzz=$enableval, enable_fuzz=no) -AM_CONDITIONAL(FUZZ, test x$enable_fuzz != xno) +AM_CONDITIONAL(ENABLE_AFL, test x$enable_fuzz != xno) if test "x$enable_fuzz" != "xno" ; then - AC_DEFINE([FUZZ], [1], [AFL fuzzing was enabled.]) + AC_DEFINE([ENABLE_AFL], [1], [AFL fuzzing was enabled.]) fi diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 2ba43def3c..d0a45aa7d1 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -31,6 +31,7 @@ #include <dhcpsrv/cfg_iface.h> #include <dhcpsrv/cfg_shared_networks.h> #include <dhcpsrv/cfg_subnets4.h> +#include <dhcpsrv/fuzz.h> #include <dhcpsrv/lease_mgr.h> #include <dhcpsrv/lease_mgr_factory.h> #include <dhcpsrv/ncr_generator.h> @@ -771,6 +772,21 @@ Dhcpv4Srv::sendPacket(const Pkt4Ptr& packet) { bool Dhcpv4Srv::run() { +#ifdef ENABLE_AFL + // AFL fuzzing setup initiated here. At this stage, Kea has loaded its + // config, opened sockets, established DB connections, etc. It is truly + // ready to process packets. Now it's time to initialize AFL. It will set + // up a separate thread that will receive data from fuzzing engine and will + // send it as packets to Kea. Kea is supposed to process them and hopefully + // not crash in the process. Once the packet processing is done, Kea should + // let the know that it's ready for the next packet. This is done further + // down in this loop by a call to the packetProcessed() method. + Fuzz fuzz_controller(4, &shutdown_); + // + // The next line is needed as a signature for AFL to recognise that we are + // running persistent fuzzing. This has to be in the main image file. + __AFL_LOOP(0); +#endif // ENABLE_AFL while (!shutdown_) { try { run_one(); @@ -786,6 +802,12 @@ Dhcpv4Srv::run() { // std::exception. LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION); } + +#ifdef ENABLE_AFL + // Ok, this particular packet processing is done. If we are fuzzing, + // let AFL know about it. + fuzz_controller.packetProcessed(); +#endif // ENABLE_AFL } return (true); diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 8ad0cfb519..6ab6b5b684 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -38,7 +38,6 @@ libdhcp6_la_SOURCES += dhcp6_lexer.ll location.hh position.hh stack.hh libdhcp6_la_SOURCES += dhcp6_parser.cc dhcp6_parser.h libdhcp6_la_SOURCES += parser_context.cc parser_context.h parser_context_decl.h libdhcp6_la_SOURCES += dhcp6_messages.h dhcp6_messages.cc -libdhcp6_la_SOURCES += fuzz.cc sbin_PROGRAMS = kea-dhcp6 diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 27b46277b2..4d28f364c1 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -13,6 +13,7 @@ #include <dhcp/docsis3_option_defs.h> #include <dhcp/duid.h> #include <dhcp/duid_factory.h> +#include <dhcpsrv/fuzz.h> #include <dhcp/iface_mgr.h> #include <dhcp/libdhcp++.h> #include <dhcp/option6_addrlst.h> @@ -65,8 +66,6 @@ #endif #include <dhcpsrv/memfile_lease_mgr.h> -#include <dhcp6/fuzz.h> - #include <boost/bind.hpp> #include <boost/foreach.hpp> #include <boost/tokenizer.hpp> @@ -444,18 +443,21 @@ Dhcpv6Srv::initContext(const Pkt6Ptr& pkt, } bool Dhcpv6Srv::run() { - -#ifdef FUZZ +#ifdef ENABLE_AFL // AFL fuzzing setup initiated here. At this stage, Kea has loaded its // config, opened sockets, established DB connections, etc. It is truly - // ready to process packets. Now it's time to initialize AFL. It will - // set up a separate thread that will receive data from fuzzing engine - // and will send it as packets to Kea. Kea is supposed to process them - // and hopefully not crash in the process. Once the packet processing - // is done, Kea should let the AFL know that it's ready for the next - // packet. This is done further down in this loop (see kea_fuzz_notify()). - kea_fuzz_setup(&shutdown_); -#endif /* FUZZ */ + // ready to process packets. Now it's time to initialize AFL. It will set + // up a separate thread that will receive data from fuzzing engine and will + // send it as packets to Kea. Kea is supposed to process them and hopefully + // not crash in the process. Once the packet processing is done, Kea should + // let the know that it's ready for the next packet. This is done further + // down in this loop by a call to the packetProcessed() method. + Fuzz fuzz_controller(6, &shutdown_); + // + // The next line is needed as a signature for AFL to recognise that we are + // running persistent fuzzing. This has to be in the main image file. + __AFL_LOOP(0); +#endif // ENABLE_AFL while (!shutdown_) { try { @@ -473,11 +475,11 @@ bool Dhcpv6Srv::run() { LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION); } -#ifdef FUZZ - // Ok, this particular packet processing is done. - // Let the AFL know about it. - kea_fuzz_notify(); -#endif +#ifdef ENABLE_AFL + // Ok, this particular packet processing is done. If we are fuzzing, + // let AFL know about it. + fuzz_controller.packetProcessed(); +#endif // ENABLE_AFL } return (true); diff --git a/src/bin/dhcp6/fuzz.cc b/src/bin/dhcp6/fuzz.cc deleted file mode 100644 index a2f50ad32b..0000000000 --- a/src/bin/dhcp6/fuzz.cc +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (C) 2016 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 - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include "config.h" - -#include <dhcp6/fuzz.h> - -#define ENABLE_AFL - -#ifdef ENABLE_AFL -#include <sys/errno.h> - -#include <dhcp/dhcp6.h> - -#include <iostream> -#include <fstream> -#include <ctime> - -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <arpa/inet.h> -#include <net/if.h> -#include <unistd.h> -#include <pthread.h> - - -#ifndef __AFL_LOOP -#error To use American Fuzzy Lop you have to set CC to afl-clang-fast!!! -#endif - -/// This is how many packets Kea will process until shutting itself down. -/// AFL should restart it. This safety switch is here for eliminating cases -/// where Kea goes into a weird state and stops processing packets properly. -const unsigned int LOOP_COUNT = 100000; - -/// This mechanism limits down the number of logs this harness prints. -/// E.g. when set to 100, it will print a message every 100 packets. -const unsigned int PRINT_EVERY = 5; - -/// This is the place where the harness log message will be printed. -const std::string PRINT_LOG("/tmp/kea-fuzz-harness.txt"); - -/* - * We are using pthreads directly because we might be using it with unthreaded - * version of BIND, where all thread functions are mocks. Since AFL for now only - * works on Linux it's not a problem. - */ -static pthread_cond_t cond; -static pthread_mutex_t mutex; - -static bool ready; - -using namespace std; - -static volatile bool * shutdown_reference = NULL; - -void kea_shutdown(void) { - if (shutdown_reference) { - // do we have the reference to shutdown flag from Dhcp6Srv? - // If yes, then let's set it to true. Kea will shutdown on - // its own. - *shutdown_reference = true; - } else { - // We don't have the pointer yet. Let's terminate abruptly. - exit(EXIT_SUCCESS); - } -} - - -// This is the main fuzzing function. It receives data from fuzzing engine. -// That data is received to stdin and then sent over the configured UDP socket. -// Then it wait for a conditional, which is called in kea_fuzz_notify() from -// Kea main loop. -static void * -kea_main_client(void *) { - const char *host; - struct sockaddr_in6 servaddr; - int sockfd; - int loop; - void *buf; - - string iface("eth0"); - string dst(ALL_DHCP_RELAY_AGENTS_AND_SERVERS); - string port("547"); - - ofstream f(PRINT_LOG.c_str(), ios::ate); - - const char *iface_ptr = getenv("KEA_AFL_INTERFACE"); - if (iface_ptr) { - iface = string(iface_ptr); - } - - const char *dst_ptr = getenv("KEA_AFL_ADDR"); - if (dst_ptr) { - dst = string(dst_ptr); - } - - const char *port_ptr = getenv("KEA_AFL_PORT"); - if (port_ptr) { - port = string(port_ptr); - } - - unsigned int iface_id = if_nametoindex(iface.c_str()); - - f << "Kea AFL setup:" << endl; - f << "Interface: " << iface << endl; - f << "Interface index: " << iface_id << endl; - f << "UDP destination addr: " << dst << endl; - f << "UDP destination port: " << port << endl; - - memset(&servaddr, 0, sizeof (servaddr)); - servaddr.sin6_family = AF_INET6; - if (inet_pton(AF_INET6, dst.c_str(), &servaddr.sin6_addr) != 1) { - f << "Error: inet_pton() failed: can't convert " << dst - << " to address." << endl; - exit(EXIT_FAILURE); - } - servaddr.sin6_port = htons(atoi(port.c_str())); - servaddr.sin6_scope_id = iface_id; - - sockfd = socket(AF_INET6, SOCK_DGRAM, 0); - if (sockfd < 0) { - f << "Failed to create UDP6 socket" << endl; - exit(EXIT_FAILURE); - } - - buf = malloc(65536); - if (!buf) { - f << "Failed to allocate a buffer" << endl; - exit(EXIT_FAILURE); - } - - time_t t; - - loop = LOOP_COUNT; - while (loop--) { - ssize_t length; - - length = read(0, buf, 65536); - if (length <= 0) { - usleep(1000000); - continue; - } - - /* if (length > 4096) { - if (getenv("AFL_CMIN")) { - ns_server_flushonshutdown(ns_g_server, - ISC_FALSE); - isc_app_shutdown(); - return (NULL); - } - raise(SIGSTOP); - continue; - } */ - - if (pthread_mutex_lock(&mutex) != 0) { - f << "#### Failed to lock mutex" << endl; - abort(); - } - - ready = false; - - ssize_t sent; - - t = time(0); - struct tm * now = localtime(&t); - - if (! (loop%PRINT_EVERY)) { - f << (now->tm_year + 1900) << "-" << (now->tm_mon + 1) << "-" << (now->tm_mday) - << " " << (now->tm_hour) << ":" << (now->tm_min) << ":" << (now->tm_sec) - << " Sending " << length << " bytes to " << dst << "/" << port - << " over " << iface << "/" << iface_id << ", loop iteration << " - << loop << endl; - } - - sent = sendto(sockfd, buf, length, 0, - (struct sockaddr *) &servaddr, sizeof(servaddr)); - if (sent != length) { - f << "#### Error: expected to send " << length - << ", but really sent " << sent << endl; - f << "#### errno=" << errno << endl; - } - - /* unclog */ - recvfrom(sockfd, buf, 65536, MSG_DONTWAIT, NULL, NULL); - - while (!ready) - pthread_cond_wait(&cond, &mutex); - - if (pthread_mutex_unlock(&mutex) != 0) { - f << "#### Failed to unlock mutex" << endl; - abort(); - } - } - - f << LOOP_COUNT << " packets processed, terminating." << endl; - f.close(); - - free(buf); - close(sockfd); - - // @todo: shutdown kea - // ns_server_flushonshutdown(ns_g_server, ISC_FALSE); - // isc_app_shutdown(); - kea_shutdown(); - - /* - * It's here just for the signature, that's how AFL detects if it's - * a 'persistent mode' binary. - */ - __AFL_LOOP(0); - - return (NULL); -} - -#endif /* ENABLE_AFT */ - -void -kea_fuzz_notify(void) { -#ifdef ENABLE_AFL - if (getenv("AFL_CMIN")) { - kea_shutdown(); - return; - } - - raise(SIGSTOP); - - if (pthread_mutex_lock(&mutex) != 0) { - cerr << "#### unable to lock mutex" << endl; - abort(); - } - - ready = true; - - if (pthread_cond_signal(&cond) != 0) { - cerr << "#### unable to cond signal" << endl; - abort(); - } - - if (pthread_mutex_unlock(&mutex) != 0) { - cerr << "Unable to unlock mutex" << endl; - abort(); - } -#endif /* ENABLE_AFL */ -} - -void -kea_fuzz_setup(volatile bool* shutdown) { -#ifdef ENABLE_AFL - - shutdown_reference = shutdown; - - /// @todo: What are those variables? What do they do? - if (getenv("__AFL_PERSISTENT") || getenv("AFL_CMIN")) { - pthread_t thread; - - if (pthread_mutex_init(&mutex, NULL) != 0) { - cerr << "#### unable to init mutex" << endl; - abort(); - } - - if (pthread_cond_init(&cond, NULL) != 0) { - cerr << "#### unable to init condition variable" << endl; - abort(); - } - - if (pthread_create(&thread, NULL, kea_main_client, NULL) != 0) { - cerr << "#### unable to create fuzz thread" << endl; - abort(); - } - } - -#endif /* ENABLE_AFL */ -} diff --git a/src/bin/dhcp6/fuzz.h b/src/bin/dhcp6/fuzz.h deleted file mode 100644 index 98d9cdf047..0000000000 --- a/src/bin/dhcp6/fuzz.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2016 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 - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#ifndef KEA_FUZZ_H -#define KEA_FUZZ_H - -extern "C" { - -void kea_fuzz_notify(void); - -/// @brief Sets up Kea fuzzing -/// -/// @param shutdown pointer to boolean flag that will be set to true to -/// trigger shutdown procedure -/// -/// This takes one parameter, which is a pointer to shutdown flag, -/// which should point to instance of Dhcp6Srv::shutdown_. Kea runs -/// until something sets this flag to true, which is an indication to -/// start shutdown procedure. -void kea_fuzz_setup(volatile bool * shutdown); - -}; - -#endif /* KEA_FUZZ_H */ diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index 8657a6d0aa..427dd3a2b5 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -180,6 +180,12 @@ libkea_dhcpsrv_la_SOURCES += parsers/simple_parser4.h libkea_dhcpsrv_la_SOURCES += parsers/simple_parser6.cc libkea_dhcpsrv_la_SOURCES += parsers/simple_parser6.h +if ENABLE_AFL +libkea_dhcpsrv_la_SOURCES += fuzz.cc fuzz.h +libkea_dhcpsrv_la_SOURCES += fuzz_log.cc fuzz_log.h +libkea_dhcpsrv_la_SOURCES += fuzz_messages.cc fuzz_messages.h +endif + libkea_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS) libkea_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) libkea_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/eval/libkea-eval.la @@ -226,6 +232,7 @@ endif EXTRA_DIST += alloc_engine_messages.mes EXTRA_DIST += dhcpsrv_messages.mes EXTRA_DIST += hosts_messages.mes +EXTRA_DIST += fuzz_messages.mes # If we want to get rid of all generated messages files, we need to use # make maintainer-clean. The proper way to introduce custom commands for @@ -237,6 +244,7 @@ maintainer-clean-local: rm -f alloc_engine_messages.h alloc_engine_messages.cc rm -f dhcpsrv_messages.h dhcpsrv_messages.cc rm -f hosts_messages.h hosts_messages.cc + rm -f fuzz_messages.h fuzz_messages.cc # To regenerate messages files, one can do: # @@ -251,7 +259,8 @@ if GENERATE_MESSAGES # Define rule to build logging source files from message file messages: alloc_engine_messages.h alloc_engine_messages.cc \ dhcpsrv_messages.h dhcpsrv_messages.cc \ - hosts_messages.h hosts_messages.cc + hosts_messages.h hosts_messages.cc \ + fuzz_messages.h fuzz_messages.cc @echo Message files regenerated alloc_engine_messages.h alloc_engine_messages.cc: alloc_engine_messages.mes @@ -263,11 +272,15 @@ dhcpsrv_messages.h dhcpsrv_messages.cc: dhcpsrv_messages.mes hosts_messages.h hosts_messages.cc: hosts_messages.mes $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/lib/dhcpsrv/hosts_messages.mes +fuzz_messages.h fuzz_messages.cc: fuzz_messages.mes + $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/lib/dhcpsrv/fuzz_messages.mes + else messages: alloc_engine_messages.h alloc_engine_messages.cc \ dhcpsrv_messages.h dhcpsrv_messages.cc \ - hosts_messages.h hosts_messages.cc + hosts_messages.h hosts_messages.cc \ + fuzz_messages.h fuzz_messages.cc @echo Messages generation disabled. Configure with --enable-generate-messages to enable it. endif diff --git a/src/lib/dhcpsrv/fuzz.cc b/src/lib/dhcpsrv/fuzz.cc new file mode 100644 index 0000000000..cb28389de4 --- /dev/null +++ b/src/lib/dhcpsrv/fuzz.cc @@ -0,0 +1,339 @@ +// Copyright (C) 2016 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 +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#ifdef ENABLE_AFL + +#ifndef __AFL_LOOP +#error To use American Fuzzy Lop you have to set CXX to afl-clang-fast++ +#endif + +#include <dhcp/dhcp6.h> +#include <dhcpsrv/fuzz.h> +#include <dhcpsrv/fuzz_log.h> + +#include <boost/lexical_cast.hpp> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> + +#include <iostream> +#include <sstream> +#include <fstream> +#include <ctime> + +using namespace isc; +using namespace isc::dhcp; +using namespace std; + +// Constants defined in the Fuzz class definition. +constexpr size_t Fuzz::BUFFER_SIZE; +constexpr size_t Fuzz::MAX_SEND_SIZE; +constexpr useconds_t Fuzz::SLEEP_INTERVAL; +constexpr long Fuzz::LOOP_COUNT; + +// FuzzSync methods. FuzSynch is the class that encapsulates the +// synchronization process between the main and fuzzing threads. + +// Constructor +FuzzSync::FuzzSync(const char* name) : ready_(false), name_(name) { +} + +// Wait to be notified when the predicate is true +void +FuzzSync::wait(void) { + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_WAITING).arg(name_); + unique_lock<mutex> lock(mutex_); + cond_.wait(lock, [=]() { return this->ready_; }); + ready_ = false; + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_WAITED).arg(name_); +} + +// Set predicate and notify the waiting thread to continue +void +FuzzSync::notify(void) { + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_SETTING).arg(name_); + unique_lock<mutex> lock(mutex_); + ready_ = true; + cond_.notify_all(); + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_SET).arg(name_); +} + +// Fuzz methods. + +// Constructor +Fuzz::Fuzz(int ipversion, volatile bool* shutdown) : + fuzz_sync_("fuzz_sync"), main_sync_("main_sync"), address_(nullptr), + interface_(nullptr), loop_max_(LOOP_COUNT), port_(0), running_(false), + sockaddr_ptr_(nullptr), sockaddr_len_(0), shutdown_ptr_(nullptr) { + + try { + stringstream reason; // Used to construct exception messages + + // Store reference to shutdown flag. When the fuzzing loop has read + // the set number of packets from AFL, it will set this flag to trigger + // a Kea shutdown. + if (shutdown) { + shutdown_ptr_ = shutdown; + } else { + isc_throw(FuzzInitFail, "must pass shutdown flag to kea_fuzz_init"); + } + + // Set up address structures. + setAddress(ipversion); + + // Check if the hard-coded maximum loop count is being overridden + const char *loop_max_ptr = getenv("FUZZ_AFL_LOOP_MAX"); + if (loop_max_ptr != 0) { + try { + loop_max_ = boost::lexical_cast<long>(loop_max_ptr); + } catch (const boost::bad_lexical_cast&) { + reason << "cannot convert port number specification " + << loop_max_ptr << " to an integer"; + isc_throw(FuzzInitFail, reason.str()); + } + + if (loop_max_ <= 0) { + reason << "FUZZ_AFL_LOOP_MAX is " << loop_max_ << ". " + << "It must be an integer greater than zero."; + isc_throw(FuzzInitFail, reason.str()); + } + } + + // Start the thread that reads the packets sent by AFL from stdin and + // passes them to the port on which Kea is listening. + fuzzing_thread_ = std::thread(&Fuzz::run, this); + + // Wait for the fuzzing thread to read its first packet from AFL and + // send it to the port on which Kea is listening. + fuzz_sync_.wait(); + + } catch (const FuzzInitFail& e) { + // AFL tends to make it difficult to find out what exactly has failed: + // make sure that the error is logged. + LOG_FATAL(fuzz_logger, FUZZ_INIT_FAIL).arg(e.what()); + throw; + } + + LOG_INFO(fuzz_logger, FUZZ_INIT_COMPLETE).arg(interface_).arg(address_) + .arg(port_).arg(loop_max_); +} + +// Destructor +Fuzz::~Fuzz() { + // The fuzzing thread should not be running when the fuzzing object + // goes out of scope. + if (running_) { + LOG_ERROR(fuzz_logger, FUZZ_THREAD_NOT_TERMINATED); + } +} + +// Parse IP address/port/interface and set up address structures. +void +Fuzz::setAddress(int ipversion) { + stringstream reason; // Used in error messages + + // Get the environment for the fuzzing: interface, address and port. + interface_ = getenv("FUZZ_AFL_INTERFACE"); + if (! interface_) { + isc_throw(FuzzInitFail, "no fuzzing interface has been set"); + } + + // Now the address. + address_ = getenv("FUZZ_AFL_ADDRESS"); + if (address_ == 0) { + isc_throw(FuzzInitFail, "no fuzzing address has been set"); + } + + // ... and the port. + const char *port_ptr = getenv("FUZZ_AFL_PORT"); + if (port_ptr == 0) { + isc_throw(FuzzInitFail, "no fuzzing port has been set"); + } + try { + port_ = boost::lexical_cast<uint16_t>(port_ptr); + } catch (const boost::bad_lexical_cast&) { + reason << "cannot convert port number specification " + << port_ptr << " to an integer"; + isc_throw(FuzzInitFail, reason.str()); + } + + // Decide if the address is an IPv4 or IPv6 address. + if ((strstr(address_, ".") != NULL) && (ipversion == 4)) { + // Assume an IPv4 address + memset(&servaddr4_, 0, sizeof(servaddr4_)); + + servaddr4_.sin_family = AF_INET; + if (inet_pton(AF_INET, address_, &servaddr4_.sin_addr) != 1) { + reason << "inet_pton() failed: can't convert " + << address_ << " to an IPv6 address" << endl; + isc_throw(FuzzInitFail, reason.str()); + } + servaddr4_.sin_port = htons(port_); + + sockaddr_ptr_ = reinterpret_cast<sockaddr*>(&servaddr4_); + sockaddr_len_ = sizeof(servaddr4_); + + } else if ((strstr(address_, ":") != NULL) && (ipversion == 6)) { + + // Set up the IPv6 address structure. + memset(&servaddr6_, 0, sizeof (servaddr6_)); + + servaddr6_.sin6_family = AF_INET6; + if (inet_pton(AF_INET6, address_, &servaddr6_.sin6_addr) != 1) { + reason << "inet_pton() failed: can't convert " + << address_ << " to an IPv6 address" << endl; + isc_throw(FuzzInitFail, reason.str()); + } + servaddr6_.sin6_port = htons(port_); + + // Interface ID is needed for IPv6 address structures. + servaddr6_.sin6_scope_id = if_nametoindex(interface_); + if (servaddr6_.sin6_scope_id == 0) { + reason << "error retrieving interface ID for " + << interface_ << ": " << strerror(errno); + isc_throw(FuzzInitFail, reason.str()); + } + + sockaddr_ptr_ = reinterpret_cast<sockaddr*>(&servaddr6_); + sockaddr_len_ = sizeof(servaddr6_); + } else { + reason << "Expected IP version (" << ipversion << ") is not " + << "4 or 6, or the given address " << address_ << " does not " + << "match the IP version expected"; + isc_throw(FuzzInitFail, reason.str()); + } + +} + + +// This is the main fuzzing function. It receives data from fuzzing engine. +// That data is received to stdin and then sent over the configured UDP socket. +// It then waits for the main thread to process the packet, the completion of +// that task being signalled by the main thread calling Fuzz::packetProcessed(). +void +Fuzz::run(void) { + running_ = true; + + // Create the socket throw which packets read from stdin will be send + // to the port on which Kea is listening. + int sockfd = socket(AF_INET6, SOCK_DGRAM, 0); + if (sockfd < 0) { + LOG_FATAL(fuzz_logger, FUZZ_SOCKET_CREATE_FAIL).arg(strerror(errno)); + return; + } + + // Main loop. This runs for a fixed number of iterations, after which + // Kea will be terminated and AFL will restart it. The counting of loop + // iterations is done here with a separate variable (instead of inside + // inside the read loop in the server process using __AFL_LOOP) to ensure + // that thread running this function shuts down properly between each + // restart of Kea. + auto loop = loop_max_; + while (loop-- > 0) { + // Read from stdin and continue reading (albeit after a pause) even + // if there is an error. Do the same if an EOF is received. + char buf[BUFFER_SIZE]; + ssize_t length = read(0, buf, sizeof(buf)); + if (length <= 0) { + // Don't log EOFs received - they may be generated by AFL + if (length != 0) { + LOG_ERROR(fuzz_logger, FUZZ_READ_FAIL).arg(strerror(errno)); + } + usleep(SLEEP_INTERVAL); + continue; + } + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_DATA_READ) + .arg(length); + + // Now send the data to the UDP port on which Kea is listening. + // + // The condition variables synchronize the operation: this thread + // will read from stdin and write to the socket. It then blocks until + // the main thread has processed the packet, at which point it can read + // more data from stdin. + // + // Synchronization is required because although the read from stdin is + // blocking, there is no blocking on the sending of data to the port + // from which Kea is reading. It is quite possible to lose packets, + // and AFL seems to get confused in this case. At any rate, without + // some form of synchronization, this approach does not work. + + // Send the data to the main Kea thread. Limit the size of the + // packets that can be sent. + size_t send_len = (length < MAX_SEND_SIZE) ? length : MAX_SEND_SIZE; + ssize_t sent = sendto(sockfd, buf, send_len, 0, sockaddr_ptr_, + sockaddr_len_); + if (sent < 0) { + // TODO: If we get here, we may well hang: AFL has sent us a + // packet but by continuing, we are not letting Kea process it + // and trigger AFL to send another. For the time being, we + // are restricting the size of packets Kea can send us. + LOG_ERROR(fuzz_logger, FUZZ_SEND_ERROR).arg(strerror(errno)); + continue; + } else if (sent != length) { + LOG_WARN(fuzz_logger, FUZZ_SHORT_SEND).arg(length).arg(sent); + } else { + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_SEND).arg(sent); + } + + if (loop <= 0) { + // If this is the last loop iteration, close everything down. + // This is done before giving permission for the main thread + // to run to avoid a race condition. + *shutdown_ptr_ = true; + close(sockfd); + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_SHUTDOWN_INITIATED); + } + + // Tell the main thread to run. + fuzz_sync_.notify(); + + // We now need to synchronize with the main thread. In particular, + // we suspend processing until we know that the processing of the + // packet by Kea has finished and that the completion function has + // raised a SIGSTOP. + main_sync_.wait(); + } + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_LOOP_EXIT); + + // If the main thread is waiting, let it terminate as well. + fuzz_sync_.notify(); + + running_ = false; + + return; +} + +// Called by the main thread, this notifies AFL that processing for the +// last packet has finished. +void +Fuzz::packetProcessed(void) { + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_PACKET_PROCESSED_CALLED); + + // Tell AFL that the processing for this packet has finished. + raise(SIGSTOP); + + // Tell the fuzzing loop that it can continue and wait until it tells + // us that the main thread can continue. + main_sync_.notify(); + fuzz_sync_.wait(); + + // If the fuzzing thread is shutting down, wait for it to terminate. + if (*shutdown_ptr_) { + // We shouldn't need to notify it to continue (the previous call in + // this method should have done that), but it does no harm to be sure. + main_sync_.notify(); + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_THREAD_WAIT); + fuzzing_thread_.join(); + LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_THREAD_TERMINATED); + } +} + +#endif // ENABLE_AFL diff --git a/src/lib/dhcpsrv/fuzz.h b/src/lib/dhcpsrv/fuzz.h new file mode 100644 index 0000000000..bdcbaf0a09 --- /dev/null +++ b/src/lib/dhcpsrv/fuzz.h @@ -0,0 +1,199 @@ +// Copyright (C) 2016 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 +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef FUZZ_H +#define FUZZ_H + +#ifdef ENABLE_AFL + +#include <exceptions/exceptions.h> + +#include <arpa/inet.h> +#include <net/if.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <condition_variable> +#include <mutex> +#include <string> +#include <thread> + +namespace isc { + +/// @brief Helper class to manage synchronization between fuzzing threads +/// +/// This contains the variables and encapsulates the primitives required +/// to manage the condition variables between the two threads. + +class FuzzSync { +public: + /// @brief Constructor + /// + /// Just set the name of the variable for debug message purposes. + /// + /// @param name The name of the object, output in debug messages. + FuzzSync(const char* name); + + /// @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. + /// + /// In both cases, the predicate variable is cleared on exit. + void wait(void); + + /// @brief Notifies other thread to continue + /// + /// 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 + +class Fuzz { +public: + /// @brief Constructor + /// + /// Initializes member variables. + Fuzz(); + + /// @brief Constructor + /// + /// Initializes fuzzing object and starts the fuzzing thread. + /// + /// @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); + + /// @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. + ~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. + /// + /// 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 + /// + /// 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. + /// + /// If a shutdown has been initiated, this method waits for the fuzzing + /// thread to exit before allowing the shutdown to continue. + void packetProcessed(void); + + /// @brief Populate address structures + /// + /// Decodes the environment variables used to pass address/port information + /// to the program and sets up the appropriate address structures. + /// + /// @param ipversion Either 4 or 6 depending on which IP version address + /// is expected. + /// + /// @throws FuzzInitFail Thrown if the address is not in the expected + /// 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_in servaddr4_; //< IPv6 address information + struct sockaddr_in6 servaddr6_; //< IPv6 address information + volatile bool* shutdown_ptr_; //< Pointer to shutdown flag +}; + + +/// @brief Exception thrown if fuzzing initialization fails. +class FuzzInitFail : public Exception { +public: + FuzzInitFail(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) { }; +}; + +} + +#endif // ENABLE_AFL + +#endif // FUZZ_H diff --git a/src/lib/dhcpsrv/fuzz_log.cc b/src/lib/dhcpsrv/fuzz_log.cc new file mode 100644 index 0000000000..e214aa0a2d --- /dev/null +++ b/src/lib/dhcpsrv/fuzz_log.cc @@ -0,0 +1,23 @@ +// Copyright (C) 2015-2018 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 +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// @brief Defines the logger used by the @c isc::dhcp::HostMgr + +#include <config.h> + +#include "dhcpsrv/fuzz_log.h" + +namespace isc { +namespace dhcp { + +extern const int FUZZ_DBG_TRACE = isc::log::DBGLVL_TRACE_BASIC; +extern const int FUZZ_DBG_TRACE_DETAIL = isc::log::DBGLVL_TRACE_DETAIL; + +isc::log::Logger fuzz_logger("fuzz"); + +} // namespace dhcp +} // namespace isc + diff --git a/src/lib/dhcpsrv/fuzz_log.h b/src/lib/dhcpsrv/fuzz_log.h new file mode 100644 index 0000000000..89a3820d2d --- /dev/null +++ b/src/lib/dhcpsrv/fuzz_log.h @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2018 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 +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef FUZZ_LOG_H +#define FUZZ_LOG_H + +#include <dhcpsrv/fuzz_messages.h> +#include <log/macros.h> + +namespace isc { +namespace dhcp { + +///@{ +/// \brief Logging levels for fuzzing output +/// +/// Defines the levels used to output debug messages during fuzzing. + +/// @brief Traces normal operations +/// +/// An example of the normal operation is a report of a packet being received +/// from the fuzzer. +extern const int FUZZ_DBG_TRACE; + +/// @brief Record detailed traces +/// +/// Messages logged at this level will log detailed tracing information. +extern const int FUZZ_DBG_TRACE_DETAIL; + +///@} + +/// @brief Logger for the @c HostMgr and the code it calls. +/// +/// Define the logger used to log messages in @c HostMgr and the code it +/// calls to manage host reservations. +extern isc::log::Logger fuzz_logger; + +} // namespace dhcp +} // namespace isc + +#endif // FUZZ_LOG_H diff --git a/src/lib/dhcpsrv/fuzz_messages.cc b/src/lib/dhcpsrv/fuzz_messages.cc new file mode 100644 index 0000000000..65dfe4de2d --- /dev/null +++ b/src/lib/dhcpsrv/fuzz_messages.cc @@ -0,0 +1,63 @@ +// File created from ../../../src/lib/dhcpsrv/fuzz_messages.mes on Sun Jun 16 2019 18:13 + +#include <cstddef> +#include <log/message_types.h> +#include <log/message_initializer.h> + +namespace isc { +namespace dhcp { + +extern const isc::log::MessageID FUZZ_DATA_READ = "FUZZ_DATA_READ"; +extern const isc::log::MessageID FUZZ_INIT_COMPLETE = "FUZZ_INIT_COMPLETE"; +extern const isc::log::MessageID FUZZ_INIT_FAIL = "FUZZ_INIT_FAIL"; +extern const isc::log::MessageID FUZZ_INTERFACE = "FUZZ_INTERFACE"; +extern const isc::log::MessageID FUZZ_LOOP_EXIT = "FUZZ_LOOP_EXIT"; +extern const isc::log::MessageID FUZZ_LOOP_MAX = "FUZZ_LOOP_MAX"; +extern const isc::log::MessageID FUZZ_PACKET_PROCESSED_CALLED = "FUZZ_PACKET_PROCESSED_CALLED"; +extern const isc::log::MessageID FUZZ_READ_FAIL = "FUZZ_READ_FAIL"; +extern const isc::log::MessageID FUZZ_SEND = "FUZZ_SEND"; +extern const isc::log::MessageID FUZZ_SEND_ERROR = "FUZZ_SEND_ERROR"; +extern const isc::log::MessageID FUZZ_SET = "FUZZ_SET"; +extern const isc::log::MessageID FUZZ_SETTING = "FUZZ_SETTING"; +extern const isc::log::MessageID FUZZ_SHORT_SEND = "FUZZ_SHORT_SEND"; +extern const isc::log::MessageID FUZZ_SHUTDOWN_INITIATED = "FUZZ_SHUTDOWN_INITIATED"; +extern const isc::log::MessageID FUZZ_SOCKET_CREATE_FAIL = "FUZZ_SOCKET_CREATE_FAIL"; +extern const isc::log::MessageID FUZZ_THREAD_NOT_TERMINATED = "FUZZ_THREAD_NOT_TERMINATED"; +extern const isc::log::MessageID FUZZ_THREAD_TERMINATED = "FUZZ_THREAD_TERMINATED"; +extern const isc::log::MessageID FUZZ_THREAD_WAIT = "FUZZ_THREAD_WAIT"; +extern const isc::log::MessageID FUZZ_WAITED = "FUZZ_WAITED"; +extern const isc::log::MessageID FUZZ_WAITING = "FUZZ_WAITING"; + +} // namespace dhcp +} // namespace isc + +namespace { + +const char* values[] = { + "FUZZ_DATA_READ", "read %1 byte(s) from AFL via stdin", + "FUZZ_INIT_COMPLETE", "fuzz initialization complete: interface %1, address %2, port %3, max loops %4", + "FUZZ_INIT_FAIL", "fuzz initialization failure, reason: %1", + "FUZZ_INTERFACE", "fuzzing will use interface %1 (address %2, port %3)", + "FUZZ_LOOP_EXIT", "fuzzing loop has exited, shutting down Kea", + "FUZZ_LOOP_MAX", "fuzzing loop will run %1 time(s) before exiting", + "FUZZ_PACKET_PROCESSED_CALLED", "packetProcessed has been called", + "FUZZ_READ_FAIL", "error reading input from fuzzer: %1", + "FUZZ_SEND", "sent %1 byte(s) to the socket connected to the Kea interface", + "FUZZ_SEND_ERROR", "failed to send data to Kea input socket: %1", + "FUZZ_SET", "successfully set %1 condition variable", + "FUZZ_SETTING", "setting %1 condition variable", + "FUZZ_SHORT_SEND", "expected to send %d bytes to Kea input socket but only sent %2", + "FUZZ_SHUTDOWN_INITIATED", "shutdown initated, shutdown flag is set", + "FUZZ_SOCKET_CREATE_FAIL", "failed to crease socket for use by fuzzing thread: %1", + "FUZZ_THREAD_NOT_TERMINATED", "fuzzing thread has not terminated", + "FUZZ_THREAD_TERMINATED", "fuzzing thread has terminated", + "FUZZ_THREAD_WAIT", "waiting for fuzzing thread to terminate", + "FUZZ_WAITED", "successfully waited for for %1 condition variable to be set", + "FUZZ_WAITING", "waiting for %1 condition variable to be set", + NULL +}; + +const isc::log::MessageInitializer initializer(values); + +} // Anonymous namespace + diff --git a/src/lib/dhcpsrv/fuzz_messages.h b/src/lib/dhcpsrv/fuzz_messages.h new file mode 100644 index 0000000000..6dea5b1871 --- /dev/null +++ b/src/lib/dhcpsrv/fuzz_messages.h @@ -0,0 +1,35 @@ +// File created from ../../../src/lib/dhcpsrv/fuzz_messages.mes on Sun Jun 16 2019 18:13 + +#ifndef FUZZ_MESSAGES_H +#define FUZZ_MESSAGES_H + +#include <log/message_types.h> + +namespace isc { +namespace dhcp { + +extern const isc::log::MessageID FUZZ_DATA_READ; +extern const isc::log::MessageID FUZZ_INIT_COMPLETE; +extern const isc::log::MessageID FUZZ_INIT_FAIL; +extern const isc::log::MessageID FUZZ_INTERFACE; +extern const isc::log::MessageID FUZZ_LOOP_EXIT; +extern const isc::log::MessageID FUZZ_LOOP_MAX; +extern const isc::log::MessageID FUZZ_PACKET_PROCESSED_CALLED; +extern const isc::log::MessageID FUZZ_READ_FAIL; +extern const isc::log::MessageID FUZZ_SEND; +extern const isc::log::MessageID FUZZ_SEND_ERROR; +extern const isc::log::MessageID FUZZ_SET; +extern const isc::log::MessageID FUZZ_SETTING; +extern const isc::log::MessageID FUZZ_SHORT_SEND; +extern const isc::log::MessageID FUZZ_SHUTDOWN_INITIATED; +extern const isc::log::MessageID FUZZ_SOCKET_CREATE_FAIL; +extern const isc::log::MessageID FUZZ_THREAD_NOT_TERMINATED; +extern const isc::log::MessageID FUZZ_THREAD_TERMINATED; +extern const isc::log::MessageID FUZZ_THREAD_WAIT; +extern const isc::log::MessageID FUZZ_WAITED; +extern const isc::log::MessageID FUZZ_WAITING; + +} // namespace dhcp +} // namespace isc + +#endif // FUZZ_MESSAGES_H diff --git a/src/lib/dhcpsrv/fuzz_messages.mes b/src/lib/dhcpsrv/fuzz_messages.mes new file mode 100644 index 0000000000..7e011f74f9 --- /dev/null +++ b/src/lib/dhcpsrv/fuzz_messages.mes @@ -0,0 +1,105 @@ +# Copyright (C) 2015-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 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$NAMESPACE isc::dhcp + +% FUZZ_DATA_READ read %1 byte(s) from AFL via stdin +A debug message output to indicate how much data has been received from +the fuzzer via stdin + +% FUZZ_INTERFACE fuzzing will use interface %1 (address %2, port %3) +An informational message output during fuzzing initialization, this reports +the details of the interface to be used for fuzzing. + +% FUZZ_INIT_COMPLETE fuzz initialization complete: interface %1, address %2, port %3, max loops %4 +An informational message output when the fuzzing initialization function has +completed successfully. The parameters listed are those which must be/can be +set via environment variables. + +% FUZZ_INIT_FAIL fuzz initialization failure, reason: %1 +An error message reported if the fuzzing initialization failed. The reason +for the failure is given in the message. + +% FUZZ_LOOP_EXIT fuzzing loop has exited, shutting down Kea +This debug message is output when Kea has processed the number of packets +given by the hard-coded variable Fuzz::LOOP_COUNT. Kea is shutting +itself down and will be restarted by AFL. This is recommended by the AFL +documentation as a way of avoiding issues if Kea gets itself into a funny +state after running for a long time. + +% FUZZ_LOOP_MAX fuzzing loop will run %1 time(s) before exiting +A debug message noting how many loops (i.e. packets from the fuzzer) the code +will process before Kea exits and the fuzzer restarts it. The hard-coded +value can be overridden by setting the environment variable FUZZ_AFL_LOOP_MAX. + +% FUZZ_PACKET_PROCESSED_CALLED packetProcessed has been called +A debug message indicating that the processing of a packet by Kea has +finished and that the Fuzz::packetProcessed() method has been called. This +raises a SIGSTOP informing AFL that Kea is ready to receive another packet. + +% FUZZ_READ_FAIL error reading input from fuzzer: %1 +This error is reported if the read of data from the fuzzer (which is +received over stdin) fails, or if a read returns zero bytes. If this +occurs, the thread will sleep for a short period before retrying the read. +The message includes the reason for the failure. + +% FUZZ_SEND sent %1 byte(s) to the socket connected to the Kea interface +A debug message stating that the sendto() call in the main fuzzing function +has successfully completed and reporting the number of bytes sent. This +call sends data received from AFL to the port on which Kea is listening. + +% FUZZ_SEND_ERROR failed to send data to Kea input socket: %1 +This error will be reported if the sendto() call in the fuzzing thread (which +sends data received from AFL to the socket on which Kea is listening) fails. +The reason for the failure is given in the message. The fuzzing code will +attempt to continue from this, but it may cause the fuzzing process to fail. + +% FUZZ_SET successfully set %1 condition variable +A debug message stating the named condition variable has been be set. + +% FUZZ_SETTING setting %1 condition variable +A debug message stating the named condition variable is to be set. + +% FUZZ_SHORT_SEND expected to send %d bytes to Kea input socket but only sent %2 +A warning message that is output if the sendto() call (used to send data +from the fuzzing thread to the main Kea processing) did not send as much +data as that read from AFL. This may indicate a problem in the underlying +communications between the fuzzing thread and the main Kea processing. + +% FUZZ_SHUTDOWN_INITIATED shutdown initated, shutdown flag is set +A debug message output when the fuzzing thread has reached the maximum number +of iterations. At this point, the shutdown flag is set, Kea will exit and +the fuzzer will restart it. Periodic shutdowns of the program being fuzzed +are recommended in the AFL documentation as a way of overcoming memory leaks +of odd conditions that a program can get into after an extended period of +running. + +% FUZZ_SOCKET_CREATE_FAIL failed to crease socket for use by fuzzing thread: %1 +An error message output when the fuzzing code has failed to create a socket +through which is will copy data received on stdin from the AFL fuzzer to +the port on which Kea is listening. The program will most likely hang if +this occurs. + +% FUZZ_THREAD_NOT_TERMINATED fuzzing thread has not terminated +An error message output in the destructor of the fuzzing object should the +object go out of scope with the fuzzing thread running. This message is +for diagnosing problems in the fuzzing code. + +% FUZZ_THREAD_TERMINATED fuzzing thread has terminated +A debug message, output when the main thread has detected that the fuzzing +thread has terminated. + +% FUZZ_THREAD_WAIT waiting for fuzzing thread to terminate +A debug message, output when the main thread is waiting for the fuzzing thread +to terminate. + +% FUZZ_WAITED successfully waited for for %1 condition variable to be set +A debug message stating the the condition variable for which the originating +thread was waiting has been set and that the wait has completed. + +% FUZZ_WAITING waiting for %1 condition variable to be set +A debug message stating the condition variable for which the originating +thread is waiting. |