From d7bdd77a4c75cc73ea2ee4a0271ef682a4da9455 Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Tue, 4 May 2021 12:22:32 -0700 Subject: [PATCH] GitLab CI: Add a minimal fuzzing job. Add a -t option to tools/fuzz-test.sh which lets you specify a maximum fuzz time. Add an initial "fuzz-test" job which fuzzes test/captures/* for 5 minutes. To do: Fuzz longer using our capture menagerie and report failures. --- .gitlab-ci.yml | 26 ++++++++++++++++++++++++++ tools/fuzz-test.sh | 32 +++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f726a6ecdd..ada2f84ebf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,6 +59,11 @@ variables: .if-daily-schedule: - if: '$CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == "daily"' when: always +# Fuzz jobs. Care should be taken when changing this since the scheduler +# often doesn't report errors. +.if-fuzz-schedule: + - if: '$CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == "fuzz"' + when: always .build: stage: build @@ -570,3 +575,24 @@ sloccount: - sloccount . | awk "/^Computing results/ { results=1 } { if (results) print }" > $SLOC_OUT - cat $SLOC_OUT - if [ -n "$AWS_ACCESS_KEY_ID" ] && [ -n "$AWS_SECRET_ACCESS_KEY" ] && [ -n "$S3_DESTINATION_ANALYSIS" ] ; then aws s3 cp "$SLOC_OUT" "$S3_DESTINATION_ANALYSIS/" ; fi + +fuzz-test: + extends: .build-ubuntu + rules: !reference [.if-fuzz-schedule] + stage: test + resource_group: fuzz-master + variables: + MIN_PLUGINS: 10 + MAX_PASSES: 5 + script: + - mkdir /tmp/fuzz + # - JOB_START_SECS=$( date -d "$CI_JOB_STARTED_AT" +%s ) + - cmake -G Ninja -DBUILD_wireshark=OFF -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON .. + - ninja + # - MAX_SECONDS=$(( 3600 - ( $( date +%s ) - $JOB_START_SECS ) - 300 )) + - MAX_SECONDS=300 + - cd .. + - FUZZ_PASSED=false + - ./tools/fuzz-test.sh -a -2 -P $MIN_PLUGINS -b ./build/run -d /tmp/fuzz -t $MAX_SECONDS $( shuf -e test/captures/* ) 2> fuzz-test.err && FUZZ_PASSED=true + - if $FUZZ_PASSED ; then exit 0 ; fi + - echo Fuzzing failed. diff --git a/tools/fuzz-test.sh b/tools/fuzz-test.sh index 0eb4be5a80..cc70f2c39e 100755 --- a/tools/fuzz-test.sh +++ b/tools/fuzz-test.sh @@ -22,8 +22,8 @@ TEST_TYPE="fuzz" # Sanity check to make sure we can find our plugins. Zero or less disables. MIN_PLUGINS=0 -# Did we catch a signal? -DONE=0 +# Did we catch a signal or time out? +DONE=false # Currently running children RUNNER_PIDS= @@ -48,8 +48,12 @@ CHANGE_OFFSET=0 # Only has effect when running under valgrind. MAX_LEAK=$(( 1024 * 100 )) +# Our maximum run time. +START_SECONDS=$SECONDS +MAX_SECONDS=$(( START_SECONDS + 86400 )) + # To do: add options for file names and limits -while getopts "2b:C:d:e:agp:P:o:" OPTCHAR ; do +while getopts "2b:C:d:e:agp:P:o:t:" OPTCHAR ; do case $OPTCHAR in a) ASAN=1 ;; 2) TWO_PASS="-2 " ;; @@ -61,6 +65,7 @@ while getopts "2b:C:d:e:agp:P:o:" OPTCHAR ; do p) MAX_PASSES=$OPTARG ;; P) MIN_PLUGINS=$OPTARG ;; o) CHANGE_OFFSET=$OPTARG ;; + t) MAX_SECONDS=$(( START_SECONDS + OPTARG )) ;; *) printf "Unknown option %s" "$OPTCHAR" esac done @@ -145,7 +150,7 @@ echo "" # Clean up on C, etc trap_all() { - DONE=1 + DONE=true echo 'Caught signal' } @@ -161,14 +166,14 @@ trap trap_abrt ABRT # Iterate over our capture files. PASS=0 -while { [ $PASS -lt "$MAX_PASSES" ] || [ "$MAX_PASSES" -lt 1 ]; } && [ $DONE -ne 1 ] ; do +while { [ $PASS -lt "$MAX_PASSES" ] || [ "$MAX_PASSES" -lt 1 ]; } && ! $DONE ; do PASS=$(( PASS+1 )) echo "Starting pass $PASS:" RUN=0 for CF in "$@" ; do - if [ $DONE -eq 1 ]; then - break # We caught a signal + if $DONE; then + break # We caught a signal or timed out fi RUN=$(( RUN + 1 )) if [ $(( RUN % 50 )) -eq 0 ] ; then @@ -185,7 +190,7 @@ while { [ $PASS -lt "$MAX_PASSES" ] || [ "$MAX_PASSES" -lt 1 ]; } && [ $DONE -ne echo "Not a valid capture file" rm -f "$TMP_DIR/$ERR_FILE" continue - elif [ $RETVAL -ne 0 ] && [ $DONE -ne 1 ] ; then + elif [ $RETVAL -ne 0 ] && ! $DONE ; then # Some other error ws_exit_error fi @@ -208,7 +213,7 @@ while { [ $PASS -lt "$MAX_PASSES" ] || [ "$MAX_PASSES" -lt 1 ]; } && [ $DONE -ne RUNNER_PIDS= RUNNER_ERR_FILES= for ARGS in "${RUNNER_ARGS[@]}" ; do - if [ $DONE -eq 1 ]; then + if $DONE; then break # We caught a signal fi echo -n "($ARGS) " @@ -242,6 +247,11 @@ while { [ $PASS -lt "$MAX_PASSES" ] || [ "$MAX_PASSES" -lt 1 ]; } && [ $DONE -ne RUNNER_PID=$! RUNNER_PIDS="$RUNNER_PIDS $RUNNER_PID" RUNNER_ERR_FILES="$RUNNER_ERR_FILES $TMP_DIR/$ERR_FILE.$RUNNER_PID" + + if [ $SECONDS -ge $MAX_SECONDS ] ; then + printf "\nStopping after %d seconds.\n" $(( SECONDS - START_SECONDS )) + DONE=true + fi done for RUNNER_PID in $RUNNER_PIDS ; do @@ -254,7 +264,7 @@ while { [ $PASS -lt "$MAX_PASSES" ] || [ "$MAX_PASSES" -lt 1 ]; } && [ $DONE -ne #grep -i "dissector bug" $TMP_DIR/$ERR_FILE \ # > /dev/null 2>&1 && DISSECTOR_BUG=1 - if [ $VALGRIND -eq 1 ] && [ $DONE -ne 1 ]; then + if [ $VALGRIND -eq 1 ] && ! $DONE; then VG_ERR_CNT=$( grep "ERROR SUMMARY:" "$TMP_DIR/$ERR_FILE" | cut -f4 -d' ' ) VG_DEF_LEAKED=$( grep "definitely lost:" "$TMP_DIR/$ERR_FILE" | cut -f7 -d' ' | tr -d , ) VG_IND_LEAKED=$( grep "indirectly lost:" "$TMP_DIR/$ERR_FILE" | cut -f7 -d' ' | tr -d , ) @@ -273,7 +283,7 @@ while { [ $PASS -lt "$MAX_PASSES" ] || [ "$MAX_PASSES" -lt 1 ]; } && [ $DONE -ne fi fi - if [ $DONE -ne 1 ] && { [ $RUNNER_RETVAL -ne 0 ] || [ $DISSECTOR_BUG -ne 0 ] || [ $VG_ERR_CNT -ne 0 ]; } ; then + if $DONE && { [ $RUNNER_RETVAL -ne 0 ] || [ $DISSECTOR_BUG -ne 0 ] || [ $VG_ERR_CNT -ne 0 ]; } ; then # shellcheck disable=SC2086 rm -f $RUNNER_ERR_FILES ws_exit_error