diff options
author | Eric Biggers <ebiggers@google.com> | 2022-02-08 01:13:48 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-02-08 01:13:48 +0000 |
commit | fca5118c6f6f4f55ab8ab6a39679c5a5a871f5e3 (patch) | |
tree | a5e816c7e99ab84a0c3abfe52e8ddb094303bdf9 | |
parent | 67c03956aff6fd90e29b2aa85db7f4d2371d0274 (diff) | |
parent | e483d62e0ccd06d6fe6ff1ce39db8b37322e558c (diff) | |
download | fsverity-utils-fca5118c6f6f4f55ab8ab6a39679c5a5a871f5e3.tar.gz |
Merge remote-tracking branch 'aosp/upstream-master' am: 58926f716c am: 7c6fce9125 am: 0685632d03 am: e483d62e0c
Original change: https://android-review.googlesource.com/c/platform/external/fsverity-utils/+/1975207
Change-Id: I8f68e66e5e46d109f8645125235286972eec6348
-rw-r--r-- | .github/workflows/ci.yml | 169 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | NEWS.md | 11 | ||||
-rw-r--r-- | README.md | 52 | ||||
-rw-r--r-- | include/libfsverity.h | 16 | ||||
-rw-r--r-- | lib/libfsverity.pc.in | 2 | ||||
-rw-r--r-- | man/fsverity.1.md | 8 | ||||
-rw-r--r-- | programs/fsverity.c | 2 | ||||
-rwxr-xr-x | scripts/do-release.sh | 101 | ||||
-rwxr-xr-x | scripts/run-sparse.sh | 2 | ||||
-rwxr-xr-x | scripts/run-tests.sh | 369 |
13 files changed, 566 insertions, 193 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..309013a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: MIT +# Copyright 2021 Google LLC +# +# Use of this source code is governed by an MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT. + +name: CI +on: [pull_request] + +jobs: + static-linking-test: + name: Test building static library + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: scripts/run-tests.sh static_linking + + dynamic-linking-test: + name: Test building dynamic library + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: scripts/run-tests.sh dynamic_linking + + cplusplus-test: + name: Test using library from C++ program + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: scripts/run-tests.sh cplusplus + + uninstall-test: + name: Test uninstalling + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: scripts/run-tests.sh uninstall + + dash-test: + name: Test building using the dash shell + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: scripts/run-tests.sh dash + + license-test: + name: Test for correct license info + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: scripts/run-tests.sh license + + gcc-test: + name: Test with gcc + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: scripts/run-tests.sh gcc + + clang-test: + name: Test with clang + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y clang + - run: scripts/run-tests.sh clang + + _32bit-test: + name: Test building 32-bit binaries + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install -y gcc-multilib libssl-dev:i386 + - run: scripts/run-tests.sh 32bit + + sanitizers-test: + name: Test with sanitizers enabled + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y clang llvm + - run: scripts/run-tests.sh sanitizers + + valgrind-test: + name: Test with valgrind enabled + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y valgrind + - run: scripts/run-tests.sh valgrind + + boringssl-test: + name: Test with BoringSSL + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Cache BoringSSL build + uses: actions/cache@v2 + with: + key: boringssl + path: boringssl + - run: make boringssl + - run: scripts/run-tests.sh boringssl + + char-test: + name: Test with unsigned/signed char + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: scripts/run-tests.sh unsigned_char signed_char + + # FIXME: need a Windows build of libcrypto for this to work + #windows-build-test: + #name: Windows build tests + #runs-on: ubuntu-latest + #steps: + #- uses: actions/checkout@v2 + #- name: Install dependencies + #run: | + #sudo apt-get update + #sudo apt-get install -y gcc-mingw-w64-i686 gcc-mingw-w64-x86-64 + # - run: scripts/run-tests.sh windows_build + + sparse-test: + name: Run sparse + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y sparse + - run: scripts/run-tests.sh sparse + + clang-analyzer-test: + name: Run clang static analyzer + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y clang-tools + - run: scripts/run-tests.sh clang_analyzer + + shellcheck-test: + name: Run shellcheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y shellcheck + - run: scripts/run-tests.sh shellcheck @@ -6,6 +6,8 @@ *.so *.so.* /.build-config +/boringssl +/boringssl.tar.gz /fsverity /fsverity.sig /run-tests.log @@ -5,12 +5,12 @@ third_party { type: GIT value: "https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/fsverity-utils.git" } - version: "4258209301d54512956d536149b0eef0c695cfe6" + version: "20e87c13075a8e5660a8d69fd6c93d4f7c5f01a5" # would be NOTICE save for common/fsverity_uapi.h license_type: RESTRICTED last_upgrade_date { - year: 2021 - month: 12 - day: 20 + year: 2022 + month: 2 + day: 7 } } @@ -46,7 +46,7 @@ endif # Set the CFLAGS. First give the warning-related flags (unconditionally, though # the user can override any of them by specifying the opposite flag); then give -# the user-specifed CFLAGS, defaulting to -O2 if none were specified. +# the user-specified CFLAGS, defaulting to -O2 if none were specified. # # Use -Wno-deprecated-declarations to avoid warnings about the Engine API having # been deprecated in OpenSSL 3.0; the replacement isn't ready yet. @@ -213,6 +213,21 @@ EXTRA_TARGETS += $(MAN_PAGES) ############################################################################## +# Support for downloading and building BoringSSL. The purpose of this is to +# allow testing builds of fsverity-utils that link to BoringSSL instead of +# OpenSSL, without having to use a system that uses BoringSSL natively. + +boringssl: + rm -rf boringssl boringssl.tar.gz + curl -s -o boringssl.tar.gz \ + https://boringssl.googlesource.com/boringssl/+archive/refs/heads/master.tar.gz + mkdir boringssl + tar xf boringssl.tar.gz -C boringssl + cmake -B boringssl/build boringssl + $(MAKE) -C boringssl/build $(MAKEFLAGS) + +############################################################################## + SPECIAL_TARGETS := all test_programs check install install-man uninstall \ help clean @@ -1,5 +1,16 @@ # fsverity-utils release notes +## Version 1.5 + +* Made the `fsverity sign` command and the `libfsverity_sign_digest()` function + support PKCS#11 tokens. + +* Avoided a compiler error when building with musl libc. + +* Avoided compiler warnings when building with OpenSSL 3.0. + +* Improved documentation and test scripts. + ## Version 1.4 * Added a manual page for the `fsverity` utility. @@ -102,11 +102,44 @@ against a trusted value. ### Using builtin signatures -With `CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y`, the filesystem supports -automatically verifying a signed file digest that has been included in -the verity metadata. The signature is verified against the set of -X.509 certificates that have been loaded into the ".fs-verity" kernel -keyring. Here's an example: +First, note that fs-verity is essentially just a way of hashing a +file; it doesn't mandate a specific way of handling signatures. +There are several possible ways that signatures could be handled: + +* Do it entirely in userspace +* Use IMA appraisal (work-in-progress) +* Use fs-verity built-in signatures + +Any such solution needs two parts: (a) a policy that determines which +files are required to have fs-verity enabled and have a valid +signature, and (b) enforcement of the policy. Each part could happen +either in a trusted userspace program(s) or in the kernel. + +fs-verity built-in signatures (which are supported when the kernel was +built with `CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y`) are a hybrid +solution where the policy of which files are required to be signed is +determined and enforced by a trusted userspace program, but the actual +signature verification happens in the kernel. Specifically, with +built-in signatures, the filesystem supports storing a signed file +digest in each file's verity metadata. Before allowing access to the +file, the filesystem will automatically verify the signature against +the set of X.509 certificates in the ".fs-verity" kernel keyring. If +set, the sysctl `fs.verity.require_signatures=1` will make the kernel +enforce that every verity file has a valid built-in signature. + +fs-verity built-in signatures are primarily intended as a +proof-of-concept; they reuse the kernel code that verifies the +signatures of loadable kernel modules. This solution still requires a +trusted userspace program to enforce that particular files have +fs-verity enabled. Also, this solution uses PKCS#7 signatures, which +are complex and prone to security bugs. + +Thus, if possible one of the other solutions should be used instead. +For example, the trusted userspace program could verify signatures +itself, using a simple signature format using a modern algorithm such +as Ed25519. + +That being said, here are some examples of using built-in signatures: ```bash # Generate a new certificate and private key: @@ -137,15 +170,6 @@ keyring. Here's an example: fsverity digest file --compact --for-builtin-sig | tr -d '\n' | xxd -p -r | openssl smime -sign -in /dev/stdin ... ``` -By default, it's not required that verity files have a signature. -This can be changed with `sysctl fs.verity.require_signatures=1`. -When set, it's guaranteed that the contents of every verity file has -been signed by one of the certificates in the keyring. - -Note: applications generally still need to check whether the file -they're accessing really is a verity file, since an attacker could -replace a verity file with a regular one. - ### With IMA IMA support for fs-verity is planned. diff --git a/include/libfsverity.h b/include/libfsverity.h index fe89371..a0a1527 100644 --- a/include/libfsverity.h +++ b/include/libfsverity.h @@ -22,7 +22,7 @@ extern "C" { #include <stdint.h> #define FSVERITY_UTILS_MAJOR_VERSION 1 -#define FSVERITY_UTILS_MINOR_VERSION 4 +#define FSVERITY_UTILS_MINOR_VERSION 5 #define FS_VERITY_HASH_ALG_SHA256 1 #define FS_VERITY_HASH_ALG_SHA512 2 @@ -186,13 +186,13 @@ libfsverity_compute_digest(void *fd, libfsverity_read_fn_t read_fn, struct libfsverity_digest **digest_ret); /** - * libfsverity_sign_digest() - Sign previously computed digest of a file - * This signature is used by the filesystem to validate the signed file - * digest against a public key loaded into the .fs-verity kernel - * keyring, when CONFIG_FS_VERITY_BUILTIN_SIGNATURES is enabled. The - * signature is formatted as PKCS#7 stored in DER format. See - * Documentation/filesystems/fsverity.rst in the kernel source tree for - * further details. + * libfsverity_sign_digest() - Sign a file for built-in signature verification + * Sign a file digest in a way that is compatible with the Linux + * kernel's fs-verity built-in signature verification support. The + * resulting signature will be a PKCS#7 message in DER format. Note + * that this is not the only way to do signatures with fs-verity. For + * more details, refer to the fsverity-utils README and to + * Documentation/filesystems/fsverity.rst in the kernel source tree. * @digest: pointer to previously computed digest * @sig_params: pointer to the certificate and private key information * @sig_ret: Pointer to pointer for signed digest diff --git a/lib/libfsverity.pc.in b/lib/libfsverity.pc.in index 03496fe..4c9bb20 100644 --- a/lib/libfsverity.pc.in +++ b/lib/libfsverity.pc.in @@ -4,7 +4,7 @@ includedir=@INCDIR@ Name: libfsverity Description: fs-verity library -Version: 1.4 +Version: 1.5 Libs: -L${libdir} -lfsverity Requires.private: libcrypto Cflags: -I${includedir} diff --git a/man/fsverity.1.md b/man/fsverity.1.md index a983912..dd54964 100644 --- a/man/fsverity.1.md +++ b/man/fsverity.1.md @@ -1,6 +1,6 @@ -% FSVERITY(1) fsverity-utils v1.4 | User Commands +% FSVERITY(1) fsverity-utils v1.5 | User Commands % -% June 2021 +% February 2022 # NAME @@ -161,6 +161,10 @@ token, provide **\-\-pkcs11-engine**, **\-\-pkcs11-module**, **\-\-cert**, and optionally **\-\-pkcs11-keyid**. PKCS#11 token support is unavailable when fsverity-utils was built with BoringSSL rather than OpenSSL. +**fsverity sign** should only be used if you need compatibility with fs-verity +built-in signatures. It is not the only way to do signatures with fs-verity. +For more information, see the fsverity-utils README. + Options accepted by **fsverity sign**: **\-\-block-size**=*BLOCK_SIZE* diff --git a/programs/fsverity.c b/programs/fsverity.c index 813ea2a..e4e348b 100644 --- a/programs/fsverity.c +++ b/programs/fsverity.c @@ -56,7 +56,7 @@ static const struct fsverity_command { }, { .name = "sign", .func = fsverity_cmd_sign, - .short_desc = "Sign a file for fs-verity", + .short_desc = "Sign a file for fs-verity built-in signature verification", .usage_str = " fsverity sign FILE OUT_SIGFILE\n" " [--key=KEYFILE] [--cert=CERTFILE] [--pkcs11-engine=SOFILE]\n" diff --git a/scripts/do-release.sh b/scripts/do-release.sh index 9f6bf73..3f68497 100755 --- a/scripts/do-release.sh +++ b/scripts/do-release.sh @@ -9,44 +9,73 @@ set -e -u -o pipefail cd "$(dirname "$0")/.." -if [ $# != 1 ]; then - echo "Usage: $0 VERS" 1>&2 - echo " e.g. $0 1.0" 1>&2 +usage() +{ + echo "Usage: $0 prepare|publish VERS" 1>&2 + echo " e.g. $0 prepare 1.0" 1>&2 + echo " $0 publish 1.0" 1>&2 exit 2 +} + +if [ $# != 2 ]; then + usage fi -VERS=$1 +PUBLISH=false +case $1 in +publish) + PUBLISH=true + ;; +prepare) + ;; +*) + usage + ;; +esac +VERS=$2 PKG=fsverity-utils-$VERS -git checkout -f -git clean -fdx -./scripts/run-tests.sh -git clean -fdx - -major=$(echo "$VERS" | cut -d. -f1) -minor=$(echo "$VERS" | cut -d. -f2) -month=$(LC_ALL=C date +%B) -year=$(LC_ALL=C date +%Y) - -sed -E -i -e "/FSVERITY_UTILS_MAJOR_VERSION/s/[0-9]+/$major/" \ - -e "/FSVERITY_UTILS_MINOR_VERSION/s/[0-9]+/$minor/" \ - include/libfsverity.h -sed -E -i "/Version:/s/[0-9]+\.[0-9]+/$VERS/" \ - lib/libfsverity.pc.in -sed -E -i -e "/^% /s/fsverity-utils v[0-9]+(\.[0-9]+)+/fsverity-utils v$VERS/" \ - -e "/^% /s/[a-zA-Z]+ 2[0-9]{3}/$month $year/" \ - man/*.[1-9].md -git commit -a --signoff --message="v$VERS" -git tag --sign "v$VERS" --message="$PKG" - -git archive "v$VERS" --prefix="$PKG/" > "$PKG.tar" -tar xf "$PKG.tar" -( cd "$PKG" && make check ) -rm -r "$PKG" - -gpg --detach-sign --armor "$PKG.tar" -DESTDIR=/pub/linux/kernel/people/ebiggers/fsverity-utils/v$VERS -kup mkdir "$DESTDIR" -kup put "$PKG.tar" "$PKG.tar.asc" "$DESTDIR/$PKG.tar.gz" -git push -git push --tags +prepare_release() +{ + git checkout -f + git clean -fdx + ./scripts/run-tests.sh + git clean -fdx + + major=$(echo "$VERS" | cut -d. -f1) + minor=$(echo "$VERS" | cut -d. -f2) + month=$(LC_ALL=C date +%B) + year=$(LC_ALL=C date +%Y) + + sed -E -i -e "/FSVERITY_UTILS_MAJOR_VERSION/s/[0-9]+/$major/" \ + -e "/FSVERITY_UTILS_MINOR_VERSION/s/[0-9]+/$minor/" \ + include/libfsverity.h + sed -E -i "/Version:/s/[0-9]+\.[0-9]+/$VERS/" \ + lib/libfsverity.pc.in + sed -E -i -e "/^% /s/fsverity-utils v[0-9]+(\.[0-9]+)+/fsverity-utils v$VERS/" \ + -e "/^% /s/[a-zA-Z]+ 2[0-9]{3}/$month $year/" \ + man/*.[1-9].md + git commit -a --signoff --message="v$VERS" + git tag --sign "v$VERS" --message="$PKG" + + git archive "v$VERS" --prefix="$PKG/" > "$PKG.tar" + tar xf "$PKG.tar" + ( cd "$PKG" && make check ) + rm -r "$PKG" +} + +publish_release() +{ + gpg --detach-sign --armor "$PKG.tar" + DESTDIR=/pub/linux/kernel/people/ebiggers/fsverity-utils/v$VERS + kup mkdir "$DESTDIR" + kup put "$PKG.tar" "$PKG.tar.asc" "$DESTDIR/$PKG.tar.gz" + git push + git push --tags +} + +if $PUBLISH; then + publish_release +else + prepare_release +fi diff --git a/scripts/run-sparse.sh b/scripts/run-sparse.sh index f75b837..b8d37c1 100755 --- a/scripts/run-sparse.sh +++ b/scripts/run-sparse.sh @@ -8,7 +8,7 @@ set -e -u -o pipefail -find . -name '*.c' | while read -r file; do +find programs lib -name '*.c' | while read -r file; do sparse "$file" -gcc-base-dir "$(gcc --print-file-name=)" \ -Iinclude -D_FILE_OFFSET_BITS=64 -Wbitwise -D_GNU_SOURCE done diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index fb21c39..e2a4e38 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -17,11 +17,13 @@ set -e -u -o pipefail cd "$(dirname "$0")/.." -log() { +log() +{ echo "[$(date)] $*" 1>&2 } -fail() { +fail() +{ echo "FAIL: $*" 1>&2 exit 1 } @@ -38,31 +40,44 @@ exec 2> >(tee -ia run-tests.log 1>&2) MAKE="make -j$(getconf _NPROCESSORS_ONLN)" -log "Build and test with statically linking" -$MAKE CFLAGS="-Werror" -if ldd fsverity | grep libfsverity.so; then - fail "fsverity binary should be statically linked to libfsverity by default" -fi -./fsverity --version - -log "Check that all global symbols are prefixed with \"libfsverity_\"" -if nm libfsverity.a | grep ' T ' | grep -v " libfsverity_"; then - fail "Some global symbols are not prefixed with \"libfsverity_\"" -fi +TEST_FUNCS=() -log "Build and test with dynamic linking" -$MAKE CFLAGS="-Werror" USE_SHARED_LIB=1 check -if ! ldd fsverity | grep libfsverity.so; then - fail "fsverity binary should be dynamically linked to libfsverity when USE_SHARED_LIB=1" -fi +static_linking_test() +{ + log "Build and test with statically linking" + $MAKE CFLAGS="-Werror" + if ldd fsverity | grep libfsverity.so; then + fail "fsverity binary should be statically linked to libfsverity by default" + fi + ./fsverity --version + + log "Check that all global symbols are prefixed with \"libfsverity_\"" + if nm libfsverity.a | grep ' T ' | grep -v " libfsverity_"; then + fail "Some global symbols are not prefixed with \"libfsverity_\"" + fi +} +TEST_FUNCS+=(static_linking_test) -log "Check that all exported symbols are prefixed with \"libfsverity_\"" -if nm libfsverity.so | grep ' T ' | grep -v " libfsverity_"; then - fail "Some exported symbols are not prefixed with \"libfsverity_\"" -fi +dynamic_linking_test() +{ + log "Build and test with dynamic linking" + $MAKE CFLAGS="-Werror" USE_SHARED_LIB=1 check + if ! ldd fsverity | grep libfsverity.so; then + fail "fsverity binary should be dynamically linked to libfsverity when USE_SHARED_LIB=1" + fi + + log "Check that all exported symbols are prefixed with \"libfsverity_\"" + if nm libfsverity.so | grep ' T ' | grep -v " libfsverity_"; then + fail "Some exported symbols are not prefixed with \"libfsverity_\"" + fi +} +TEST_FUNCS+=(dynamic_linking_test) -log "Test using libfsverity from C++ program" -cat > "$TMPDIR/test.cc" <<EOF +cplusplus_test() +{ + $MAKE CFLAGS="-Werror" libfsverity.so + log "Test using libfsverity from C++ program" + cat > "$TMPDIR/test.cc" <<EOF #include <libfsverity.h> #include <iostream> int main() @@ -70,127 +85,231 @@ int main() std::cout << libfsverity_get_digest_size(FS_VERITY_HASH_ALG_SHA256) << std::endl; } EOF -c++ -Wall -Werror "$TMPDIR/test.cc" -Iinclude -L. -lfsverity -o "$TMPDIR/test" -[ "$(LD_LIBRARY_PATH=. "$TMPDIR/test")" = "32" ] -rm "${TMPDIR:?}"/* - -log "Check that build doesn't produce untracked files" -$MAKE CFLAGS="-Werror" all test_programs -if git status --short | grep -q '^??'; then - git status - fail "Build produced untracked files (check 'git status'). Missing gitignore entry?" -fi + c++ -Wall -Werror "$TMPDIR/test.cc" -Iinclude -L. -lfsverity -o "$TMPDIR/test" + [ "$(LD_LIBRARY_PATH=. "$TMPDIR/test")" = "32" ] + rm "${TMPDIR:?}"/* +} +TEST_FUNCS+=(cplusplus_test) -log "Test that 'make uninstall' uninstalls all files" -make DESTDIR="$TMPDIR" install -if [ "$(find "$TMPDIR" -type f -o -type l | wc -l)" = 0 ]; then - fail "'make install' didn't install any files" -fi -make DESTDIR="$TMPDIR" uninstall -if [ "$(find "$TMPDIR" -type f -o -type l | wc -l)" != 0 ]; then - fail "'make uninstall' didn't uninstall all files" -fi -rm -r "${TMPDIR:?}"/* - -log "Build, install, and uninstall with dash" -make clean SHELL=/bin/dash -make DESTDIR="$TMPDIR" SHELL=/bin/dash install -make DESTDIR="$TMPDIR" SHELL=/bin/dash uninstall - -log "Check that all files have license and copyright info" -list="$TMPDIR/filelist" -filter_license_info() { - # files to exclude from license and copyright info checks - grep -E -v '(\.gitignore|LICENSE|.*\.md|testdata|fsverity_uapi\.h|libfsverity\.pc\.in)' -} -git grep -L 'SPDX-License-Identifier: MIT' \ - | filter_license_info > "$list" || true -if [ -s "$list" ]; then - fail "The following files are missing an appropriate SPDX license identifier: $(<"$list")" -fi -# For now some people still prefer a free-form license statement, not just SPDX. -git grep -L 'Use of this source code is governed by an MIT-style' \ - | filter_license_info > "$list" || true -if [ -s "$list" ]; then - fail "The following files are missing an appropriate license statement: $(<"$list")" -fi -git grep -L '\<Copyright\>' | filter_license_info > "$list" || true -if [ -s "$list" ]; then - fail "The following files are missing a copyright statement: $(<"$list")" -fi -rm "$list" +untracked_files_test() +{ + log "Check that build doesn't produce untracked files" + $MAKE CFLAGS="-Werror" all test_programs + if git status --short | grep -q '^??'; then + git status + fail "Build produced untracked files (check 'git status'). Missing gitignore entry?" + fi +} +TEST_FUNCS+=(untracked_files_test) -log "Build and test with gcc (-O2)" -$MAKE CC=gcc CFLAGS="-O2 -Werror" check +uninstall_test() +{ + log "Test that 'make uninstall' uninstalls all files" + make DESTDIR="$TMPDIR" install + if [ "$(find "$TMPDIR" -type f -o -type l | wc -l)" = 0 ]; then + fail "'make install' didn't install any files" + fi + make DESTDIR="$TMPDIR" uninstall + if [ "$(find "$TMPDIR" -type f -o -type l | wc -l)" != 0 ]; then + fail "'make uninstall' didn't uninstall all files" + fi + rm -r "${TMPDIR:?}"/* +} +TEST_FUNCS+=(uninstall_test) -log "Build and test with gcc (-O3)" -$MAKE CC=gcc CFLAGS="-O3 -Werror" check +dash_test() +{ + log "Build, install, and uninstall with dash" + make clean SHELL=/bin/dash + make DESTDIR="$TMPDIR" SHELL=/bin/dash install + make DESTDIR="$TMPDIR" SHELL=/bin/dash uninstall +} +TEST_FUNCS+=(dash_test) + +license_test() +{ + log "Check that all files have license and copyright info" + list="$TMPDIR/filelist" + filter_license_info() { + # files to exclude from license and copyright info checks + grep -E -v '(\.gitignore|LICENSE|.*\.md|testdata|fsverity_uapi\.h|libfsverity\.pc\.in)' + } + git grep -L 'SPDX-License-Identifier: MIT' \ + | filter_license_info > "$list" || true + if [ -s "$list" ]; then + fail "The following files are missing an appropriate SPDX license identifier: $(<"$list")" + fi + # For now some people still prefer a free-form license statement, not just SPDX. + git grep -L 'Use of this source code is governed by an MIT-style' \ + | filter_license_info > "$list" || true + if [ -s "$list" ]; then + fail "The following files are missing an appropriate license statement: $(<"$list")" + fi + git grep -L '\<Copyright\>' | filter_license_info > "$list" || true + if [ -s "$list" ]; then + fail "The following files are missing a copyright statement: $(<"$list")" + fi + rm "$list" +} +TEST_FUNCS+=(license_test) + +gcc_test() +{ + log "Build and test with gcc (-O2)" + $MAKE CC=gcc CFLAGS="-O2 -Werror" check -log "Build and test with gcc (32-bit)" -$MAKE CC=gcc CFLAGS="-O2 -Werror -m32" check + log "Build and test with gcc (-O3)" + $MAKE CC=gcc CFLAGS="-O3 -Werror" check +} +TEST_FUNCS+=(gcc_test) -log "Build and test with clang (-O2)" -$MAKE CC=clang CFLAGS="-O2 -Werror" check +clang_test() +{ + log "Build and test with clang (-O2)" + $MAKE CC=clang CFLAGS="-O2 -Werror" check -log "Build and test with clang (-O3)" -$MAKE CC=clang CFLAGS="-O3 -Werror" check + log "Build and test with clang (-O3)" + $MAKE CC=clang CFLAGS="-O3 -Werror" check +} +TEST_FUNCS+=(clang_test) -log "Build and test with clang + UBSAN" -$MAKE CC=clang \ - CFLAGS="-O2 -Werror -fsanitize=undefined -fno-sanitize-recover=undefined" \ - check +32bit_test() +{ + log "Build and test with gcc (32-bit)" + $MAKE CC=gcc CFLAGS="-O2 -Werror -m32" check +} +TEST_FUNCS+=(32bit_test) -log "Build and test with clang + ASAN" -$MAKE CC=clang \ - CFLAGS="-O2 -Werror -fsanitize=address -fno-sanitize-recover=address" \ - check +sanitizers_test() +{ + log "Build and test with clang + UBSAN" + $MAKE CC=clang \ + CFLAGS="-O2 -Werror -fsanitize=undefined -fno-sanitize-recover=undefined" \ + check + + log "Build and test with clang + ASAN" + $MAKE CC=clang \ + CFLAGS="-O2 -Werror -fsanitize=address -fno-sanitize-recover=address" \ + check + + log "Build and test with clang + unsigned integer overflow sanitizer" + $MAKE CC=clang \ + CFLAGS="-O2 -Werror -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=unsigned-integer-overflow" \ + check + + log "Build and test with clang + CFI" + $MAKE CC=clang CFLAGS="-O2 -Werror -fsanitize=cfi -flto -fvisibility=hidden" \ + AR=llvm-ar check +} +TEST_FUNCS+=(sanitizers_test) -log "Build and test with clang + unsigned integer overflow sanitizer" -$MAKE CC=clang \ - CFLAGS="-O2 -Werror -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=unsigned-integer-overflow" \ - check +valgrind_test() +{ + log "Build and test with valgrind" + $MAKE TEST_WRAPPER_PROG="valgrind --quiet --error-exitcode=100 --leak-check=full --errors-for-leak-kinds=all" \ + CFLAGS="-O2 -Werror" check +} +TEST_FUNCS+=(valgrind_test) -log "Build and test with clang + CFI" -$MAKE CC=clang CFLAGS="-O2 -Werror -fsanitize=cfi -flto -fvisibility=hidden" \ - check +boringssl_test() +{ + log "Build and test using BoringSSL instead of OpenSSL" + log "-> Building BoringSSL" + $MAKE boringssl + log "-> Building fsverity-utils linked to BoringSSL" + $MAKE CFLAGS="-O2 -Werror" LDFLAGS="-Lboringssl/build/crypto" \ + CPPFLAGS="-Iboringssl/include" LDLIBS="-lcrypto -lpthread" check +} +TEST_FUNCS+=(boringssl_test) -log "Build and test with valgrind" -$MAKE TEST_WRAPPER_PROG="valgrind --quiet --error-exitcode=100 --leak-check=full --errors-for-leak-kinds=all" \ - CFLAGS="-O2 -Werror" check +openssl1_test() +{ + log "Build and test using OpenSSL 1.0" + $MAKE CFLAGS="-O2 -Werror" LDFLAGS="-L/usr/lib/openssl-1.0" \ + CPPFLAGS="-I/usr/include/openssl-1.0" check +} +TEST_FUNCS+=(openssl1_test) -log "Build and test using BoringSSL instead of OpenSSL" -BSSL=$HOME/src/boringssl -$MAKE CFLAGS="-O2 -Werror" LDFLAGS="-L$BSSL/build/crypto" \ - CPPFLAGS="-I$BSSL/include" LDLIBS="-lcrypto -lpthread" check +openssl3_test() +{ + log "Build and test using OpenSSL 3.0" + OSSL3=$HOME/src/openssl/inst/usr/local + LD_LIBRARY_PATH="$OSSL3/lib64" $MAKE CFLAGS="-O2 -Werror" \ + LDFLAGS="-L$OSSL3/lib64" CPPFLAGS="-I$OSSL3/include" check +} +TEST_FUNCS+=(openssl3_test) -log "Build and test using OpenSSL 1.0" -$MAKE CFLAGS="-O2 -Werror" LDFLAGS="-L/usr/lib/openssl-1.0" \ - CPPFLAGS="-I/usr/include/openssl-1.0" check +unsigned_char_test() +{ + log "Build and test using -funsigned-char" + $MAKE CFLAGS="-O2 -Werror -funsigned-char" check +} +TEST_FUNCS+=(unsigned_char_test) -log "Build and test using OpenSSL 3.0" -OSSL3=$HOME/src/openssl/inst/usr/local -LD_LIBRARY_PATH="$OSSL3/lib64" $MAKE CFLAGS="-O2 -Werror" \ - LDFLAGS="-L$OSSL3/lib64" CPPFLAGS="-I$OSSL3/include" check +signed_char_test() +{ + log "Build and test using -fsigned-char" + $MAKE CFLAGS="-O2 -Werror -fsigned-char" check +} +TEST_FUNCS+=(signed_char_test) -log "Build and test using -funsigned-char" -$MAKE CFLAGS="-O2 -Werror -funsigned-char" check +windows_build_test() +{ + log "Cross-compile for Windows (32-bit)" + $MAKE CC=i686-w64-mingw32-gcc CFLAGS="-O2 -Werror" -log "Build and test using -fsigned-char" -$MAKE CFLAGS="-O2 -Werror -fsigned-char" check + log "Cross-compile for Windows (64-bit)" + $MAKE CC=x86_64-w64-mingw32-gcc CFLAGS="-O2 -Werror" +} +TEST_FUNCS+=(windows_build_test) -log "Cross-compile for Windows (32-bit)" -$MAKE CC=i686-w64-mingw32-gcc CFLAGS="-O2 -Werror" +sparse_test() +{ + log "Run sparse" + ./scripts/run-sparse.sh +} +TEST_FUNCS+=(sparse_test) -log "Cross-compile for Windows (64-bit)" -$MAKE CC=x86_64-w64-mingw32-gcc CFLAGS="-O2 -Werror" +clang_analyzer_test() +{ + log "Run clang static analyzer" + scan-build --status-bugs make CFLAGS="-O2 -Werror" all test_programs +} +TEST_FUNCS+=(clang_analyzer_test) -log "Run sparse" -./scripts/run-sparse.sh +shellcheck_test() +{ + log "Run shellcheck" + shellcheck scripts/*.sh 1>&2 +} +TEST_FUNCS+=(shellcheck_test) -log "Run clang static analyzer" -scan-build --status-bugs make CFLAGS="-O2 -Werror" all test_programs +test_exists() +{ + local tst=$1 + local func + for func in "${TEST_FUNCS[@]}"; do + if [ "${tst}_test" = "$func" ]; then + return 0 + fi + done + return 1 +} -log "Run shellcheck" -shellcheck scripts/*.sh 1>&2 +if [[ $# == 0 ]]; then + for func in "${TEST_FUNCS[@]}"; do + eval "$func" + done +else + for tst; do + if ! test_exists "$tst"; then + echo 1>&2 "Unknown test: $tst" + exit 2 + fi + done + for tst; do + eval "${tst}_test" + done +fi log "All tests passed!" |