Skip to content

Latest commit

 

History

History
718 lines (587 loc) · 30.1 KB

test.md

File metadata and controls

718 lines (587 loc) · 30.1 KB

Tests in libspdm

Besides spdm_emu and UnitTest introduced in README, libspdm also supports other tests.

Prerequisites

Build Tool

  1. cmake for Windows and Linux.

Run Test

Test other ARCH (arm, aarch64, riscv32, riscv64, arc)

Linux support only.

  1. Install compiler:

Refer to build.

  1. Install qemu.
sudo apt-get install build-essential pkg-config zlib1g-dev libglib2.0-0 libglib2.0-dev  libsdl2-dev libpixman-1-dev libfdt-dev autoconf automake libtool librbd-dev libaio-dev flex bison -y
wget https://download.qemu.org/qemu-4.2.0.tar.xz
tar xvf qemu-4.2.0.tar.xz
cd qemu-4.2.0
./configure --prefix=/usr/local/qemu --audio-drv-list=
sudo make -j 8 && sudo make install
sudo ln -s /usr/local/qemu/bin/* /usr/local/bin
  1. Run test

For arm (ARM_GCC): qemu-arm -L /usr/arm-linux-gnueabi <TestBinary>

For aarch64 (AARCH64_GCC): qemu-aarch64 -L /usr/aarch64-linux-gnu <TestBinary>

For riscv32 (RISCV GNU): qemu-riscv32 -L /opt/riscv32/sysroot <TestBinary>

For riscv64 (RISCV64 GCC): qemu-riscv64 -L /usr/riscv64-linux-gnu <TestBinary>

Collect Code Coverage

  1. Code Coverage in Windows with DynamoRIO

    Download and install DynamoRIO 8.0.0. Then set DRIO_PATH=<DynameRIO_PATH>

    Install Perl ActivePerl 5.26.

    Build cases. Goto libspdm/build. mkdir log and cd log.

    Run all tests and generate log file : %DRIO_PATH%\<bin64|bin32>\drrun.exe -c %DRIO_PATH%\tools\<lib64|lib32>\release\drcov.dll -- <test_app>

    Generate coverage data with filter : %DRIO_PATH%\tools\<bin64|bin32>\drcov2lcov.exe -dir . -src_filter libspdm

    Generate coverage report : perl %DRIO_PATH%\tools\<bin64|bin32>\genhtml coverage.info

    The final report is index.html.

  2. Code Coverage with GCC and lcov.

    Install lcov sudo apt-get install lcov.

    Build cases with -DGCOV=ON.

    cd libspdm
    mkdir build
    cd build
    cmake -DARCH=<x64|ia32|arm|aarch64|riscv32|riscv64|arc> -DTOOLCHAIN=GCC -DTARGET=<Debug|Release> -DCRYPTO=<mbedtls|openssl> -DGCOV=ON ..
    make copy_sample_key
    make
    

    Goto libspdm/build. mkdir log and cd log.

    Run all tests.

    Collect coverage data : lcov --capture --directory <libspdm_root_dir> --output-file coverage.info

    Collect coverage report : genhtml coverage.info --output-directory .

    The final report is index.html.

Run fuzzing

  1. Fuzzing in Linux with AFL

    Download and install AFL. Unzip and follow docs\QuickStartGuide.txt. Build it with make. Ensure AFL binary is in PATH environment variable.

    tar zxvf afl-latest.tgz
    cd afl-2.52b/
    make
    export AFL_PATH=<AFL_PATH>
    export PATH=$PATH:$AFL_PATH
    

    Then run commands as root (every time reboot the OS):

    sudo bash -c 'echo core >/proc/sys/kernel/core_pattern'
    cd /sys/devices/system/cpu/
    sudo bash -c 'echo performance | tee cpu*/cpufreq/scaling_governor'
    

    Known issue: Above command cannot run in Windows Linux Subsystem.

    Build cases with AFL toolchain -DTOOLCHAIN=AFL. For example:

    cd libspdm
    mkdir build
    cd build
    cmake -DARCH=x64 -DTOOLCHAIN=AFL -DTARGET=Release -DCRYPTO=mbedtls ..
    make copy_sample_key
    make
    

    Run cases:

    mkdir testcase_dir
    mkdir /dev/shm/findings_dir
    cp <seed> testcase_dir
    afl-fuzz -i testcase_dir -o /dev/shm/findings_dir <test_app> @@
    

    Note: /dev/shm is tmpfs.

    Fuzzing Code Coverage in Linux with AFL and lcov. Install lcov sudo apt-get install lcov.

    Build cases with AFL toolchain -DTOOLCHAIN=AFL -DGCOV=ON.

    cd libspdm
    mkdir build
    cd build
    cmake -DARCH=x64 -DTOOLCHAIN=AFL -DTARGET=Release -DCRYPTO=mbedtls -DGCOV=ON ..
    make copy_sample_key
    make
    

    You can launch the script fuzzing_AFL.sh to run a duration for each fuzzing test case. If you want to run a specific case modify the cmd tuple in the script.

    First install screen sudo apt install screen.

    The usage of the script fuzzing_AFL.sh is as following:

    libspdm/unit_test/fuzzing/fuzzing_AFL.sh <CRYPTO> <GCOV> <duration>
    <CRYPTO> means selected Crypto library: mbedtls or openssl
    <GCOV> means enable Code Coverage or not: ON or OFF
    <duration> means the duration of every program keep fuzzing: NUMBER seconds
    

    For example: build with mbedtls, enable Code Coverage and every test case run 60 seconds.

    libspdm/unit_test/fuzzing/fuzzing_AFL.sh mbedtls ON 60
    

    Fuzzing output path and code coverage output path of the script fuzzing_AFL.sh:

    #libspdm/unit_test/fuzzing/out_<CRYPTO>_<GitLogHash>/SummaryList.csv
    libspdm/unit_test/fuzzing/out_mbedtls_ac992fd/SummaryList.csv
    #libspdm/unit_test/fuzzing/out_<CRYPTO>_<GitLogHash>/coverage_log/index.html
    libspdm/unit_test/fuzzing/out_mbedtls_ac992fd/coverage_log/index.html
    
  2. Fuzzing in Windows with winafl

    Clone winafl. Download DynamoRIO.

    Set path set AFL_PATH=<AFL_PATH> and set DRIO_PATH=<DynameRIO_PATH>.

    NOTE: due to an issue googleprojectzero/winafl#145 that causes compatibility issues in recent Windows versions, the author has disabled Drsyms in recent WinAFL builds. If you want to use the newest version you will need to rebuild winafl as detailed in the issue.

    Build winafl:

    mkdir [build32|build64]
    cd [build32|build64]
    cmake -G"Visual Studio 16 2019" -A [Win32|x64] .. -DDynamoRIO_DIR=%DRIO_PATH%\cmake -DUSE_DRSYMS=1
    cmake --build . --config Release
    

    NOTE: If you get errors where the linker couldn't find certain .lib files refer to googleprojectzero/winafl#145 and delete the nonexistent files from "Additional Dependencies".

    Copy all binary under [build32|build64]/bin/Release to [bin32|bin64]. robocopy /E /is /it [build32|build64]/bin/Release [bin32|bin64].

    Build cases with VS2019 toolchain. (non AFL toolchain in Windows).

    Run cases:

    cp <test_app> winafl\<bin64|bin32>
    cp <test_app_pdb> winafl\<bin64|bin32>
    cd winafl\<bin64|bin32>
    afl-fuzz.exe -i in -o out -D %DRIO_PATH%\<bin64|bin32> -t 20000 -- -coverage_module <test_app> -fuzz_iterations 1000 -target_module <test_app> -target_method main -nargs 2 -- <test_app> @@
    
  3. Fuzzing in Linux with LLVM LibFuzzer

    First install LLVM with: sudo apt install llvm, and install CLANG with: sudo apt install clang.

    Ensure LLVM and CLANG binary in PATH environment variable. Use llvm-ar --version and clang --version to confirm the LLVM version(Take 'Ubuntu 20.04.2 LTS' as an example).

    ~$ llvm-ar --version
    LLVM (https://llvm.org/):
      LLVM version 10.0.0
    
      Optimized build.
      Default target: x86_64-pc-linux-gnu
      Host CPU: haswell
    
    ~$ clang --version
    clang version 10.0.0-4ubuntu1
    Target: x86_64-pc-linux-gnu
    Thread model: posix
    InstalledDir: /usr/bin
    

    Currently when building with LIBFUZZER toolchain, it will enable AddressSanitizer by using the -fsanitize=fuzzer,address flag during the compilation and linking. You can check it in CMakeLists.txt.

    Build cases with LIBFUZZER toolchain -DTOOLCHAIN=LIBFUZZER(Note the unit test doesn't build when DTOOLCHAIN=LIBFUZZER).

    cd libspdm
    mkdir build_libfuzz
    cd build_libfuzz
    cmake -DARCH=x64 -DTOOLCHAIN=LIBFUZZER -DTARGET=Release -DCRYPTO=mbedtls ..
    make copy_sample_key
    make
    

    If you want to collect the code coverage of fuzzing test build cases with -DGCOV=ON.

    cmake -DARCH=x64 -DTOOLCHAIN=LIBFUZZER -DTARGET=Release -DCRYPTO=mbedtls -DGCOV=ON ..
    

    Run cases:

    mkdir NEW_CORPUS_DIR // Copy test seeds to the folder before run test
    <test_app> NEW_CORPUS_DIR -rss_limit_mb=0 -artifact_prefix=<OUTPUT_PATH>
    

    You can launch the script fuzzing_LibFuzzer.sh to run a duration for each fuzzing test case. If you want to run a specific case modify the cmd tuple in the script.

    First install screen sudo apt install screen.

    The usage of the script fuzzing_LibFuzzer.sh is as following:

    Usage: ./libspdm/unit_test/fuzzing/fuzzing_LibFuzzer.sh <CRYPTO> <GCOV> <duration>
    <CRYPTO> means selected Crypto library: mbedtls or openssl
    <GCOV> means enable Code Coverage or not: ON or OFF
    <duration> means the duration of every program keep fuzzing: NUMBER seconds
    

    For example: build with mbedtls, enable Code Coverage and every test case run 30 seconds.

    libspdm/unit_test/fuzzing/fuzzing_LibFuzzer.sh mbedtls ON 30
    

    Fuzzing output path of the script fuzzing_LibFuzzer.sh:

    #libspdm/unit_test/fuzzing/out_libfuzz_<CRYPTO>_<GitLogHash>/
    libspdm/unit_test/fuzzing/out_libfuzz_mbedtls_05e7bb4/
    
  4. Fuzzing in Windows with LLVM LibFuzzer

    Note: IA32 build is not supported with LLVM in Windows.

    Ensure LLVM binary in in PATH environment variable.

    Build cases with LIBFUZZER toolchain -DARCH=x64 -DTOOLCHAIN=LIBFUZZER.

    Run cases:

    mkdir NEW_CORPUS_DIR // Copy test seeds to the folder before run test
    <test_app> NEW_CORPUS_DIR -rss_limit_mb=0 -artifact_prefix=<OUTPUT_PATH>
    
  5. Fuzzing in Linux with OSS-Fuzz locally

    Take 'Ubuntu 20.04.2 LTS' as an example: a. Install Docker You can verify that Docker Engine is installed correctly by running the hello-world image.

    sudo docker run hello-world
    

    The above command downloads a test image and runs it in a container. When the container runs, it prints the following message and exits.

    Hello from Docker!
    This message shows that your installation appears to be working correctly.
    

    If you get the following Timeout error add and check your proxy configuration.

    Unable to find image 'hello-world:latest' locally
    docker: Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).
    See 'docker run --help'.
    

    Just add your Proxy details to the /etc/systemd/system/docker.service.d/proxy.conf (folder docker.service.d may not exists , so create the directory before), for example:

    [Service]
    Environment="HTTP_PROXY=http://proxy.example.com:80/"
    Environment="HTTPS_PROXY=https://proxy.example.com:80/"
    

    If you get the following toomanyrequests error, configure the registry-mirrors option for the Docker daemon.

    Unable to find image 'hello-world:latest' locally
    docker: Error response from daemon: toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit.
    

    Just add your mirror details to the /etc/docker/daemon.json, for example:

    {
       "registry-mirrors": ["https.your-mirror.example.com"]
    }
    

    If you want to run docker without sudo, you can create a docker group. To create the docker group, add your user and activate the changes to groups:

    sudo groupadd docker
    sudo usermod -aG docker $USER
    newgrp docker
    

    b. Setting up new project Clone OSS-Fuzz

    git clone https://github.com/google/oss-fuzz.git
    

    Generate templated versions of the configuration files(project.yaml Dockerfile build.sh) by running the following commands:

    $ cd oss-fuzz
    $ export PROJECT_NAME=libspdm
    $ export LANGUAGE=c
    $ python3 infra/helper.py generate $PROJECT_NAME --language=$LANGUAGE
    

    Once the template configuration files are created, replace them with our modified files to fit our project:

    cd ~/oss-fuzz
    cp ~/libspdm/unit_test/fuzzing/oss-fuzz_conf/* ~/oss-fuzz/projects/libspdm/
    

    c. Testing locally Build your docker image

    cd oss-fuzz
    sudo python3 infra/helper.py build_image $PROJECT_NAME
    

    If build docker image successfully, it will print the following messages at last.

    Successfully built 19b86a662c16
    Successfully tagged gcr.io/oss-fuzz/libspdm:latest
    

    If you get the following connection timed out error when building docker image, unable to apt-get update through dockerfile then enable proxy configuration in Dockerfile.

    Err:1 https://archive.ubuntu.com/ubuntu xenial InRelease
    Could not connect to archive.ubuntu.com:80 (91.189.88.162), connection timed out [IP: 91.189.88.162 80]
    

    Just set your Proxy Environment before RUN apt-get in oss-fuzz/projects/libspdm/Dockerfile, for example:

    FROM gcr.io/oss-fuzz-base/base-builder
    ENV http_proxy 'http://proxy.example.com:80/'
    ENV https_proxy 'https://proxy.example.com:80/'
    RUN apt-get update && apt-get install -y make autoconf automake libtool
    

    Build your fuzz targets, the built binaries appear in the ~/oss-fuzz/build/out/$PROJECT_NAME directory on your machine (and $OUT in the container).

    sudo python3 infra/helper.py build_fuzzers --sanitizer coverage $PROJECT_NAME
    

    Run your fuzz target, to provide a corpus for my_fuzzer, put my_fuzzer_seed_corpus.zip file next to the fuzz target’s binary in $OUT during the build. Individual files in this archive will be used as starting inputs for mutations. for example:

    cd oss-fuzz
    sudo mkdir -p ./build/corpus/$PROJECT_NAME/test_spdm_responder_version
    zip -j ./build/out/libspdm/test_spdm_responder_version_seed_corpus.zip ~/libspdm/unit_test/fuzzing/seeds/test_spdm_responder_version/*
    sudo python3 infra/helper.py run_fuzzer --corpus-dir=./build/corpus/libspdm/test_spdm_responder_version $PROJECT_NAME test_spdm_responder_version
    

    Generate a code coverage report using the corpus you have locally, the code coverage report appear in the ~/oss-fuzz/build/out/$PROJECT_NAME/report/linux/index.html directory on your machine.

    sudo python3 infra/helper.py coverage --no-corpus-download $PROJECT_NAME --fuzz-target=test_spdm_responder_version
    

    d. Automation script You can launch the script oss_fuzz.sh to run a duration for each fuzzing test case. If you want to run a specific case modify the cmd tuple in the script.

    First install screen sudo apt install screen.

    The usage of the script oss_fuzz.sh is as following:

    Usage: ./libspdm/unit_test/fuzzing/oss_fuzz.sh <CRYPTO> <GCOV> <duration>
    <CRYPTO> means selected Crypto library: mbedtls or openssl
    <GCOV> means enable Code Coverage or not: ON or OFF
    <duration> means the duration of every program keep fuzzing: NUMBER seconds
    

    For example: build with mbedtls, enable Code Coverage and every test case run 30 seconds.

    libspdm/unit_test/fuzzing/oss_fuzz.sh mbedtls ON 30
    
  6. Fuzzing in Linux with AFLTurbo

    Install crypto libs then clone the repository and build the aflturbo code

    sudo apt-get install libssl-dev
    git clone https://github.com/sleicasper/aflturbo.git
    cd aflturbo/
    make
    cp afl-fuzz afl-turbo-fuzz
    export AFL_PATH=$(pwd)
    export PATH=$PATH:$AFL_PATH
    

    Build it with make & ensure AFLTurbo binary is in PATH environment variable.

    Then run commands as root (every time reboot the OS):

    sudo bash -c 'echo core >/proc/sys/kernel/core_pattern'
    cd /sys/devices/system/cpu/
    sudo bash -c 'echo performance | tee cpu*/cpufreq/scaling_governor'
    

    Known issue: Above command cannot run in Windows Linux Subsystem.

    Build cases with AFL toolchain -DTOOLCHAIN=AFL. For example:

    cd libspdm
    mkdir build
    cd build
    cmake -DARCH=x64 -DTOOLCHAIN=AFL -DTARGET=Release -DCRYPTO=mbedtls ..
    make copy_sample_key
    make
    

    Run cases:

    mkdir testcase_dir
    mkdir /dev/shm/findings_dir
    cp <seed> testcase_dir
    afl-turbo-fuzz -i testcase_dir -o /dev/shm/findings_dir <test_app> @@
    

    Note: /dev/shm is tmpfs.

    Fuzzing Code Coverage in Linux with AFLTurbo and lcov. Install lcov sudo apt-get install lcov.

    Build cases with AFL toolchain -DTOOLCHAIN=AFL -DGCOV=ON.

    cd libspdm
    mkdir build
    cd build
    cmake -DARCH=x64 -DTOOLCHAIN=AFL -DTARGET=Release -DCRYPTO=mbedtls -DGCOV=ON ..
    make copy_sample_key
    make
    

    You can launch the script fuzzing_AFLTurbo.sh to run a duration for each fuzzing test case. If you want to run a specific case modify the cmd tuple in the script.

    First install screen sudo apt install screen.

    The usage of the script fuzzing_AFLTurbo.sh is as following:

    libspdm/unit_test/fuzzing/fuzzing_AFLTurbo.sh <CRYPTO> <GCOV> <duration>
    <CRYPTO> means selected Crypto library: mbedtls or openssl
    <GCOV> means enable Code Coverage or not: ON or OFF
    <duration> means the duration of every program keep fuzzing: NUMBER seconds
    

    For example: build with mbedtls, enable Code Coverage and every test case run 60 seconds.

    libspdm/unit_test/fuzzing/fuzzing_AFLTurbo.sh mbedtls ON 60
    

    Fuzzing output path and code coverage output path of the script fuzzing_AFLTurbo.sh:

    #libspdm/unit_test/fuzzing/out_<CRYPTO>_<GitLogHash>_<TIMESTAMP>/SummaryList.csv
    libspdm/unit_test/fuzzing/out_mbedtls_ac992fd_2022-06-23_08-45-48/SummaryList.csv
    #libspdm/unit_test/fuzzing/out_<CRYPTO>_<GitLogHash>_<TIMESTAMP>/coverage_log/index.html
    libspdm/unit_test/fuzzing/out_mbedtls_ac992f_2022-06-23_08-45-48/coverage_log/index.html
    
  7. Fuzzing in Linux with AFLplusplus

    Install crypto libs then clone the repository and build the AFLplusplus code

    sudo apt-get install libssl-dev
    git clone https://github.com/AFLplusplus/AFLplusplus.git
    cd AFLplusplus/
    make
    cp afl-fuzz afl-plusplus-fuzz
    export AFL_PATH=~/AFLplusplus/
    export PATH=$PATH:$AFL_PATH
    

    Build it with make & ensure AFLplusplus binary is in PATH environment variable.

    Then run commands as root (every time reboot the OS):

    sudo bash -c 'echo core >/proc/sys/kernel/core_pattern'
    cd /sys/devices/system/cpu/
    sudo bash -c 'echo performance | tee cpu*/cpufreq/scaling_governor'
    

    Known issue: Above command cannot run in Windows Linux Subsystem.

    Build cases with AFL toolchain -DTOOLCHAIN=AFL. For example:

    cd libspdm
    mkdir build
    cd build
    cmake -DARCH=x64 -DTOOLCHAIN=AFL -DTARGET=Release -DCRYPTO=mbedtls ..
    make copy_sample_key
    make
    

    Run cases:

    mkdir testcase_dir
    mkdir /dev/shm/findings_dir
    cp <seed> testcase_dir
    afl-plusplus-fuzz -i testcase_dir -o /dev/shm/findings_dir <test_app> @@
    

    Note: /dev/shm is tmpfs.

    Fuzzing Code Coverage in Linux with AFLplusplus and lcov. Install lcov sudo apt-get install lcov.

    Build cases with AFL toolchain -DTOOLCHAIN=AFL -DGCOV=ON.

    cd libspdm
    mkdir build
    cd build
    cmake -DARCH=x64 -DTOOLCHAIN=AFL -DTARGET=Release -DCRYPTO=mbedtls -DGCOV=ON ..
    make copy_sample_key
    make
    

    You can launch the script fuzzing_AFLplusplus.sh to run a duration for each fuzzing test case. If you want to run a specific case modify the cmd tuple in the script.

    First install screen sudo apt install screen.

    The usage of the script fuzzing_AFLplusplus.sh is as following:

    libspdm/unit_test/fuzzing/fuzzing_AFLplusplus.sh <CRYPTO> <GCOV> <duration>
    <CRYPTO> means selected Crypto library: mbedtls or openssl
    <GCOV> means enable Code Coverage or not: ON or OFF
    <duration> means the duration of every program keep fuzzing: NUMBER seconds
    

    For example: build with mbedtls, enable Code Coverage and every test case run 60 seconds.

    libspdm/unit_test/fuzzing/fuzzing_AFLplusplus.sh mbedtls ON 60
    

    Fuzzing output path and code coverage output path of the script fuzzing_AFLplusplus.sh:

    #libspdm/unit_test/fuzzing/out_<CRYPTO>_<GitLogHash>_<TIMESTAMP>/SummaryList.csv
    libspdm/unit_test/fuzzing/out_mbedtls/SummaryList.csv
    #libspdm/unit_test/fuzzing/out_<CRYPTO>_<GitLogHash>_<TIMESTAMP>/coverage_log/index.html
    libspdm/unit_test/fuzzing/out_mbedtls/coverage_log/index.html
    

Run Symbolic Execution

  1. KLEE

    Download and install KLEE with LLVM9. Follow all 12 steps including optional ones.

    In step 3, constraint solver STP is recommended here. Set size of the stack to a very large value: $ ulimit -s unlimited.

    In step 8, below example can be used:

    $ cmake \
       -DENABLE_SOLVER_STP=ON \
       -DENABLE_POSIX_RUNTIME=ON \
       -DENABLE_KLEE_UCLIBC=ON \
       -DKLEE_UCLIBC_PATH=/home/tiano/env/klee-uclibc \
       -DGTEST_SRC_DIR=/home/tiano/env/googletest-release-1.7.0 \
       -DENABLE_UNIT_TESTS=ON \
       -DLLVM_CONFIG_BINARY=/usr/bin/llvm-config \
       -DLLVMCC=/usr/bin/clang \
       -DLLVMCXX=/usr/bin/clang++
       /home/tiano/env/klee
    

    Ensure KLEE binary is in PATH environment variable.

    export KLEE_SRC_PATH=<KLEE_SOURCE_DIR>
    export KLEE_BIN_PATH=<KLEE_BUILD_DIR>
    export PATH=$KLEE_BIN_PATH:$PATH
    

    Build cases in Linux with KLEE toolchain -DTOOLCHAIN=KLEE. (KLEE does not support Windows)

    Use KLEE to generate ktest: klee --only-output-states-covering-new <test_app>

    Transfer .ktest to seed file, which can be used for AFL-fuzzer. python unit_test/fuzzing/Tools/TransferKtestToSeed.py <Arguments>

    Arguments: the path of .ktest file. ... the paths of .ktest files. the path of folder contains .ktest file. ... the paths of folders contain .ktest file.

Run Model Checker

  1. CBMC

    Install CBMC tool. For Windows, unzip cbmc-5-10-win. For Linux, unzip cbmc-5-11-linux-64. Ensure CBMC executable directory is in PATH environment variable.

    Build cases with CBMC toolchain:

    For Windows, open Visual Studio 2019 command prompt at libspdm dir and build it with CBMC toolchain -DARCH=ia32 -DTOOLCHAIN=LIBFUZZER. (Use x86 command prompt for ARCH=ia32 only)

    For Linux, open command prompt at libspdm dir and build it with CBMC toolchain -DARCH=x64 -DTOOLCHAIN=CBMC. (ARCH=x64 only)

    The output binary is created by the goto-cc.

    For more infomration on how to use CBMC, refer to CBMC Manual, such as properties, modeling-nondeterminism, api. Example below:

    Using goto-instrument static analyzer operates on goto-binaries and generate a modified binary: goto-instrument SpdmRequester.exe SpdmRequester.gb <instrumentation-options>

    Using CBMC on the modified binary: cbmc SpdmRequester.gb --show-properties

Run Static Analysis

  1. Use Klocwork in Windows as an example.

    Install Klocwork and set environment.

    set KW_HOME=C:\Klocwork
    set KW_ROOT=%KW_HOME%\<version>\projects_root
    set KW_TABLE_ROOT=%KW_HOME%\Tables
    set KW_CONFIG=%KW_ROOT%\projects\workspace\rules\analysis_profile.pconf
    set KW_PROJECT_NAME=libspdm
    

    Run CMAKE to generate makefile.

    Build libspdm with Klocwork :

    kwinject --output %KW_ROOT%\%KW_PROJECT_NAME%.out nmake
    

    Collect analysis data :

    kwservice start
    kwadmin create-project %KW_PROJECT_NAME%
    kwadmin import-config %KW_PROJECT_NAME% %KW_CONFIG%
    kwbuildproject --project %KW_PROJECT_NAME% --tables-directory %KW_TABLE_ROOT%\%KW_PROJECT_NAME% %KW_ROOT%\%KW_PROJECT_NAME%.out --force
    kwadmin load %KW_PROJECT_NAME% %KW_TABLE_ROOT%\%KW_PROJECT_NAME%
    

    View report at http://localhost:8080/.

  2. Use Coverity in Windows as an example.

    Install Coverity and set environment. For x64 builds, use a x64 Native Tools Command Prompt for Visual Studio... command prompt.

    set PATH=%PATH%;C:\Program Files\Coverity\Coverity Static Analysis\bin\
    cov-configure --msvc --config C:\libspdm\CoverityConfig\coverity-config.xml
    

    Run CMAKE to generate makefile and build libspdm with Coverity :

    cd libspdm
    mkdir build
    cd build
    cmake -G"NMake Makefiles" -DARCH=x64 -DTOOLCHAIN=VS2019 -DTARGET=Release -DCRYPTO=mbedtls ..
    nmake copy_sample_key
    cov-build --config C:\libspdm\CoverityConfig\coverity-config.xml --dir C:\libspdm\coverity-output nmake
    

    Execute cov-analyze command and generate the report :

    cov-analyze --dir C:\libspdm\coverity-output --all --rule --enable-constraint-fpp --enable-fnptr --enable-virtual --enable FORWARD_NULL
    cov-format-errors --dir C:\libspdm\coverity-output --html-output html-report
    

    Retrieve the report from the folder html-report.

  3. Use CodeQL in CI.

    Set up and check result

    Manageing code scanning alerts for your repository

Collect Stack Usage

  1. Stack usage with GCC -fstack-usage flag

    Build with -DSTACK_USAGE=ON

    cd libspdm
    mkdir build
    cd build
    cmake -DARCH=<x64|ia32|arm|aarch64|riscv32|riscv64|arc> -DTOOLCHAIN=GCC -DTARGET=<Debug|Release> -DCRYPTO=<mbedtls|openssl> -DSTACK_USAGE=ON ..
    make copy_sample_key
    make
    
  2. Check the stack usage of individual functions in the .su file corresponding to every .c file

    For example: <path_to_libspdm>/build/library/spdm_requester_lib/CMakeFiles/spdm_requester_lib.dir/libspdm_req_send_receive.c.su

    <path_to_libspdm>/library/spdm_requester_lib/libspdm_req_send_receive.c:25:15:libspdm_send_request     4736    static
    <path_to_libspdm>/library/spdm_requester_lib/libspdm_req_send_receive.c:76:15:libspdm_receive_response 4752    static
    <path_to_libspdm>/library/spdm_requester_lib/libspdm_req_send_receive.c:167:15:spdm_send_spdm_request  64      static
    <path_to_libspdm>/library/spdm_requester_lib/libspdm_req_send_receive.c:212:15:spdm_receive_spdm_response      64      static
    
  3. Useful tools

    avstack.pl, daniel beer, https://dlbeer.co.nz/oss/avstack.html

Measure spdm_context Size

libspdm requires an spdm_context as input parameter. The consumer of libspdm needs to allocate the spdm_context with size returned from libspdm_get_context_size().

Usually the spdm_context is allocated in the heap. The size of spdm_context can be shown in the spdm emulator with printf("context_size - 0x%x\n", (uint32_t)libspdm_get_context_size());.

Measure libspdm Size

The size of libspdm can be evaluated by test_size_of_spdm_requester and test_size_of_spdm_responder.

Use a release build with -DTARGET=Release.

You can find the a raw image at bin/test_size_of_spdm_requester and bin/test_size_of_spdm_responder. Those images includes all SPDM features. They do not include cryptography library or standard library. Those images are used for size evaluation. They cannot run in OS environment.

The SPDM features can be controlled by spdm_lib_config.h.