[EXAMPLE] How to add a source3 fuzz target

Jeremy Allison jra at samba.org
Mon Jan 13 21:38:41 UTC 2020


On Sun, Jan 12, 2020 at 11:00:06PM +1300, Douglas Bagnall via samba-technical wrote:
> Maybe you are a Samba developer who has noticed some activity around
> automated fuzzing, but you haven't really got your head around how to
> add a fuzz target in your subdomain. This message is meant to show you
> how easy it is. So easy, in fact, that you might prefer to skip to the
> attached patch.
> 
> My process for finding this target was:
> 
> 1. `git grep parse_ -- source3`.
> 
> 2. look for a function that looks like it
>    a. does a bit of work,
>    b. probably deals with untrusted data,
>    c. is not enmeshed in a whole lot of state.
> 
> So already with point 1, you know that YOU can do better.
> 
> For point 2, I saw this parse_packet() was filling out nested
> structures using a tree of function calls (that's 2a), has a networky
> sounding name (2b), and there is no context pointer involved (2c). (If
> there was a context pointer, that would be OK if we could create the
> context afresh every time, or if it wasn't really modified).
> 
> With the target selected, you make a file in lib/fuzzing with a
> function called LLVMFuzzerTestOneInput(). That is libfuzzer's entry
> point. LLVMFuzzerTestOneInput() essentially takes a datablob and
> returns 0 (always 0 -- you report errors with abort()). This is
> sort of enough to fuzz nmblib's parse_packet:
> 
>   int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
>   {
>           struct packet_struct *p = NULL;
>           struct in_addr ip = {
>                   0x0100007f /* 127.0.0.1 */
>           };
> 
>           p = parse_packet((char *)input,
>                            len,
>                            NMB_PACKET,
>                            ip,
>                            1234);
>           return 0;
>   }
> 
> but that's a bit useless. It [hopefully] tells us that parse_packet()
> doesn't crash, but it doesn't warn us if it is returning deadly
> structures. So we add in a round trip using build_packet() and a test
> to ensure p->packet.nmb.question.question_name.name exists, which I
> think something somewhere assumes is true. Anybody who knew anything
> about nmb packets could add more checks, which they would do by
> straight out doing the thing that might crash, not by making careful
> assertions.
> 
> To compile it we add a stanza to wscript_build using the standard mix
> of copy, paste, trial, error, and guesswork. Then you need to compile
> it differently. What I use is a wrapper around libfuzzer and compilers
> called Honggfuzz. The steps to get it are something like:
> 
> $  git clone git at github.com:google/honggfuzz.git
> $  cd honggfuzz
> $  make
> 
> then back in samba, you need a fancy configure line:
> 
> $  rm -r bin
> $  buildtools/bin/waf -C \
>                 --without-gettext \
>                 --enable-debug \
>                 --enable-developer \
>                 --enable-libfuzzer \
>                 CC=$PATH_TO_HONGGFUZZ/hfuzz_cc/hfuzz-clang \
>                 configure \
>                 LINK_CC=$PATH_TO_HONGGFUZZ/hfuzz_cc/hfuzz-clang \
>                 --disable-warnings-as-errors  \
>                 --abi-check-disable
> $  make -j
> 
> Maybe not all of those options are necessary, but at some point they
> were each for something. I think at least you'll need
> '--enable-libfuzzer CC=...'.
> 
> Then run it:
> 
> $  mkdir nmb_parse_seeds
> $  $PATH_TO_HONGGFUZZ/honggfuzz  -V -T -F 50000 \
>           -i nmb_parse_seeds \
>           -- bin/fuzz_nmblib_parse_packet
> 
> This will create fuzz packets based on the the examples in
> ./nmb_parse_seeds, of which there are initially none. It will mutate
> and add to these (initially mutating the empty string), trying to find
> packets that lead to new code pathways. While it doing this it shows
> you how it's going on a console dashboard. If a packet causes a crash
> or abort (or with -T, a timeout), it saves that packet in a weirdly
> named file and writes a report in (by default) HONGGFUZZ_REPORT.TXT.
> 
> To replay a packet in gdb or valgrind, you just do this:
> 
> $  gdb --args ./bin/fuzz_nmblib_parse_packet $the_file_name
> 
> and the problem should become apparent.
> 
> Needless to say, I have found no crashes with this particular patch,
> and I suspect it is not actually a very good target. But perhaps it is
> an excellent target and we just happen to have very good code!

Thanks Douglas, this is a *really* helpful guide - much appreciated !

nmblib_parse_packet is old code that has been kicked *very hard*
over the years, so I'm hoping it's just good code now :-).

Jeremy.



More information about the samba-technical mailing list