2018-04-17 16:31:53 +00:00
|
|
|
#!/bin/bash -u
|
2017-08-08 17:54:53 +00:00
|
|
|
# Copyright 2017 Google Inc.
|
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
#
|
|
|
|
################################################################################
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
# A minimal number of runs to test fuzz target with a non-empty input.
|
|
|
|
MIN_NUMBER_OF_RUNS=4
|
|
|
|
|
|
|
|
# The "example" target has 73 with ASan, 65 with UBSan, and 6648 with MSan.
|
|
|
|
# Real world targets have greater values (arduinojson: 407, zlib: 664).
|
|
|
|
THRESHOLD_FOR_NUMBER_OF_EDGES=256
|
|
|
|
|
|
|
|
# Threshold values for different sanitizers used by instrumentation checks.
|
|
|
|
ASAN_CALLS_THRESHOLD_FOR_ASAN_BUILD=1000
|
|
|
|
ASAN_CALLS_THRESHOLD_FOR_NON_ASAN_BUILD=0
|
|
|
|
|
|
|
|
MSAN_CALLS_THRESHOLD_FOR_MSAN_BUILD=1000
|
|
|
|
MSAN_CALLS_THRESHOLD_FOR_NON_MSAN_BUILD=0
|
|
|
|
|
|
|
|
UBSAN_CALLS_THRESHOLD_FOR_UBSAN_BUILD=350
|
|
|
|
UBSAN_CALLS_THRESHOLD_FOR_NON_UBSAN_BUILD=200
|
|
|
|
|
|
|
|
|
|
|
|
# Verify that the given fuzz target has proper coverage instrumentation.
|
2017-08-08 17:54:53 +00:00
|
|
|
function check_instrumentation {
|
|
|
|
local FUZZER=$1
|
|
|
|
local CHECK_FAILED=0
|
2018-04-17 16:31:53 +00:00
|
|
|
local FUZZER_OUTPUT="/tmp/$(basename $FUZZER).output"
|
2017-08-08 17:54:53 +00:00
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
if [[ "$FUZZING_ENGINE" != libfuzzer ]]; then
|
|
|
|
return
|
2017-08-08 17:54:53 +00:00
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
# Store fuzz target's output into a temp file to be used for further checks.
|
|
|
|
$FUZZER -runs=$MIN_NUMBER_OF_RUNS &>$FUZZER_OUTPUT
|
|
|
|
CHECK_FAILED=$(egrep "ERROR: no interesting inputs were found. Is the code instrumented" -c $FUZZER_OUTPUT)
|
2017-08-08 17:54:53 +00:00
|
|
|
if (( $CHECK_FAILED > 0 )); then
|
2018-04-17 16:31:53 +00:00
|
|
|
echo "BAD BUILD: the target does not seem to have coverage instrumentation."
|
|
|
|
|
|
|
|
# Bail out as the further check does not make any sense, there are 0 PCs.
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
local NUMBER_OF_EDGES=$(grep -Po "INFO: Loaded [[:digit:]]+ module.*\(.*counters\):[[:space:]]+\K[[:digit:]]+" $FUZZER_OUTPUT)
|
|
|
|
|
|
|
|
if (( $NUMBER_OF_EDGES < $THRESHOLD_FOR_NUMBER_OF_EDGES )); then
|
|
|
|
echo "BAD BUILD: the target seems to have only partial coverage instrumentation."
|
2017-08-08 17:54:53 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
# Verify that the given fuzz target has been built properly and works.
|
2017-08-08 17:54:53 +00:00
|
|
|
function check_startup_crash {
|
|
|
|
local FUZZER=$1
|
|
|
|
local CHECK_PASSED=0
|
|
|
|
|
|
|
|
if [[ "$FUZZING_ENGINE" = libfuzzer ]]; then
|
2018-04-17 16:31:53 +00:00
|
|
|
CHECK_PASSED=$($FUZZER -runs=$MIN_NUMBER_OF_RUNS 2>&1 | egrep "Done $MIN_NUMBER_OF_RUNS runs" -c)
|
2017-08-08 17:54:53 +00:00
|
|
|
else
|
|
|
|
# TODO: add checks for another fuzzing engines if possible.
|
|
|
|
CHECK_PASSED=1
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
if [ "$CHECK_PASSED" -eq "0" ]; then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: the fuzzer seems to have either startup crash or exit."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# Mixed sanitizers check for ASan build.
|
|
|
|
function check_asan_build {
|
|
|
|
local FUZZER=$1
|
|
|
|
local ASAN_CALLS=$2
|
|
|
|
local MSAN_CALLS=$3
|
|
|
|
local UBSAN_CALLS=$4
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
# Perform all the checks for more detailed error message.
|
|
|
|
if (( $ASAN_CALLS < $ASAN_CALLS_THRESHOLD_FOR_ASAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: $FUZZER does not seem to be compiled with ASan."
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
if (( $MSAN_CALLS > $MSAN_CALLS_THRESHOLD_FOR_NON_MSAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: ASan build of $FUZZER seems to be compiled with MSan."
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
if (( $UBSAN_CALLS > $UBSAN_CALLS_THRESHOLD_FOR_NON_UBSAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: ASan build of $FUZZER seems to be compiled with UBSan."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# Mixed sanitizers check for MSan build.
|
|
|
|
function check_msan_build {
|
|
|
|
local FUZZER=$1
|
|
|
|
local ASAN_CALLS=$2
|
|
|
|
local MSAN_CALLS=$3
|
|
|
|
local UBSAN_CALLS=$4
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
# Perform all the checks for more detailed error message.
|
|
|
|
if (( $ASAN_CALLS > $ASAN_CALLS_THRESHOLD_FOR_NON_ASAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: MSan build of $FUZZER seems to be compiled with ASan."
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
if (( $MSAN_CALLS < $MSAN_CALLS_THRESHOLD_FOR_MSAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: $FUZZER does not seem to be compiled with UBSan."
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
if (( $UBSAN_CALLS > $UBSAN_CALLS_THRESHOLD_FOR_NON_UBSAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: MSan build of $FUZZER seems to be compiled with UBSan."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# Mixed sanitizers check for UBSan build.
|
|
|
|
function check_ubsan_build {
|
|
|
|
local FUZZER=$1
|
|
|
|
local ASAN_CALLS=$2
|
|
|
|
local MSAN_CALLS=$3
|
|
|
|
local UBSAN_CALLS=$4
|
|
|
|
|
2017-08-09 15:49:41 +00:00
|
|
|
if [[ "$FUZZING_ENGINE" != libfuzzer ]]; then
|
|
|
|
# Ignore UBSan checks for fuzzing engines other than libFuzzer because:
|
|
|
|
# A) we (probably) are not going to use those with UBSan
|
|
|
|
# B) such builds show indistinguishable number of calls to UBSan
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
# Perform all the checks for more detailed error message.
|
|
|
|
if (( $ASAN_CALLS > $ASAN_CALLS_THRESHOLD_FOR_NON_ASAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: UBSan build of $FUZZER seems to be compiled with ASan."
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
if (( $MSAN_CALLS > $MSAN_CALLS_THRESHOLD_FOR_NON_MSAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: UBSan build of $FUZZER seems to be compiled with MSan."
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
if (( $UBSAN_CALLS < $UBSAN_CALLS_THRESHOLD_FOR_UBSAN_BUILD )); then
|
2017-08-08 17:54:53 +00:00
|
|
|
echo "BAD BUILD: $FUZZER does not seem to be compiled with UBSan."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# Verify that the given fuzz target is compiled with correct sanitizer.
|
|
|
|
function check_mixed_sanitizers {
|
|
|
|
local FUZZER=$1
|
2018-04-17 16:31:53 +00:00
|
|
|
|
2017-08-08 17:54:53 +00:00
|
|
|
local ASAN_CALLS=$(objdump -dC $FUZZER | egrep "callq\s+[0-9a-f]+\s+<__asan" -c)
|
|
|
|
local MSAN_CALLS=$(objdump -dC $FUZZER | egrep "callq\s+[0-9a-f]+\s+<__msan" -c)
|
|
|
|
local UBSAN_CALLS=$(objdump -dC $FUZZER | egrep "callq\s+[0-9a-f]+\s+<__ubsan" -c)
|
|
|
|
|
|
|
|
if [[ "$SANITIZER" = address ]]; then
|
|
|
|
check_asan_build $FUZZER $ASAN_CALLS $MSAN_CALLS $UBSAN_CALLS
|
|
|
|
elif [[ "$SANITIZER" = memory ]]; then
|
|
|
|
check_msan_build $FUZZER $ASAN_CALLS $MSAN_CALLS $UBSAN_CALLS
|
|
|
|
elif [[ "$SANITIZER" = undefined ]]; then
|
|
|
|
check_ubsan_build $FUZZER $ASAN_CALLS $MSAN_CALLS $UBSAN_CALLS
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function main {
|
|
|
|
local FUZZER=$1
|
|
|
|
|
|
|
|
check_instrumentation $FUZZER
|
|
|
|
check_mixed_sanitizers $FUZZER
|
|
|
|
check_startup_crash $FUZZER
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if [ $# -ne 1 ]; then
|
|
|
|
echo "Usage: $0 <fuzz_target_binary>"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2018-04-17 16:31:53 +00:00
|
|
|
# Fuzz target path.
|
2017-08-08 17:54:53 +00:00
|
|
|
FUZZER=$1
|
2018-04-17 16:31:53 +00:00
|
|
|
|
2017-08-08 17:54:53 +00:00
|
|
|
main $FUZZER
|