Skip to content

Commit ccdc47b

Browse files
committed
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: systemd/systemd#12252 (comment) systemd/systemd#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<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) (/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 <evvers@ya.ru>
1 parent db85c0e commit ccdc47b

File tree

4 files changed

+70
-0
lines changed

4 files changed

+70
-0
lines changed

configure.ac

+7
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,13 @@ AS_IF([test "x$enable_ubsan" = xyes], [
189189
])
190190
AC_SUBST([UBSAN_LDFLAGS])
191191

192+
AC_ARG_ENABLE([fuzzing-engine],
193+
AS_HELP_STRING([--enable-fuzzing-engine], [compile with fuzzing engine]),
194+
[], [enable_fuzzing_engine=no]
195+
)
196+
AC_PROG_CXX
197+
AM_CONDITIONAL([FUZZING_ENGINE], [test x$enable_fuzzing_engine = xyes])
198+
192199
dnl libtool-2
193200
LT_INIT
194201

libmount/src/Makemodule.am

+13
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,19 @@ test_mount_debug_CFLAGS = $(libmount_tests_cflags)
154154
test_mount_debug_LDFLAGS = $(libmount_tests_ldflags)
155155
test_mount_debug_LDADD = $(libmount_tests_ldadd)
156156

157+
if FUZZING_ENGINE
158+
check_PROGRAMS += test_mount_fuzz
159+
160+
test_mount_fuzz_SOURCES = libmount/src/fuzz.c
161+
162+
# https://google.github.io/oss-fuzz/getting-started/new-project-guide/#Requirements
163+
nodist_EXTRA_test_mount_fuzz_SOURCES = dummy.cxx
164+
165+
test_mount_fuzz_CFLAGS = $(libmount_tests_cflags)
166+
test_mount_fuzz_LDFLAGS = $(libmount_tests_ldflags)
167+
test_mount_fuzz_LDADD = $(libmount_tests_ldadd) $(LIB_FUZZING_ENGINE)
168+
endif
169+
157170
endif # BUILD_LIBMOUNT_TESTS
158171

159172

libmount/src/fuzz.c

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "mountP.h"
2+
3+
#include <stddef.h>
4+
#include <stdint.h>
5+
6+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
7+
struct libmnt_table *tb = NULL;
8+
FILE *f = NULL;
9+
10+
if (size == 0)
11+
return 0;
12+
13+
tb = mnt_new_table();
14+
assert(tb);
15+
16+
f = fmemopen((char*) data, size, "re");
17+
assert(f);
18+
19+
(void) mnt_table_parse_stream(tb, f, "mountinfo");
20+
21+
mnt_unref_table(tb);
22+
fclose(f);
23+
24+
return 0;
25+
}

tools/oss-fuzz.sh

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env bash
2+
3+
set -ex
4+
5+
export LC_CTYPE=C.UTF-8
6+
7+
export CC=${CC:-clang}
8+
export CXX=${CXX:-clang++}
9+
export LIB_FUZZING_ENGINE=${LIB_FUZZING_ENGINE:--fsanitize=fuzzer}
10+
11+
SANITIZER=${SANITIZER:-address -fsanitize-address-use-after-scope}
12+
flags="-O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=$SANITIZER -fsanitize=fuzzer-no-link"
13+
14+
export CFLAGS=${CFLAGS:-$flags}
15+
export CXXFLAGS=${CXXFLAGS:-$flags}
16+
17+
export OUT=${OUT:-$(pwd)/out}
18+
mkdir -p $OUT
19+
20+
./autogen.sh
21+
./configure --disable-all-programs --enable-fuzzing-engine --enable-libmount --enable-libblkid
22+
make -j$(nproc) V=1 check-programs
23+
24+
find . -maxdepth 1 -type f -executable -name "test_*_fuzz" -exec mv {} $OUT \;
25+
find . -type f -name "fuzz-*.dict" -exec cp {} $OUT \;

0 commit comments

Comments
 (0)