fuzz: Add fuzzing for core and i2c
Add fuzzing infrastructure and a fuzz target handling mctp-i2c packets.
After running for a few days with honggfuzz this achieves close to
complete line coverage of core.c
Change-Id: I6cd7361e6f600831a319f06fb7c7c0d2186fd7de
Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
diff --git a/tests/fuzz/fuzz-build.py b/tests/fuzz/fuzz-build.py
new file mode 100755
index 0000000..82edfb1
--- /dev/null
+++ b/tests/fuzz/fuzz-build.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+# Builds fuzzing variants. Run this from the toplevel directory.
+# Beware this will wipe build directories.
+
+# Requires honggfuzz and afl++ installed
+
+# Builds are:
+# * AFL (normal, asan, cmplog)
+# * honggfuzz (asan, msan, ubsan)
+# * -O0, with coverage
+
+import os
+import subprocess
+
+# reduce warning level since tests since gtest is noisy
+BASE_MESONFLAGS = "-Dwarning_level=2 -Ddefault_library=static --wipe".split()
+FUZZ_PROGRAMS = ["tests/fuzz/i2c-fuzz"]
+
+
+def build(
+ build_dir: str,
+ cc: str = None,
+ cxx: str = None,
+ cflags="",
+ cxxflags="",
+ opt="3",
+ env={},
+ mesonflags=[],
+):
+ env = os.environ | env
+ env["CFLAGS"] = cflags
+ env["CXXFLAGS"] = cxxflags
+
+ # Meson sets CC="ccache cc" by default, but ccache removes -fprofile-arcs
+ # so coverage breaks (ccache #1531). Prevent that by setting CC/CXX.
+ env["CC"] = cc if cc else "cc"
+ env["CXX"] = cxx if cxx else "c++"
+
+ meson_cmd = ["meson"] + BASE_MESONFLAGS + mesonflags
+ meson_cmd += [f"-Doptimization={opt}"]
+ meson_cmd += [build_dir]
+ subprocess.run(meson_cmd, env=env, check=True)
+
+ ninja_cmd = ["ninja", "-C", build_dir] + FUZZ_PROGRAMS
+ subprocess.run(ninja_cmd, env=env, check=True)
+
+
+def build_afl():
+ env = {
+ # seems to be required for afl-clang-lto?
+ "AFL_REAL_LD": "ld.lld",
+ }
+ cc = "afl-clang-lto"
+ cxx = "afl-clang-lto++"
+
+ # normal
+ build("bfuzz", cc=cc, cxx=cxx, env=env)
+ # ASAN
+ build(
+ "bfuzzasan",
+ cc=cc,
+ cxx=cxx,
+ mesonflags=["-Db_sanitize=address"],
+ env=env,
+ )
+ # cmplog
+ build("bcmplog", cc=cc, cxx=cxx, env={"AFL_LLVM_CMPLOG": "1"} | env)
+
+
+def main():
+ # No profiling, has coverage
+ build(
+ "bnoopt",
+ cflags="-fprofile-abs-path",
+ cxxflags="-fprofile-abs-path",
+ opt="0",
+ mesonflags=["-Db_coverage=true"],
+ )
+
+ # AFL
+ build_afl()
+
+ # Honggfuzz
+ # asan by default
+ build(
+ "bhf",
+ cc="hfuzz-clang",
+ cxx="hfuzz-clang++",
+ env={"HFUZZ_CC_ASAN": "1"},
+ )
+ # msan
+ build(
+ "bhf-msan",
+ cc="hfuzz-clang",
+ cxx="hfuzz-clang++",
+ env={"HFUZZ_CC_MSAN": "1"},
+ )
+ # ubsan
+ build(
+ "bhf-ubsan",
+ cc="hfuzz-clang",
+ cxx="hfuzz-clang++",
+ env={"HFUZZ_CC_UBSAN": "1"},
+ )
+
+
+if __name__ == "__main__":
+ main()