diff --git a/projects/firefox/ContentParentIPC.options b/projects/firefox/ContentParentIPC.options new file mode 100644 index 000000000..7ca5e76f5 --- /dev/null +++ b/projects/firefox/ContentParentIPC.options @@ -0,0 +1,2 @@ +[libfuzzer] +close_fd_mask = 2 diff --git a/projects/firefox/Dockerfile b/projects/firefox/Dockerfile index 7a63e6018..982613bbc 100644 --- a/projects/firefox/Dockerfile +++ b/projects/firefox/Dockerfile @@ -16,9 +16,8 @@ FROM gcr.io/oss-fuzz-base/base-builder MAINTAINER pdknsk@gmail.com -RUN apt-get update && \ - apt-get install -y apt-file gawk mercurial parallel && \ - apt-file --non-interactive update -RUN hg clone https://hg.mozilla.org/mozilla-central +RUN apt-get update && apt-get install -y gawk mercurial +RUN hg clone --uncompressed https://hg.mozilla.org/mozilla-central +RUN git clone --depth 1 https://github.com/mozillasecurity/fuzzdata WORKDIR mozilla-central -COPY build.sh target.c $SRC/ +COPY build.sh target.c *options $SRC/ diff --git a/projects/firefox/build.sh b/projects/firefox/build.sh index 2cc446474..ce9ef71b5 100755 --- a/projects/firefox/build.sh +++ b/projects/firefox/build.sh @@ -19,6 +19,8 @@ FUZZ_TARGETS=( SdpParser StunParser + ContentParentIPC + ContentSecurityPolicyParser # Qcms # needn't be enabled; has its own project with more sanitizers/engines ) @@ -49,14 +51,12 @@ mk_add_options CXXFLAGS= EOF fi -# Remove existing cargo configs (if any). Otherwise, mach fails. -if [ -d "$HOME/.cargo" ]; then rm -rf $HOME/.cargo; fi - -# Install dependencies. +# Install dependencies. Note that bootstrap installs cargo, which must be added +# to PATH via source. In a successive run (for a different sanitizer), the +# cargo installation carries over, but bootstrap fails if cargo is not in PATH. export SHELL=/bin/bash +[ -f "$HOME/.cargo/env" ] && source $HOME/.cargo/env ./mach bootstrap --no-interactive --application-choice browser - -# Set environment for rustc. source $HOME/.cargo/env # Update internal libFuzzer. @@ -74,34 +74,16 @@ tar -xf $OBJDIR/dist/firefox*bz2 -C $OUT mv $OBJDIR/toolkit/library/gtest/libxul.so $OUT/firefox mv $OUT/firefox/dependentlibs.list $OUT/firefox/dependentlibs.list.gtest -# Get the absolute paths of the required libraries. +# Get the absolute paths of the required system libraries. export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:$OUT/firefox REQUIRED_LIBRARIES=($(ldd $OUT/firefox/libxul.so | gawk '/=> [/]/ {print $3}')) REQUIRED_LIBRARIES=(${REQUIRED_LIBRARIES[@]##$OUT/*}) -mkdir $WORK/apt -chown _apt $WORK/apt # suppress warning message on each file -cd $WORK/apt - -# Find and download packages which have the required files, ignoring some. -# Note that apt-file is very slow, hence parallel is used. -# Takes only 1-2 minutes on a 32 vCPU instance. -PACKAGES=($(parallel apt-file search -lFN "{}" ::: ${REQUIRED_LIBRARIES[@]})) -PACKAGES=(${PACKAGES[@]##libc6*}) -PACKAGES=(${PACKAGES[@]##libgcc*}) -PACKAGES=(${PACKAGES[@]##libstdc++*}) -apt-get -q download ${PACKAGES[@]} - -mkdir $WORK/deb -# Extract downloaded packages. -find $WORK/apt -type f -exec dpkg-deb --extract "{}" $WORK/deb \; - -mkdir $OUT/lib -# Move required libraries. Less than 50MB total. +# Copy libraries. Less than 50MB total. +mkdir -p $OUT/lib for REQUIRED_LIBRARY in ${REQUIRED_LIBRARIES[@]} do - find $WORK/deb \ - -xtype f -name "${REQUIRED_LIBRARY##*/}" -exec cp -uL "{}" $OUT/lib \; + cp -L $REQUIRED_LIBRARY $OUT/lib done # Build a wrapper binary for each target to set environment variables. @@ -112,16 +94,18 @@ do $SRC/target.c -o $OUT/$FUZZ_TARGET done -cd $SRC/mozilla-central - # SdpParser -find media/webrtc/trunk/webrtc/test/fuzzers/corpora/sdp-corpus \ - -type f -exec zip -qju $OUT/SdpParser_seed_corpus.zip "{}" \; -cp media/webrtc/trunk/webrtc/test/fuzzers/corpora/sdp.tokens \ - $OUT/SdpParser.dict +find media/webrtc -iname "*.sdp" \ + -type f -exec zip -qu $OUT/SdpParser_seed_corpus.zip "{}" \; +cp $SRC/fuzzdata/dicts/sdp.dict $OUT/SdpParser.dict # StunParser -find media/webrtc/trunk/webrtc/test/fuzzers/corpora/stun-corpus \ - -type f -exec zip -qju $OUT/StunParser_seed_corpus.zip "{}" \; -cp media/webrtc/trunk/webrtc/test/fuzzers/corpora/stun.tokens \ - $OUT/StunParser.dict +find media/webrtc -iname "*.stun" \ + -type f -exec zip -qu $OUT/StunParser_seed_corpus.zip "{}" \; +cp $SRC/fuzzdata/dicts/stun.dict $OUT/StunParser.dict + +# ContentParentIPC +cp $SRC/fuzzdata/settings/ipc/libfuzzer.content.blacklist.txt $OUT/firefox + +# ContentSecurityPolicyParser +cp dom/security/fuzztest/csp_fuzzer.dict $OUT/ContentSecurityPolicyParser.dict diff --git a/projects/firefox/target.c b/projects/firefox/target.c index 8333b73ac..5f6ba2785 100644 --- a/projects/firefox/target.c +++ b/projects/firefox/target.c @@ -13,72 +13,60 @@ static const char* magic __attribute__((used)) = "LLVMFuzzerTestOneInput"; int main(int argc, char* argv[]) { char path[PATH_MAX] = {0}; + // Handle (currently not used) relative binary path. if (**argv != '/') { - if (!getcwd(path, PATH_MAX)) { - perror("Couldn't get CWD"); + if (!getcwd(path, PATH_MAX - 1)) { + perror("getcwd"); exit(1); } strcat(path, "/"); } - if (strlen(path) + strlen(*argv) + 20 > PATH_MAX) { + if (strlen(path) + strlen(*argv) + 40 >= PATH_MAX) { fprintf(stderr, "Path length would exceed PATH_MAX\n"); exit(1); } strcat(path, *argv); - char* solidus = strrchr(path, '/'); - *solidus = 0; // terminate string before last / + *solidus = 0; // terminate path before last / char ld_path[PATH_MAX] = {0}; strcpy(ld_path, path); strcat(ld_path, "/lib"); + // Expects LD_LIBRARY_PATH to not also be set by oss-fuzz. + setenv("LD_LIBRARY_PATH", ld_path, 0); + setenv("HOME", "/tmp", 0); + setenv("MOZ_RUN_GTEST", "1", 1); + setenv("LIBFUZZER", "1", 1); + setenv("FUZZER", STRINGIFY(FUZZ_TARGET), 1); + + // ContentParentIPC + char blacklist_path[PATH_MAX] = {0}; + strcpy(blacklist_path, path); + strcat(blacklist_path, "/firefox/libfuzzer.content.blacklist.txt"); + setenv("MOZ_IPC_MESSAGE_FUZZ_BLACKLIST", blacklist_path, 1); + + // Temporary (or permanent?) work-arounds for fuzzing interface bugs. + char* options = getenv("ASAN_OPTIONS"); + if (options) { + char* ptr; + char* new_options = strdup(options); + // https://bugzilla.mozilla.org/1477846 + ptr = strstr(new_options, "detect_stack_use_after_return=1"); + if (ptr) ptr[30] = '0'; + // https://bugzilla.mozilla.org/1477844 + ptr = strstr(new_options, "detect_leaks=1"); + if (ptr) ptr[13] = '0'; + setenv("ASAN_OPTIONS", new_options, 1); + free(new_options); + } + char ff_path[PATH_MAX] = {0}; strcpy(ff_path, path); strcat(ff_path, "/firefox/firefox"); - // Expects LD_LIBRARY_PATH to not also be set by oss-fuzz. - // If it ever is, this has to be replaced with more complex code. - if (setenv("LD_LIBRARY_PATH", ld_path, 0)) { - perror("Error setting LD_LIBRARY_PATH"); - exit(1); - } - - if (setenv("MOZ_RUN_GTEST", "1", 1) || setenv("LIBFUZZER", "1", 1) || - setenv("FUZZER", STRINGIFY(FUZZ_TARGET), 1)) { - perror("Error setting fuzzing variables"); - exit(1); - } - - if (setenv("HOME", "/tmp", 0)) { - perror("Error setting HOME"); - exit(1); - } - - char* options = getenv("ASAN_OPTIONS"); - if (!options) { - fprintf(stderr, "ASAN_OPTIONS not set ?!\n"); - exit(1); - } - - // Temporary (or permanent?) work-arounds for fuzzing interface bugs. - char* new_options = strdup(options); - char* ptr; - // https://bugzilla.mozilla.org/show_bug.cgi?id=1477846 - ptr = strstr(new_options, "detect_stack_use_after_return=1"); - if (ptr) ptr[30] = '0'; - // https://bugzilla.mozilla.org/show_bug.cgi?id=1477844 - ptr = strstr(new_options, "detect_leaks=1"); - if (ptr) ptr[13] = '0'; - - if (setenv("ASAN_OPTIONS", new_options, 1)) { - perror("Error setting ASAN_OPTIONS"); - exit(1); - } - free(new_options); - int ret = execv(ff_path, argv); if (ret) perror("execv");