[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.