diff --git a/projects/cpython3/Dockerfile b/projects/cpython3/Dockerfile index ab3038fa1e09..50ae927fdca8 100644 --- a/projects/cpython3/Dockerfile +++ b/projects/cpython3/Dockerfile @@ -18,8 +18,10 @@ FROM gcr.io/oss-fuzz-base/base-builder RUN apt-get update && \ apt-get install -y build-essential libncursesw5-dev \ libreadline-dev libssl-dev libgdbm-dev \ - libc6-dev libsqlite3-dev tk-dev libbz2-dev \ - zlib1g-dev libffi-dev + libc6-dev libsqlite3-dev libbz2-dev \ + zlib1g-dev libffi-dev libmpdec-dev \ + liblzma-dev libzstd-dev uuid-dev \ + libgdbm-compat-dev RUN git clone https://github.com/python/cpython.git cpython3 WORKDIR cpython3 diff --git a/projects/cpython3/build.sh b/projects/cpython3/build.sh index 022c851feec2..7fbf07d3bcb2 100644 --- a/projects/cpython3/build.sh +++ b/projects/cpython3/build.sh @@ -30,7 +30,12 @@ CFLAGS="${CFLAGS} -UNDEBUG" # We use some internal CPython API. CFLAGS="${CFLAGS} -IInclude/internal/" +# Build all stdlib C extension modules statically into libpython +# rather than as shared .so files, so they are linked into the fuzzers. +export MODULE_BUILDTYPE=static + FLAGS=() +FLAGS+=("--disable-test-modules") case $SANITIZER in address) FLAGS+=("--with-address-sanitizer") @@ -49,19 +54,41 @@ case $SANITIZER in esac ./configure "${FLAGS[@]:-}" --prefix $OUT +# When building modules statically, HACL* crypto object files must be linked +# via static archives (.a) instead of raw .o files to avoid duplicate symbols +# across _blake2, _sha*, _hmac modules that share HACL* objects. +# Only patch the MODULE_ dependency lines, not the LIBHACL variable definitions. +sed -i '/^MODULE__/s/LIB_SHARED/LIB_STATIC/g' Makefile + # We use altinstall to avoid having the Makefile create symlinks make -j$(nproc) altinstall +# When modules are statically linked into libpython, the fuzzer binaries +# need the system libraries that those modules depend on (e.g. -lsqlite3, +# -lz, -lssl). These are tracked in the Makefile's MODLIBS variable but +# are not included by python-config --ldflags. +PYTHON=$(ls $OUT/bin/python3.* | grep -v config | head -1) +MODLIBS=$($PYTHON -c "import sysconfig; print(sysconfig.get_config_var('MODLIBS'))") + FUZZ_DIR=Modules/_xxtestfuzz for fuzz_test in $(cat $FUZZ_DIR/fuzz_tests.txt) do + # Template fuzzers have their own .c file; original targets use fuzzer.c + if [ -f "$FUZZ_DIR/${fuzz_test}.c" ]; then + FUZZ_SOURCE="$FUZZ_DIR/${fuzz_test}.c" + FUZZ_DEFINES="" + else + FUZZ_SOURCE="$FUZZ_DIR/fuzzer.c" + FUZZ_DEFINES="-D _Py_FUZZ_ONE -D _Py_FUZZ_$fuzz_test" + fi + # Build (but don't link) the fuzzing stub with a C compiler - $CC $CFLAGS $($OUT/bin/python*-config --cflags) $FUZZ_DIR/fuzzer.c \ - -D _Py_FUZZ_ONE -D _Py_FUZZ_$fuzz_test -c -Wno-unused-function \ + $CC $CFLAGS $($OUT/bin/python*-config --cflags) $FUZZ_SOURCE \ + $FUZZ_DEFINES -c -Wno-unused-function \ -o $WORK/$fuzz_test.o # Link with C++ compiler to appease libfuzzer $CXX $CXXFLAGS -rdynamic $WORK/$fuzz_test.o -o $OUT/$fuzz_test \ - $LIB_FUZZING_ENGINE $($OUT/bin/python*-config --ldflags --embed) + $LIB_FUZZING_ENGINE $($OUT/bin/python*-config --ldflags --embed) $MODLIBS # Zip up and copy any seed corpus if [ -d "${FUZZ_DIR}/${fuzz_test}_corpus" ]; then