3. Set up path to AFL binaries
- EXPORT AFL_PATH=/home/thomson/devel/afl-2.35b
- EXPORT PATH=$PATH:/home/thomson/devel/afl-2.35b
+ export AFL_PATH=/home/thomson/devel/afl-2.35b
+ export PATH=$PATH:/home/thomson/devel/afl-2.35b
4. Build Kea using AFL
git pull
git checkout experiments/fuzz
autoreconf -i
- CXX=afl-clang-fast++ ./configure --enable-fuzz
+ CXX=afl-clang-fast++ ./configure --enable-fuzz --enable-static-link
make
Note: no unit-tests needed. We will be fuzzing the
production code only.
-5. Run fuzzer
+5. Configure destination address
The defaults (see src/bin/dhcp6/fuzz.cc) are:
interface: eth0
E.g.
export KEA_AFL_INTERFACE=eth1
-
+6. Run fuzzer
+
+ Set up max size of a virtual memory allowed to 4GB:
+ ulimit -v 4096000
+
+ 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
+
+ Here's what the switches do:
+ -m 4096 - allow Kea to take up to 4GB memory
+ -i tests/fuzz-data - Input seeds. These are the packet files used
+ to initiate the packet randomization. Several examples are in
+ src/bin/dhcp6/tests/fuzz-data. You can extract them using wireshark,
+ right click on a packet, then export as binary data. Make sure you
+ export the payload of UDP content. the first exported byte should
+ by message-type.
+ -o dir - that's the output directory. It doesn't have to exist.
+
+7. Checking that the fuzzer is really working
+
+ a) the harness prints out a line to /tmp/kea-fuzz-harness.txt every
+ time a new packet is sent. This generated 4,5MB of entries in 20
+ minutes. Obviously, this has to be disabled for production fuzzing,
+ but it's good for initial trials.
+
+ 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.
#include <dhcp/dhcp6.h>
#include <iostream>
+#include <fstream>
#include <stdlib.h>
#include <string.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
string dst(ALL_DHCP_RELAY_AGENTS_AND_SERVERS);
string port("547");
+ ofstream f("/tmp/kea-fuzz-harness.txt", ios::ate);
+
const char *iface_ptr = getenv("KEA_AFL_INTERFACE");
if (iface_ptr) {
iface = string(iface_ptr);
unsigned int iface_id = if_nametoindex(iface.c_str());
- cout << "Kea AFL setup:" << endl;
- cout << "Interface: " << iface << endl;
- cout << "Interface index: " << iface_id << endl;
- cout << "UDP destination addr: " << dst << endl;
- cout << "UDP destination port: " << port << endl;
+ 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) {
- cout << "Error: inet_pton() failed: can't convert " << dst
- << " to address." << endl;
+ f << "Error: inet_pton() failed: can't convert " << dst
+ << " to address." << endl;
exit(EXIT_FAILURE);
}
servaddr.sin6_port = htons(547);
sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sockfd < 0) {
- cout << "Failed to create UDP6 socket" << endl;
+ f << "Failed to create UDP6 socket" << endl;
exit(EXIT_FAILURE);
}
buf = malloc(65536);
if (!buf) {
- cout << "Failed to allocate a buffer" << endl;
+ f << "Failed to allocate a buffer" << endl;
exit(EXIT_FAILURE);
}
} */
if (pthread_mutex_lock(&mutex) != 0) {
- cout << "#### Failed to lock mutex" << endl;
+ f << "#### Failed to lock mutex" << endl;
}
ready = false;
ssize_t sent;
- cout << "Sending " << length << " bytes to " << dst << "/" << port
- << " over " << iface << "/" << iface_id << endl;
+ f << "Sending " << length << " bytes to " << dst << "/" << port
+ << " over " << iface << "/" << iface_id << endl;
sent = sendto(sockfd, buf, length, 0,
(struct sockaddr *) &servaddr, sizeof(servaddr));
if (sent != length) {
- cout << "#### Error: expected to send " << length
- << ", but really sent " << sent << endl;
+ f << "#### Error: expected to send " << length
+ << ", but really sent " << sent << endl;
}
/* unclog */
pthread_cond_wait(&cond, &mutex);
if (pthread_mutex_unlock(&mutex) != 0) {
- cout << "#### Failed to unlock mutex" << endl;
+ f << "#### Failed to unlock mutex" << endl;
}
}