[0/6] batctl: tcpdump: Fix problems detected during fuzzing

Message ID 20240127-tcpdump_fuzzing-v1-0-fbc1e1d3fec1@narfation.org (mailing list archive)
Headers
Series batctl: tcpdump: Fix problems detected during fuzzing |

Message

Sven Eckelmann Jan. 27, 2024, 12:48 p.m. UTC
  While many parts of batctl are rather simple, tcpdump is one of the most
complex parts - which unfortunately is also dealing all the time
with potentially harmful input. It is therefore a good idea to perform
some tests to figure out how bad the current state of the code is. The
findings will be presented here - including some information how other
people can reproduce these problems.

With afl++, it is possible to fuzz batctl tcpdump and find parsing errors
(easier). But it needs an entry point to actually send data to. So for
simplicity, a fuzzme subcommand was added which just gets new data from
afl++ and then runs the main ethernet parsing function.

  diff --git a/split_pcap.py b/split_pcap.py
  new file mode 100755
  index 0000000000000000000000000000000000000000..11a1f5ce8ec60fac141693b0449d5c3955f9ad28
  --- /dev/null
  +++ b/split_pcap.py
  @@ -0,0 +1,21 @@
  +#!/usr/bin/env python3
  +
  +import sys
  +
  +from hashlib import sha256
  +from scapy.utils import rdpcap
  +
  +
  +def main():
  +    for pcap in sys.argv[1:]:
  +        packets = rdpcap(pcap)
  +        for packet in packets:
  +            m = sha256()
  +            m.update(packet.load)
  +            fname = m.hexdigest()
  +            with open(fname, "wb") as f:
  +                f.write(packet.load)
  +
  +
  +if __name__ == "__main__":
  +    main()
  diff --git a/tcpdump.c b/tcpdump.c
  index 5e7c76c69bd192d7485958aafabc0e9264b41b90..d340af986f99bdf2e8e6dae0d91a641bc80e82a2 100644
  --- a/tcpdump.c
  +++ b/tcpdump.c
  @@ -1556,3 +1556,41 @@ static int tcpdump(struct state *state __maybe_unused, int argc, char **argv)
   
   COMMAND(SUBCOMMAND, tcpdump, "td", 0, NULL,
   	"<interface>       \ttcpdump layer 2 traffic on the given interface");
  +
  +__AFL_FUZZ_INIT();
  +
  +static int fuzzme(struct state *state __maybe_unused, int argc, char **argv)
  +{
  +	dump_level = dump_level_all;
  +
  +#ifdef __AFL_HAVE_MANUAL_CONTROL
  +	__AFL_INIT();
  +#endif
  +
  +	unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
  +	while (__AFL_LOOP(10000)) {
  +		int len = __AFL_FUZZ_TESTCASE_LEN;
  +
  +		/* safety check from tcpdump */
  +		if ((size_t)len < sizeof(struct ether_header))
  +			continue;
  +
  +		/* move into new buffer to allow ASAN to detect invalid memory access */
  +		unsigned char *p = malloc(len);
  +		if (!p)
  +			continue;
  +
  +		memcpy(p, buf, len);
  +
  +		/* function under test */
  +		parse_eth_hdr(p, len, 0, 0);
  +
  +		/* drop buffer from asan */
  +		free(p);
  +	}
  +
  +	return 0;
  +}
  +
  +COMMAND(SUBCOMMAND, fuzzme, "fz", 0, NULL,

To build the fuzzing test, it is necessary to build batctl slightly
differently:

  make clean
  export AFL_USE_ASAN=1; CC=afl-clang-fast make V=s

And the some input files (containing raw ethernet fames have to be
generated from existing pcaps):

  mkdir in
  cd in
  ../split_pcap.py ~/wireshark-batman-adv/tests/*
  cd ..

And then multiple afl++ fuzzer instances can be started.

  if [ -z "${STY}" ]; then
      echo "must be started inside a screen session" >&2
      exit 1
  fi

  for i in $(seq 1 $(nproc)); do
      start_mode=-M
      [ "${i}" = "1" ] || start_mode=-S
      screen afl-fuzz "${start_mode}" "fuzzer${i}" -i in -o out ./batctl fuzzme
  done

The crashes can then be analyzed further by sending them to the fuzzme
subcommand:

   ./batctl fuzzme < out/fuzzer1/crashes/id:000000,sig:06,src:000528,time:12,execs:23992,op:havoc,rep:8

Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
Sven Eckelmann (6):
      batctl: tcpdump: Fix missing sanity check for batman-adv header
      batctl: tcpdump: Add missing throughput header length check
      batctl: tcpdump: Fix IPv4 header length check
      batctl: tcpdump: Add missing ICMPv6 Neighbor Advert length check
      batctl: tcpdump: Add missing ICMPv6 Neighbor Solicit length check
      batctl: tcpdump: Fix ICMPv4 inner IPv4 header length check

 tcpdump.c | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)
---
base-commit: a57de3183e67ec27cf96f1761e69d542e6dfac03
change-id: 20240127-tcpdump_fuzzing-736774906f60

Best regards,
  

Comments

Sven Eckelmann Jan. 27, 2024, 12:51 p.m. UTC | #1
On Saturday, 27 January 2024 13:48:58 CET Sven Eckelmann wrote:
> While many parts of batctl are rather simple, tcpdump is one of the most
> complex parts - which unfortunately is also dealing all the time
> with potentially harmful input. It is therefore a good idea to perform
> some tests to figure out how bad the current state of the code is. The
> findings will be presented here - including some information how other
> people can reproduce these problems.

Attached are also the actual reproducers.

Kind regards,
	Sven