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
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.
#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
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
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) {
}
unsigned int iface_id = if_nametoindex(iface.c_str());
-
+
f << "Kea AFL setup:" << endl;
f << "Interface: " << iface << endl;
f << "Interface index: " << iface_id << endl;
exit(EXIT_FAILURE);
}
- loop = 100000;
+ time_t t;
+
+ loop = LOOP_COUNT;
while (loop--) {
ssize_t length;
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));
}
}
+ 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
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;
}
}
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) {
+
}
}
--- /dev/null
+# 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"
+ }
+ ]
+}
+
+}