| #!/bin/bash |
| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # Enable strict mode |
| set -euo pipefail |
| IFS=$'\n\t' |
| |
| # Read command line arguments |
| if [[ "$#" -ne 1 || -z "${JVM_LD_LIBRARY_PATH:-}" ]]; then |
| cat >&2 <<EOF |
| Generates fuzzer runner scripts to be employed by Google OSS-Fuzz. |
| See "FUZZING.adoc" for details. |
| |
| Usage: $0 <outputDir> |
| |
| outputDir |
| |
| The output directory to dump runner scripts and their dependencies. |
| |
| Environment variables: |
| |
| BUILD (optional) |
| |
| If "false", Maven installation will be skipped. |
| |
| FORCE_DOWNLOAD (optional) |
| |
| If "true", certain externally downloaded files (corpus, dictionary, etc.) |
| will be downloaded anyway and override existing ones. |
| |
| JVM_LD_LIBRARY_PATH (required) |
| |
| Directory containing the Java shared libraries, e.g., |
| "/usr/lib/jvm/zulu17/lib/server". |
| EOF |
| exit 1 |
| fi |
| outputDir=$(readlink -f "$1") |
| |
| # Ensure output directory exists |
| mkdir -p "$outputDir" |
| |
| # Switch to the script directory |
| cd -- "$(dirname -- "${BASH_SOURCE[0]}")" |
| |
| # Record the Git commit ID |
| commitId=$(git rev-parse HEAD) |
| |
| # To contain all Maven dependencies under `$outputDir`, explicitly provide the Maven local repository. |
| # `.`-prefixed files are not copied by OSS-Fuzz, don't use them! |
| export MAVEN_OPTS="-Dmaven.repo.local=$outputDir/m2" |
| |
| # Make Maven executions scripting friendly |
| export MAVEN_ARGS="--batch-mode --no-transfer-progress --errors" |
| |
| # Determine the project version |
| projectVersion=$(./mvnw \ |
| --quiet -DforceStdout=true \ |
| -Dexpression=project.version \ |
| help:evaluate \ |
| | tail -n 1) |
| |
| # Build the project |
| [ "${BUILD:-}" != "false" ] && ./mvnw \ |
| -Dmaven.test.skip=true \ |
| -Dxml.skip \ |
| -Dcyclonedx.skip \ |
| -Dbnd.baseline.skip \ |
| -Drat.skip \ |
| -Dspotless.skip \ |
| -Dspotbugs.skip \ |
| -Denforcer.skip \ |
| install |
| |
| # Download the JSON dictionary |
| jsonDictPath="$outputDir/json.dict" |
| [[ ! -f "$jsonDictPath" || "${FORCE_DOWNLOAD:-}" = "true" ]] && \ |
| wget --quiet https://raw.githubusercontent.com/google/fuzzing/master/dictionaries/json.dict -O "$jsonDictPath" |
| |
| # Download the JSON seed corpus |
| jsonSeedCorpusPath="$outputDir/json_seed_corpus.zip" |
| if [[ ! -f "$jsonSeedCorpusPath" || "${FORCE_DOWNLOAD:-}" = "true" ]]; then |
| git clone --quiet --depth 1 https://github.com/dvyukov/go-fuzz-corpus |
| zip -q -j "$jsonSeedCorpusPath" go-fuzz-corpus/json/corpus/* |
| rm -rf go-fuzz-corpus |
| fi |
| |
| # Build and fuzz environments are different: https://google.github.io/oss-fuzz/further-reading/fuzzer-environment/ |
| # Package the Java runtime along with the fuzzers. |
| javaHomeFileName="jvm" |
| cp -rL "$JAVA_HOME" "$outputDir/$javaHomeFileName" |
| |
| # Iterate over fuzzers |
| for module in *-fuzz-test; do |
| |
| # Copy the built module artifact to the output folder |
| cp "$PWD/$module/target/$module-$projectVersion.jar" "$outputDir/$module-$projectVersion.jar" |
| |
| # Determine the Java class path |
| ./mvnw dependency:build-classpath -Dmdep.outputFile=/tmp/cp.txt -pl $module |
| classPath="$(sed "s|$outputDir/||g" /tmp/cp.txt):$module-$projectVersion.jar" |
| rm /tmp/cp.txt |
| |
| for fuzzer in $(find "$module" -name "*Fuzzer.java"); do |
| |
| # Create the runner script |
| fqcn=$(echo "$fuzzer" | sed -r 's|^'$module'/src/main/java/(.+)\.java|\1|' | tr / .) |
| className="${fqcn##*.}" |
| scriptPath="$outputDir/$module-$className" |
| cat >"$scriptPath" <<EOF |
| #!/bin/bash |
| # |
| # This file is auto-generated by https://github.com/apache/logging-log4j2/tree/2.x/oss-fuzz-build.sh |
| # |
| |
| # OSS-Fuzz detects fuzzers by checking the presence of the magical "LLVMFuzzerTestOneInput" word, hence this line. |
| |
| # Enable strict mode |
| set -euo pipefail |
| IFS=\$'\n\t' |
| |
| # Report the build |
| echo "INFO: Produced using the commit ID: $commitId" |
| |
| # Switch to the script directory |
| cd -- "\$(dirname -- "\${BASH_SOURCE[0]}")" |
| |
| # Determine JVM args |
| if [[ "\$@" =~ (^| )-runs=[0-9]+(\$| ) ]]; then |
| jvmArgs="-Xmx1900m:-Xss900k" |
| else |
| jvmArgs="-Xmx2048m:-Xss1024k" |
| fi |
| |
| # Verify the classpath |
| classPath="$classPath" |
| echo "\$classPath" | sed 's/:/\n/g' | while read classPathFilePath; do |
| if [[ ! -f "\$classPathFilePath" ]]; then |
| echo "ERROR: Could not find class path file: \"\$classPathFilePath\"" |
| echo "ERROR: Complete class path: \"\$classPath\"" |
| echo "DEBUG: \"ls\" output" |
| ls -al | sed "s/^/DEBUG: /g" |
| classPathFileName=\$(basename "\$classPathFilePath") |
| echo "DEBUG: \"find\" output" |
| find / -name "\$classPathFileName" 2>/dev/null | sed "s/^/DEBUG: /g" |
| exit 1 |
| fi |
| done |
| |
| # Employ the Java runtime |
| export JAVA_HOME="\$PWD/$javaHomeFileName" |
| export JVM_LD_LIBRARY_PATH="\$JAVA_HOME/lib/server" |
| export PATH="\$JAVA_HOME/bin:\$PATH" |
| java -version |
| |
| # Dump some debugging aid |
| dump_debug() { |
| echo "DEBUG: Dumping system memory information..." |
| free -m |
| echo "DEBUG: Dumping environment variables..." |
| export |
| for filePath in . "\${CRASH_STACKTRACES_DIR:-}" "\${CRASH_STACKTRACES_DIR:-}" "\${DATA_BUNDLES_DIR:-}" "\${FUZZ_INPUTS:-}"; do |
| if [ -e "\$filePath" ]; then |
| echo "DEBUG: Listing \"\$filePath\"..." |
| ls -al "\$filePath" |
| fi |
| done |
| } |
| dump_debug |
| |
| # Create a temporary file for capturing the command output |
| cmdOutputFile=\$(mktemp "$module-$className-XXX.out") |
| trap 'rm -f -- "'\$cmdOutputFile'"' EXIT |
| |
| # Run the fuzzer |
| LD_LIBRARY_PATH="\$JVM_LD_LIBRARY_PATH":. \\ |
| jazzer_driver \\ |
| --agent_path=jazzer_agent_deploy.jar \\ |
| --cp="\$classPath" \\ |
| --target_class="$fqcn" \\ |
| --jvm_args="\$jvmArgs" \\ |
| \$@ \\ |
| 2>&1 | tee "\$cmdOutputFile" || { |
| retCode=\$?; |
| if grep -q "A fatal error has been detected by the Java Runtime Environment" "\$cmdOutputFile"; then |
| echo "WARN: Detected JRE crash; it doesn't qualify as a fuzzing failure." |
| echo "WARN: Cleaning up crash reports and exiting with success..." |
| [ -d "\${FUZZ_INPUTS:-}" ] && rm -f -v "\${FUZZ_INPUTS}"/* |
| dump_debug |
| exit 0 |
| else |
| exit \$retCode |
| fi |
| } |
| EOF |
| chmod +x "$scriptPath" |
| |
| # Execute fuzzer setup scripts |
| { grep "^// FUZZER-SETUP-SCRIPT " "$fuzzer" || :; } | while read _ _ setupScript; do |
| eval $setupScript |
| done |
| |
| done |
| |
| done |