diff --git a/infra/experimental/chronos/README.md b/infra/experimental/chronos/README.md new file mode 100644 index 000000000..423d732e3 --- /dev/null +++ b/infra/experimental/chronos/README.md @@ -0,0 +1,16 @@ +# Usage +Under `OSS-Fuzz` root directory: +```bash +export PROJECT=libiec61850 +export FUZZ_TARGET=fuzz_mms_decode.c +export FUZZING_LANGUAGE=c +infra/experimental/chronos/prepare-recompile "$PROJECT" "$FUZZ_TARGET" "$FUZZING_LANGUAGE" +python infra/helper.py build_image "$PROJECT" +docker run -ti --entrypoint="/bin/sh" --name "${PROJECT}-origin" "gcr.io/oss-fuzz/${PROJECT}" -c "compile && rm -rf /out/*" +docker commit "${PROJECT}-origin" "gcr.io/oss-fuzz/${PROJECT}-ofg-cached" +docker run -ti --entrypoint="recompile" "gcr.io/oss-fuzz/${PROJECT}-ofg-cached" +``` + +# Assumptions +1. Fuzzer: Chronos assumes `libFuzzer`. Other fuzzers are not well-supported, but may work by setting ENV `FUZZING_ENGINE` in project's `Dockerfile`. +2. Sanitizer: Chronos assumes `AddressSanitizer`. Other sanitizers may work by adding setting ENV `SANITIZER` in project's `Dockerfile`. diff --git a/infra/experimental/chronos/chronos.sh b/infra/experimental/chronos/chronos.sh new file mode 100644 index 000000000..c364613a2 --- /dev/null +++ b/infra/experimental/chronos/chronos.sh @@ -0,0 +1,74 @@ +# Copyright 2024 Google LLC +# +# Licensed 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. +# +################################################################################ + +# This script records the ENV and commands needed for fuzz target recompilation. +# It intercepts bash commands to save: 1) the ENV variable values before +# building the fuzz target (`recompile_env.sh`) and 2) all subsequent bash +# commands from that point (`recompile`). Combined with Docker, this setup +# allows for recompiling the fuzz target without rebuilding the entire project. +# Usage: +# 1. Set FUZZ_TARGET (e.g., in project's Dockerfile) +# 2. Source this file before compiling the fuzz target (e.g., source chronos.sh +# at the beginning of project's build.sh). + +export START_RECORDING="false" +RECOMPILE_ENV="/usr/local/bin/recompile_env.sh" + + +# Initialize the recompile script. +initialize_recompile_script() { + export RECOMPILE_SCRIPT="/usr/local/bin/recompile" + echo "#!/bin/bash" > "$RECOMPILE_SCRIPT" + echo "source $RECOMPILE_ENV" >> "$RECOMPILE_SCRIPT" + chmod +x "$RECOMPILE_SCRIPT" +} + + +# Execute or record command for recompilation. +execute_or_record_command() { + record_command() { + echo "cd \"$(pwd)\"" >> "$RECOMPILE_SCRIPT" + echo "$@" >> "$RECOMPILE_SCRIPT" + } + + # Check if any element in the command array contains the FUZZ_TARGET. + if [[ "$BASH_COMMAND" == *"$FUZZ_TARGET"* ]]; then + export START_RECORDING="true" + # Save all environment variables, excluding read-only ones + declare -p | grep -Ev 'declare -[^ ]*r[^ ]*' > "$RECOMPILE_ENV" + fi + + if [[ "$START_RECORDING" == "true" ]]; then + record_command "$BASH_COMMAND" + echo "Recorded execution of: $BASH_COMMAND" + fi +} + + +main() { + # Initialize. + initialize_recompile_script + + # Set up trap for DEBUG to intercept commands. + trap 'execute_or_record_command' DEBUG + + # Enable extended debugging mode + shopt -s extdebug + # Ensure trap works in subshells and functions. + set -T +} + +main diff --git a/infra/experimental/chronos/prepare-recompile b/infra/experimental/chronos/prepare-recompile new file mode 100755 index 000000000..7c6726b47 --- /dev/null +++ b/infra/experimental/chronos/prepare-recompile @@ -0,0 +1,40 @@ +#!/usr/bin/bash +# Copyright 2024 Google LLC +# +# Licensed 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. +# +################################################################################ + +# Prepare a project for fuzz target recompilation via chronos.sh +# Usage: +# (in OSS-Fuzz root dir) infra/experimental/chronos/prepare-recompile.sh +# E.g.: +#infra/experimental/chronos/prepare-recompile.sh libiec61850 fuzz_mms_decode.c c + + + +PROJECT=$1 +FUZZ_TARGET=$2 +FUZZING_LANGUAGE=$3 + +# Step 1: Copy chronos.sh to its project directory. +cp infra/experimental/chronos/chronos.sh "projects/$PROJECT/" + +# Step 2: Copy chronos.sh to image and set FUZZ_TARGET and FUZZING_LANGUAGE in its Dockerfile. +{ + echo "COPY chronos.sh /src"; + echo "ENV FUZZ_TARGET=\"$FUZZ_TARGET\""; + echo "ENV FUZZING_LANGUAGE=\"$FUZZING_LANGUAGE\""; + # Step 3: Source chronos.sh at the beginning of its build.sh. + echo "RUN sed -i.bak \"1s|^|source \\\"/src/chronos.sh\\\"\\n|\" \"/src/build.sh\"" +} >> "projects/$PROJECT/Dockerfile"