Skip to content

Commit

Permalink
Rust coverage report (for Suricata) (#4697)
Browse files Browse the repository at this point in the history
* Rust coverage test

* Workaround to get rust coverage for Suricata
  • Loading branch information
catenacyber committed Mar 8, 2021
1 parent 96ae2ed commit c41e46f
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 8 deletions.
4 changes: 3 additions & 1 deletion infra/base-images/base-builder/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ RUN curl https://sh.rustup.rs | sh -s -- -y --default-toolchain=nightly --profil
RUN cargo install cargo-fuzz
# Needed to recompile rust std library for MSAN
RUN rustup component add rust-src --toolchain nightly
# Set up custom environment variable for source code copy for coverage reports
ENV OSSFUZZ_RUSTPATH /rust

# Install Bazel through Bazelisk, which automatically fetches the latest Bazel version.
ENV BAZELISK_VERSION 1.7.4
Expand Down Expand Up @@ -185,7 +187,7 @@ RUN cd $SRC && \
tar -xzv --strip-components=1 -f $SRC/oss-fuzz.tar.gz && \
rm -rf examples $SRC/oss-fuzz.tar.gz

COPY compile compile_afl compile_dataflow compile_libfuzzer compile_honggfuzz \
COPY cargo compile compile_afl compile_dataflow compile_libfuzzer compile_honggfuzz \
compile_go_fuzzer precompile_honggfuzz precompile_afl debug_afl srcmap \
write_labels.py /usr/local/bin/

Expand Down
51 changes: 51 additions & 0 deletions infra/base-images/base-builder/cargo
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash -eu
# Copyright 2020 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.
#
# This is a wrapper around calling cargo
# This just expands RUSTFLAGS in case of a coverage build
# We need this until https://github.com/rust-lang/cargo/issues/5450 is merged
# because cargo uses relative paths for the current crate
# and absolute paths for its dependencies
#
################################################################################

export PATH="/rust/bin:$PATH"

if [ "$SANITIZER" = "coverage" ] && [ $1 = "build" ]
then
crate_src_abspath=`cargo metadata --no-deps --format-version 1 | jq -r '.workspace_root'`
export RUSTFLAGS="$RUSTFLAGS --remap-path-prefix src=$crate_src_abspath/src"
fi

if [ "$SANITIZER" = "coverage" ] && [ $1 = "fuzz" ]
then
fuzz_src_abspath=`pwd`
export RUSTFLAGS="$RUSTFLAGS --remap-path-prefix fuzz_targets=$fuzz_src_abspath/fuzz_targets"
# hack to turn cargo fuzz build into cargo build so as to get coverage
# cargo fuzz adds "--target" "x86_64-unknown-linux-gnu"
(
# go into fuzz directory if not already the case
cd fuzz || true
# do not optimize with --release, leading to Malformed instrumentation profile data
cargo build --bins
# copies the build output in the expected target directory
cd target
mkdir -p x86_64-unknown-linux-gnu/release
cp -r debug/* x86_64-unknown-linux-gnu/release/
)
exit 0
fi

cargo "$@"
7 changes: 6 additions & 1 deletion infra/base-images/base-builder/compile
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ if [ "$SANITIZER" != "undefined" ] && [ "$SANITIZER" != "coverage" ] && [ "$ARCH
else
export RUSTFLAGS="--cfg fuzzing -Cdebuginfo=1 -Cforce-frame-pointers"
fi
if [ "$SANITIZER" = "coverage" ]
then
# link to C++ from comment in f5098035eb1a14aa966c8651d88ea3d64323823d
export RUSTFLAGS="$RUSTFLAGS -Zinstrument-coverage -C link-arg=-lc++"
fi

# Add Rust libfuzzer flags.
# See https://github.com/rust-fuzz/libfuzzer/blob/master/build.rs#L12.
Expand Down Expand Up @@ -145,7 +150,7 @@ BUILD_CMD="bash -eux $SRC/build.sh"

# We need to preserve source code files for generating a code coverage report.
# We need exact files that were compiled, so copy both $SRC and $WORK dirs.
COPY_SOURCES_CMD="cp -rL --parents $SRC $WORK /usr/include /usr/local/include $GOPATH $OUT"
COPY_SOURCES_CMD="cp -rL --parents $SRC $WORK /usr/include /usr/local/include $GOPATH $OSSFUZZ_RUSTPATH $OUT"

if [ "${BUILD_UID-0}" -ne "0" ]; then
adduser -u $BUILD_UID --disabled-password --gecos '' builder
Expand Down
3 changes: 2 additions & 1 deletion infra/base-images/base-clang/checkout_build_install_llvm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
# 2).
NPROC=$(expr $(nproc) / 2)

LLVM_DEP_PACKAGES="build-essential make cmake ninja-build git python3 g++-multilib binutils-dev"
# zlib1g-dev is needed for llvm-profdata to handle coverage data from rust compiler
LLVM_DEP_PACKAGES="build-essential make cmake ninja-build git python3 g++-multilib binutils-dev zlib1g-dev"
apt-get install -y $LLVM_DEP_PACKAGES --no-install-recommends

# Checkout
Expand Down
9 changes: 9 additions & 0 deletions infra/base-images/base-runner/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
wget \
curl \
zip

RUN git clone https://chromium.googlesource.com/chromium/src/tools/code_coverage /opt/code_coverage && \
Expand All @@ -83,6 +84,13 @@ ENV UBSAN_OPTIONS="print_stacktrace=1:print_summary=1:silence_unsigned_overflow=
ENV FUZZER_ARGS="-rss_limit_mb=2560 -timeout=25"
ENV AFL_FUZZER_ARGS="-m none"

# Install rustfilt for symbol demangling.
ENV CARGO_HOME=/rust
ENV RUSTUP_HOME=/rust/rustup
ENV PATH=$PATH:/rust/bin
RUN curl https://sh.rustup.rs | sh -s -- -y --default-toolchain=nightly
RUN cargo install rustfilt

# Install OpenJDK 15 and trim its size by removing unused components.
ENV JAVA_HOME=/usr/lib/jvm/java-15-openjdk-amd64
ENV JVM_LD_LIBRARY_PATH=$JAVA_HOME/lib/server
Expand All @@ -103,6 +111,7 @@ COPY bad_build_check \
dataflow_tracer.py \
download_corpus \
minijail0 \
rcfilt \
reproduce \
run_fuzzer \
run_minijail \
Expand Down
2 changes: 1 addition & 1 deletion infra/base-images/base-runner/coverage
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ else

# Generate HTML report.
llvm-cov show -format=html -output-dir=$REPORT_ROOT_DIR \
-Xdemangler c++filt -Xdemangler -n $LLVM_COV_ARGS
-Xdemangler rcfilt $LLVM_COV_ARGS

# Export coverage summary in JSON format.
llvm-cov export -summary-only $LLVM_COV_ARGS > $SUMMARY_FILE
Expand Down
21 changes: 21 additions & 0 deletions infra/base-images/base-runner/rcfilt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash -u
# Copyright 2020 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.
#
# Symbol demangling for both C++ and Rust
#
################################################################################

# simply pipe
rustfilt | c++filt -n
2 changes: 1 addition & 1 deletion infra/build/functions/build_and_run_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
UPLOAD_URL_FORMAT = 'gs://' + COVERAGE_BUCKET_NAME + '/{project}/{type}/{date}'

# Languages from project.yaml that have code coverage support.
LANGUAGES_WITH_COVERAGE_SUPPORT = ['c', 'c++', 'go']
LANGUAGES_WITH_COVERAGE_SUPPORT = ['c', 'c++', 'go', 'rust']


def usage():
Expand Down
2 changes: 1 addition & 1 deletion infra/ci/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
DEFAULT_SANITIZERS = ['address', 'undefined']

# Languages from project.yaml that have code coverage support.
LANGUAGES_WITH_COVERAGE_SUPPORT = ['c', 'c++', 'go']
LANGUAGES_WITH_COVERAGE_SUPPORT = ['c', 'c++', 'go', 'rust']


def get_changed_files_output():
Expand Down
2 changes: 1 addition & 1 deletion infra/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
PROJECT_LANGUAGE_REGEX = re.compile(r'\s*language\s*:\s*([^\s]+)')

# Languages from project.yaml that have code coverage support.
LANGUAGES_WITH_COVERAGE_SUPPORT = ['c', 'c++', 'go']
LANGUAGES_WITH_COVERAGE_SUPPORT = ['c', 'c++', 'go', 'rust']

# pylint: disable=too-many-lines

Expand Down
1 change: 1 addition & 0 deletions projects/suricata/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ RUN git clone --depth 1 https://github.com/OISF/libhtp.git libhtp
RUN git clone --depth 1 https://github.com/OISF/suricata-verify suricata-verify
WORKDIR $SRC
COPY build.sh $SRC/
COPY rustc.py $SRC/
10 changes: 9 additions & 1 deletion projects/suricata/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,16 @@ mv libhtp suricata/
cd suricata
sh autogen.sh
#run configure with right options
if [ "$SANITIZER" = "coverage" ]
then
export RUSTFLAGS="$RUSTFLAGS -C debug-assertions=no"
chmod +x $SRC/rustc.py
export RUSTC="$SRC/rustc.py"
./configure --disable-shared --enable-fuzztargets --enable-debug
else
./src/tests/fuzz/oss-fuzz-configure.sh
make
fi
make -j$(nproc)

cp src/fuzz_* $OUT/

Expand Down
28 changes: 28 additions & 0 deletions projects/suricata/rustc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python

# Copyright 2021 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.

import sys
import subprocess

#disable coverage for crate brotli_decompressor
sys.argv[0] = "rustc"
if "brotli_decompressor" in sys.argv:
try:
sys.argv.remove("-Zinstrument-coverage")
except:
pass
print(sys.argv)
subprocess.call(sys.argv)

0 comments on commit c41e46f

Please sign in to comment.