[tor-dev] Fuzzing tor_inet_pton(): A fuzzing example

Nick Mathewson nickm at torproject.org
Wed Jul 5 19:19:43 UTC 2017

So, there was a bug report of an assertion failure in
tor_inet_pton(), and I wanted to track it down.  Here's my
reconstruction of my process, in case it helps anybody else
write fuzzing code.

First, I wrote a new fuzzing target in src/test/fuzz/fuzz_pton.c:

#include "orconfig.h"
#include "or.h"

#include "fuzzing.h"

  return 0;
  return 0;

fuzz_main(const uint8_t *stdin_buf, size_t data_size)
  struct in_addr *in = tor_malloc(sizeof(*in));
  struct in6_addr *in6 = tor_malloc(sizeof(*in6));
  char *cp = tor_memdup_nulterm(stdin_buf, data_size);
  int in_ok = tor_inet_pton(AF_INET, cp, in);
  int in6_ok = tor_inet_pton(AF_INET6, cp, in6);
  log_info(LD_GENERAL, "%d %d", in_ok, in6_ok);
  return 0;

  * The init and cleanup functions don't have anything to do above, but
    the test harness in fuzzing_common.c expects to find them.
  * This fuzzer tries to parse each address twice: first as an IPv4
    address, then as an IPv6 address.
  * The fuzzer puts its outputs into heap-allocated RAM to improve the
    odds that any bugs will get caught by asan, though this shouldn't
    really be necessary.
  * Because tor_inet_pton() takes a nul-terminated string, this fuzzer
    nul-term inates its input.  You shouldn't do that unless you're
    fuzing a function that requires nul-terminated inputs.

Next, I edited the script in scripts/codegen/fuzzing_include_am.py to
add "pton" to the "FUZZERS" list at the top of the file, and I re-ran
the script and used its output to replace src/test/fuzz/include.am, so
that our build system can know about the new fuzzer.

I knew I would need a corpus of pton examples, so I started one in
fuzzing-corpora (fuzzing-corpora is a separate repository).  I made a
new "pton" directory there, and filled it with 4 or 5 examples of things
that looked like they might be addresses.  I chose:

Each example went into its own file, without a terminating newline.

I tried the fuzzing corpora examples out with the fuzzing program,
to make sure that I got the expected results

$ ./src/test/fuzz/fuzz-pton --info < ../tor-fuzz-corpora/pton/b
Jul 05 15:00:56.371 [info] fuzz_main(): 1 0

===== AFL

Then I re-built Tor for use with AFL:
   ./configure CC=afl-gcc --enable-fragile-hardening
   make clean
   AFL_HARDEN=1 make fuzzers

To fuzz it, I started by telling afl-fuzz to run with no memory limit,
writing results to pton-output, taking inputs from the corpus:

  afl-fuzz  -i ../tor-fuzz-corpora/pton -o ./pton-output/ -m none \
      -- ./src/test/fuzz/fuzz-pton

AFL wound up complaining about some kernel settings, so I had to do this
as root.  YMMV.  AFL told me to do this:

   echo core >/proc/sys/kernel/core_pattern
   cd /sys/devices/system/cpu
   echo performance | tee cpu*/cpufreq/scaling_governor

Then AFL started running!

I watched the "total paths" value climb.  That's how many different
distinct paths through the code that the fuzzer was able to find.  I
didn't see any "uniq crashes" or "uniq hangs" values, so I knew the
fuzzer hadn't found anything.

===== Libfuzzer

After that had run for a day, I stopped it and tried again with libfuzzer:

     ./configure --enable-libfuzzer CC=/home/nickm/build/llvm-build/bin/clang
     make clean
     make fuzzers

Obviously, you'll need to point CC to your own clang here.  I wasn't
able to use the system clang because libfuzzer needs features I didn't

Then I made a new file for the libfuzzer results, and ran libfuzzer
using the original corpus and the output from AFL:
   mkdir pton-output-libfuzzer
   ./src/test/fuzz/lf-fuzz-pton pton-output-libfuzzer/ \
        ./pton-output/queue/ ../tor-fuzz-corpora/pton/

And libfuzzer began giving results.  Every "NEW" line was a new path;
every "pulse" line meant that time had passed but no new paths were

More information about the tor-dev mailing list