]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[expriments/fuzz] Added timestamps in logs, gentle shutdown support
authorTomek Mrugalski <tomasz@isc.org>
Wed, 23 Nov 2016 12:24:30 +0000 (13:24 +0100)
committerTomek Mrugalski <tomasz@isc.org>
Wed, 24 Apr 2019 10:43:05 +0000 (12:43 +0200)
doc/fuzz.txt
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/fuzz.cc
src/bin/dhcp6/fuzz.h
src/bin/dhcp6/tests/fuzz-config/fuzz.json [new file with mode: 0644]

index a1463bead52be9a2701de806e1cbbb4499e184d5..a7da3607f78c0f90303b2755fd90056f53bba552 100644 (file)
@@ -60,8 +60,12 @@ Ubuntu 16.04 I had to do this:
  Set up max size of a virtual memory allowed to 4GB:
  ulimit -v 4096000
 
+ You may be asked by AFL to tweak your kernel. In my case (ubuntu
+ 16.04), I had to tweak the scaling_governor. The instructions AFL
+ gives are very easy to follow.
+
  Instruct AFL to allow 4096MB of virtual memory and run AFL:
- afl-fuzz -m 4096 -i tests/fuzz-data -o fuzz-out ./kea-dhcp6 -c fuzz.json
+ afl-fuzz -m 4096 -i tests/fuzz-data -o fuzz-out ./kea-dhcp6 -c tests/fuzz-config/fuzz.json
 
  Here's what the switches do:
  -m 4096 - allow Kea to take up to 4GB memory
@@ -83,3 +87,12 @@ Ubuntu 16.04 I had to do this:
  b) I have my fuzz.json (which is renamed doc/examples/kea6/simple.json)
  that tell Kea to use logging on level INFO and write output to a
  file. This file keeps growing. That's around 3,8MB after 20 minutes.
+
+8. Tweak Kea harness if needed
+
+ There are several variables in src/bin/dhcp6/fuzz.cc that you can
+ tweak. By default, it will write the log to /tmp/kea-fuzz-harness.txt
+ every 5 packets and will terminate after 100.000 packets processed.
+ That mechanism is to avoid cases when Kea gets stuck and technically
+ running, but not processing packets. AFL should be able to restart
+ Kea and continue running.
index 93cb45669a05a0bb8d55bcdee5f77f0b9887098a..4c8851cb9e89a310bb22b1eeb3e728271cb7c804 100644 (file)
@@ -417,7 +417,7 @@ bool Dhcpv6Srv::run() {
     // 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();
+    kea_fuzz_setup(&shutdown_);
 #endif /* FUZZ */
 
     while (!shutdown_) {
index 43071b138e46b071d74a3f36a565da64da7d0638..9e0d1cbd93dff3ae5a2594758c543e244a5982aa 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <iostream>
 #include <fstream>
+#include <ctime>
 
 #include <stdlib.h>
 #include <string.h>
 #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
@@ -45,6 +58,22 @@ static bool ready;
 
 using namespace std;
 
+bool * shutdown_reference = NULL;
+
+
+void kea_shutdown() {
+    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
@@ -61,7 +90,7 @@ kea_main_client(void *arg) {
     string dst(ALL_DHCP_RELAY_AGENTS_AND_SERVERS);
     string port("547");
 
-    ofstream f("/tmp/kea-fuzz-harness.txt", ios::ate);
+    ofstream f(PRINT_LOG.c_str(), ios::ate);
 
     const char *iface_ptr = getenv("KEA_AFL_INTERFACE");
     if (iface_ptr) {
@@ -79,7 +108,7 @@ kea_main_client(void *arg) {
     }
 
     unsigned int iface_id = if_nametoindex(iface.c_str());
-    
+
     f << "Kea AFL setup:" << endl;
     f << "Interface: " << iface << endl;
     f << "Interface index: " << iface_id << endl;
@@ -108,7 +137,9 @@ kea_main_client(void *arg) {
         exit(EXIT_FAILURE);
     }
 
-    loop = 100000;
+    time_t t;
+
+    loop = LOOP_COUNT;
     while (loop--) {
         ssize_t length;
 
@@ -137,8 +168,16 @@ kea_main_client(void *arg) {
 
         ssize_t sent;
 
-        f << "Sending " << length << " bytes to " << dst << "/" << port
-          << " over " << iface << "/" << iface_id << endl;
+        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));
@@ -158,12 +197,16 @@ kea_main_client(void *arg) {
         }
     }
 
+    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
@@ -179,25 +222,26 @@ kea_main_client(void *arg) {
 void
 kea_fuzz_notify(void) {
 #ifdef ENABLE_AFL
-    /// @todo: What does this piece of code do?
-    /* if (getenv("AFL_CMIN")) {
-        ns_server_flushonshutdown(ns_g_server, ISC_FALSE);
-        isc_app_shutdown();
+    if (getenv("AFL_CMIN")) {
+        kea_shutdown();
+        /// @todo: What does this piece of code do?
+        /* ns_server_flushonshutdown(ns_g_server, ISC_FALSE);
+           isc_app_shutdown(); */
         return;
-        } */
+    }
 
     raise(SIGSTOP);
-    
+
     if (pthread_mutex_lock(&mutex) != 0) {
         cout << "#### unable to lock mutex" << endl;
     }
-    
+
     ready = true;
-    
+
     if (pthread_cond_signal(&cond) != 0) {
 
     }
-    
+
     if (pthread_mutex_unlock(&mutex) != 0) {
         cout << "Unable to unlock mutex" << endl;
     }
@@ -205,24 +249,24 @@ kea_fuzz_notify(void) {
 }
 
 void
-kea_fuzz_setup(void) {
+kea_fuzz_setup(volatile bool* shutdown) {
 #ifdef ENABLE_AFL
 
     /// @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) {
-            
+
         }
-        
+
         if (pthread_cond_init(&cond, NULL) == 0) {
 
         }
 
-        
-        if (pthread_create(&thread, NULL, kea_main_client, NULL) != 0) {
-            
+
+        if (pthread_create(&thread, NULL, kea_main_client, (void*)shutdown) != 0) {
+
         }
     }
 
index dcce8b27287ea30746e108de2210f278095794e1..98d9cdf047807f61105842006b0354ec4ec1f1f3 100644 (file)
@@ -13,7 +13,16 @@ extern "C" {
 
 void kea_fuzz_notify(void);
 
-void kea_fuzz_setup(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);
 
 };
 
diff --git a/src/bin/dhcp6/tests/fuzz-config/fuzz.json b/src/bin/dhcp6/tests/fuzz-config/fuzz.json
new file mode 100644 (file)
index 0000000..80d80b7
--- /dev/null
@@ -0,0 +1,61 @@
+# This is an example configuration file for DHCPv6 server in Kea.
+# It's a basic scenario with one IPv6 subnet configured. It is
+# assumed that one subnet (2001:db8:1::/64 is available directly
+# over ethX interface.
+
+{ "Dhcp6":
+
+{
+# Kea is told to listen on ethX interface only.
+  "interfaces-config": {
+    "interfaces": [ "eth0" ]
+  },
+
+# We need to specify the the database used to store leases. As of
+# September 2016, four database backends are supported: MySQL,
+# PostgreSQL, Cassandra, and the in-memory database, Memfile.
+# We'll use memfile  because it doesn't require any prior set up.
+  "lease-database": {
+    "type": "memfile"
+  },
+
+# Addresses will be assigned with preferred and valid lifetimes
+# being 3000 and 4000, respectively. Client is told to start
+# renewing after 1000 seconds. If the server does not respond
+# after 2000 seconds since the lease was granted, client is supposed
+# to start REBIND procedure (emergency renewal that allows switching
+# to a different server).
+  "preferred-lifetime": 3000,
+  "valid-lifetime": 4000,
+  "renew-timer": 1000,
+  "rebind-timer": 2000,
+
+# The following list defines subnets. Each subnet consists of at
+# least subnet and pool entries.
+  "subnet6": [
+    {
+      "pools": [ { "pool": "2001:db8:1::/80" } ],
+      "subnet": "2001:db8:1::/64",
+      "interface": "eth0"
+    }
+  ]
+},
+
+# The following configures logging. It assumes that messages with at least
+# informational level (info, warn, error and fatal) should be logged to stdout.
+"Logging": {
+    "loggers": [
+        {
+            "name": "kea-dhcp6",
+            "output_options": [
+                {
+                    "output": "/tmp/kea-fuzz.log"
+                }
+            ],
+            "debuglevel": 0,
+            "severity": "DEBUG"
+        }
+    ]
+}
+
+}