From: Evgeny Vereshchagin Date: Sat, 11 Apr 2020 13:25:26 +0000 (+0000) Subject: tests: add a fuzzer for mnt_table_parse_stream X-Git-Tag: v2.37-rc1~527^2~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ccdc47b7f57b323633d49e416117cfdd3f80f9ad;p=thirdparty%2Futil-linux.git tests: add a fuzzer for mnt_table_parse_stream The fuzzer is supposed to cover `mnt_table_parse_stream`, which is used by systemd to parse /proc/self/mountinfo. The systemd project has run into memory leaks there at least twice: https://github.com/systemd/systemd/pull/12252#issuecomment-482804040 https://github.com/systemd/systemd/issues/8504 so it seems to be a good idea to continuously fuzz that particular function. The patch can be tested locally by installing clang and running ./tools/oss-fuzz.sh. Currently the fuzzer is failing with ``` ================================================================= ==96638==ERROR: LeakSanitizer: detected memory leaks Direct leak of 216 byte(s) in 1 object(s) allocated from: #0 0x50cd77 in calloc (/home/vagrant/util-linux/out/test_mount_fuzz+0x50cd77) #1 0x58716a in mnt_new_fs /home/vagrant/util-linux/libmount/src/fs.c:36:25 #2 0x54f224 in __table_parse_stream /home/vagrant/util-linux/libmount/src/tab_parse.c:728:9 #3 0x54eed8 in mnt_table_parse_stream /home/vagrant/util-linux/libmount/src/tab_parse.c:804:8 #4 0x5448b2 in LLVMFuzzerTestOneInput /home/vagrant/util-linux/libmount/src/fuzz.c:19:16 #5 0x44cc88 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/vagrant/util-linux/out/test_mount_fuzz+0x44cc88) #6 0x44d8b0 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) (/home/vagrant/util-linux/out/test_mount_fuzz+0x44d8b0) #7 0x44e270 in fuzzer::Fuzzer::MutateAndTestOne() (/home/vagrant/util-linux/out/test_mount_fuzz+0x44e270) #8 0x450617 in fuzzer::Fuzzer::Loop(std::vector >&) (/home/vagrant/util-linux/out/test_mount_fuzz+0x450617) #9 0x43adbb in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/vagrant/util-linux/out/test_mount_fuzz+0x43adbb) #10 0x42ad46 in main (/home/vagrant/util-linux/out/test_mount_fuzz+0x42ad46) #11 0x7fa084f621a2 in __libc_start_main (/lib64/libc.so.6+0x271a2) SUMMARY: AddressSanitizer: 216 byte(s) leaked in 1 allocation(s). INFO: to ignore leaks on libFuzzer side use -detect_leaks=0. ``` Once the bug is fixed and the OSS-Fuzz counterpart is merged it should be possible to turn on CIFuzz to make sure the fuzz target can be built and run for some time without crashing: https://google.github.io/oss-fuzz/getting-started/continuous-integration/ Signed-off-by: Evgeny Vereshchagin --- diff --git a/configure.ac b/configure.ac index 97f404f929..8815d270b8 100644 --- a/configure.ac +++ b/configure.ac @@ -189,6 +189,13 @@ AS_IF([test "x$enable_ubsan" = xyes], [ ]) AC_SUBST([UBSAN_LDFLAGS]) +AC_ARG_ENABLE([fuzzing-engine], + AS_HELP_STRING([--enable-fuzzing-engine], [compile with fuzzing engine]), + [], [enable_fuzzing_engine=no] +) +AC_PROG_CXX +AM_CONDITIONAL([FUZZING_ENGINE], [test x$enable_fuzzing_engine = xyes]) + dnl libtool-2 LT_INIT diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am index eaa69c135e..32fdd3f24b 100644 --- a/libmount/src/Makemodule.am +++ b/libmount/src/Makemodule.am @@ -154,6 +154,19 @@ test_mount_debug_CFLAGS = $(libmount_tests_cflags) test_mount_debug_LDFLAGS = $(libmount_tests_ldflags) test_mount_debug_LDADD = $(libmount_tests_ldadd) +if FUZZING_ENGINE +check_PROGRAMS += test_mount_fuzz + +test_mount_fuzz_SOURCES = libmount/src/fuzz.c + +# https://google.github.io/oss-fuzz/getting-started/new-project-guide/#Requirements +nodist_EXTRA_test_mount_fuzz_SOURCES = dummy.cxx + +test_mount_fuzz_CFLAGS = $(libmount_tests_cflags) +test_mount_fuzz_LDFLAGS = $(libmount_tests_ldflags) +test_mount_fuzz_LDADD = $(libmount_tests_ldadd) $(LIB_FUZZING_ENGINE) +endif + endif # BUILD_LIBMOUNT_TESTS diff --git a/libmount/src/fuzz.c b/libmount/src/fuzz.c new file mode 100644 index 0000000000..7363e2bd98 --- /dev/null +++ b/libmount/src/fuzz.c @@ -0,0 +1,25 @@ +#include "mountP.h" + +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + struct libmnt_table *tb = NULL; + FILE *f = NULL; + + if (size == 0) + return 0; + + tb = mnt_new_table(); + assert(tb); + + f = fmemopen((char*) data, size, "re"); + assert(f); + + (void) mnt_table_parse_stream(tb, f, "mountinfo"); + + mnt_unref_table(tb); + fclose(f); + + return 0; +} diff --git a/tools/oss-fuzz.sh b/tools/oss-fuzz.sh new file mode 100755 index 0000000000..60aeb3b598 --- /dev/null +++ b/tools/oss-fuzz.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -ex + +export LC_CTYPE=C.UTF-8 + +export CC=${CC:-clang} +export CXX=${CXX:-clang++} +export LIB_FUZZING_ENGINE=${LIB_FUZZING_ENGINE:--fsanitize=fuzzer} + +SANITIZER=${SANITIZER:-address -fsanitize-address-use-after-scope} +flags="-O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=$SANITIZER -fsanitize=fuzzer-no-link" + +export CFLAGS=${CFLAGS:-$flags} +export CXXFLAGS=${CXXFLAGS:-$flags} + +export OUT=${OUT:-$(pwd)/out} +mkdir -p $OUT + +./autogen.sh +./configure --disable-all-programs --enable-fuzzing-engine --enable-libmount --enable-libblkid +make -j$(nproc) V=1 check-programs + +find . -maxdepth 1 -type f -executable -name "test_*_fuzz" -exec mv {} $OUT \; +find . -type f -name "fuzz-*.dict" -exec cp {} $OUT \;