From: Sven Eckelmann <sven@narfation.org>
To: b.a.t.m.a.n@lists.open-mesh.org
Cc: Sven Eckelmann <sven@narfation.org>,
Marco Dalla Torre <marco.dallato@gmail.com>
Subject: [PATCH 0/6] batctl: tcpdump: Fix problems detected during fuzzing
Date: Sat, 27 Jan 2024 13:48:58 +0100 [thread overview]
Message-ID: <20240127-tcpdump_fuzzing-v1-0-fbc1e1d3fec1@narfation.org> (raw)
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,
--
Sven Eckelmann <sven@narfation.org>
next reply other threads:[~2024-01-27 12:49 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-27 12:48 Sven Eckelmann [this message]
2024-01-27 12:48 ` [PATCH 1/6] batctl: tcpdump: Fix missing sanity check for batman-adv header Sven Eckelmann
2024-01-27 12:49 ` [PATCH 2/6] batctl: tcpdump: Add missing throughput header length check Sven Eckelmann
2024-01-27 12:49 ` [PATCH 3/6] batctl: tcpdump: Fix IPv4 " Sven Eckelmann
2024-01-27 12:49 ` [PATCH 4/6] batctl: tcpdump: Add missing ICMPv6 Neighbor Advert " Sven Eckelmann
2024-01-27 12:49 ` [PATCH 5/6] batctl: tcpdump: Add missing ICMPv6 Neighbor Solicit " Sven Eckelmann
2024-01-27 12:49 ` [PATCH 6/6] batctl: tcpdump: Fix ICMPv4 inner IPv4 header " Sven Eckelmann
2024-01-27 12:51 ` [PATCH 0/6] batctl: tcpdump: Fix problems detected during fuzzing Sven Eckelmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240127-tcpdump_fuzzing-v1-0-fbc1e1d3fec1@narfation.org \
--to=sven@narfation.org \
--cc=b.a.t.m.a.n@lists.open-mesh.org \
--cc=marco.dallato@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).