[PATCH] scripts/oss-fuzz: build PCRE2 from source with sanitizer instrumentation
Petr Matyas <[email protected]>
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <[email protected]> |
The selabel_file fuzzers link against the system libpcre2, which is not instrumented when building with -fsanitize=memory. MSan requires all libraries to be instrumented; uninstrumented libraries can produce false positives because their writes do not update the sanitizer's shadow memory. In practice this causes a spurious use-of-uninitialized-value report: pcre2_compile() writes literal character bytes via direct assignment (not through memset/memcpy), so MSan's shadow memory does not reflect those writes. pcre2_jit_compile() then calls memcmp() in detect_repeat() over compiled bytecode containing those character bytes, and MSan flags the comparison as reading uninitialized memory. The PCRE2 maintainers confirmed this is a false positive per MSan documentation and declined to change the library [1]. Fix by building PCRE2 from source with the same -fsanitize= flags as the rest of the fuzzer build. With instrumentation, all pcre2_compile() writes are tracked, detect_repeat()'s memcmp() sees properly initialized bytes, and the false positive disappears. Both selabel_file fuzzers are now linked against the resulting static libpcre2-8.a from DESTDIR instead of the system shared library. [1] https://github.com/KwisatzHaderach/pcre2/pull/1 Signed-off-by: Petr Matyas <[email protected]> --- scripts/oss-fuzz.sh | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/scripts/oss-fuzz.sh b/scripts/oss-fuzz.sh index 08e06975..57ac5c2d 100755 --- a/scripts/oss-fuzz.sh +++ b/scripts/oss-fuzz.sh @@ -43,6 +43,30 @@ mkdir -p "$OUT" export LIB_FUZZING_ENGINE=${LIB_FUZZING_ENGINE:--fsanitize=fuzzer} rm -rf "$DESTDIR" + +## Build PCRE2 from source so it is instrumented with the same sanitizer +## as the fuzzer targets. Using the system libpcre2 (uninstrumented) causes +## MSan to report use-of-uninitialized-value false positives: pcre2_compile() +## writes character bytes via direct assignment that the sanitizer cannot +## track in uninstrumented code, so pcre2_jit_compile()'s memcmp()-based +## repeat-detection reads them as "uninitialized". Building from source +## with the same -fsanitize= flags ensures all writes are properly tracked. +PCRE2_SRC=/tmp/pcre2-src +if [ ! -d "$PCRE2_SRC" ]; then + git clone --depth 1 https://github.com/PCRE2Project/pcre2.git "$PCRE2_SRC" + git -C "$PCRE2_SRC" submodule update --init +fi +cmake -S "$PCRE2_SRC" -B "$PCRE2_SRC/build" \ + -DCMAKE_C_COMPILER="$CC" \ + -DCMAKE_C_FLAGS="$flags" \ + -DPCRE2_SUPPORT_JIT=ON \ + -DPCRE2_BUILD_TESTS=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_INSTALL_LIBDIR=lib +cmake --build "$PCRE2_SRC/build" -j"$(nproc)" +cmake --install "$PCRE2_SRC/build" + make -C libsepol clean make -C libselinux clean # LIBSO and LIBMAP shouldn't be expanded here because their values are unknown until Makefile @@ -106,7 +130,7 @@ cp checkpolicy/fuzz/checkpolicy-fuzzer.dict "$OUT/" # shellcheck disable=SC2086 $CC $CFLAGS -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8 -c -o selabel_file_text-fuzzer.o libselinux/fuzz/selabel_file_text-fuzzer.c # shellcheck disable=SC2086 -$CXX $CXXFLAGS $LIB_FUZZING_ENGINE selabel_file_text-fuzzer.o "$DESTDIR/usr/lib/libselinux.a" -lpcre2-8 -o "$OUT/selabel_file_text-fuzzer" +$CXX $CXXFLAGS $LIB_FUZZING_ENGINE selabel_file_text-fuzzer.o "$DESTDIR/usr/lib/libselinux.a" "$DESTDIR/usr/lib/libpcre2-8.a" -o "$OUT/selabel_file_text-fuzzer" zip -j "$OUT/selabel_file_text-fuzzer_seed_corpus.zip" libselinux/fuzz/input @@ -117,6 +141,6 @@ zip -j "$OUT/selabel_file_text-fuzzer_seed_corpus.zip" libselinux/fuzz/input # shellcheck disable=SC2086 $CC $CFLAGS -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8 -c -o selabel_file_compiled-fuzzer.o libselinux/fuzz/selabel_file_compiled-fuzzer.c # shellcheck disable=SC2086 -$CXX $CXXFLAGS $LIB_FUZZING_ENGINE selabel_file_compiled-fuzzer.o "$DESTDIR/usr/lib/libselinux.a" -lpcre2-8 -o "$OUT/selabel_file_compiled-fuzzer" +$CXX $CXXFLAGS $LIB_FUZZING_ENGINE selabel_file_compiled-fuzzer.o "$DESTDIR/usr/lib/libselinux.a" "$DESTDIR/usr/lib/libpcre2-8.a" -o "$OUT/selabel_file_compiled-fuzzer" zip -j "$OUT/selabel_file_compiled-fuzzer_seed_corpus.zip" libselinux/fuzz/input -- 2.55.0