• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/bash
2# SPDX-License-Identifier: MIT
3# Copyright 2020 Google LLC
4#
5# Use of this source code is governed by an MIT-style
6# license that can be found in the LICENSE file or at
7# https://opensource.org/licenses/MIT.
8#
9#
10# Test script for fsverity-utils.  Runs 'make check' in lots of configurations,
11# runs static analysis, and does a few other tests.
12#
13# Note: for more test coverage, in addition to running this script, also build
14# fsverity-utils into a kvm-xfstests test appliance and run
15# 'kvm-xfstests -c ext4,f2fs -g verity'
16
17set -e -u -o pipefail
18cd "$(dirname "$0")/.."
19
20log()
21{
22	echo "[$(date)] $*" 1>&2
23}
24
25fail()
26{
27	echo "FAIL: $*" 1>&2
28	exit 1
29}
30
31TMPDIR=$(mktemp -d -t libfsverity_test.XXXXXXXXX)
32trap 'rm -r "$TMPDIR"' EXIT
33
34# Both stdout and stderr go to log file.
35# Only stderr goes to terminal.
36echo "Starting fsverity-utils tests.  See run-tests.log for full output."
37rm -f run-tests.log
38exec >> run-tests.log
39exec 2> >(tee -ia run-tests.log 1>&2)
40
41MAKE="make -j$(getconf _NPROCESSORS_ONLN)"
42
43TEST_FUNCS=()
44
45static_linking_test()
46{
47	log "Build and test with statically linking"
48	$MAKE CFLAGS="-Werror"
49	if ldd fsverity | grep libfsverity.so; then
50		fail "fsverity binary should be statically linked to libfsverity by default"
51	fi
52	./fsverity --version
53
54	log "Check that all global symbols are prefixed with \"libfsverity_\""
55	if nm libfsverity.a | grep ' T ' | grep -v " libfsverity_"; then
56		fail "Some global symbols are not prefixed with \"libfsverity_\""
57	fi
58}
59TEST_FUNCS+=(static_linking_test)
60
61dynamic_linking_test()
62{
63	log "Build and test with dynamic linking"
64	$MAKE CFLAGS="-Werror" USE_SHARED_LIB=1 check
65	if ! ldd fsverity | grep libfsverity.so; then
66		fail "fsverity binary should be dynamically linked to libfsverity when USE_SHARED_LIB=1"
67	fi
68
69	log "Check that all exported symbols are prefixed with \"libfsverity_\""
70	if nm libfsverity.so | grep ' T ' | grep -v " libfsverity_"; then
71		fail "Some exported symbols are not prefixed with \"libfsverity_\""
72	fi
73}
74TEST_FUNCS+=(dynamic_linking_test)
75
76cplusplus_test()
77{
78	$MAKE CFLAGS="-Werror" libfsverity.so
79	log "Test using libfsverity from C++ program"
80	cat > "$TMPDIR/test.cc" <<EOF
81#include <libfsverity.h>
82#include <iostream>
83int main()
84{
85	std::cout << libfsverity_get_digest_size(FS_VERITY_HASH_ALG_SHA256) << std::endl;
86}
87EOF
88	c++ -Wall -Werror "$TMPDIR/test.cc" -Iinclude -L. -lfsverity -o "$TMPDIR/test"
89	[ "$(LD_LIBRARY_PATH=. "$TMPDIR/test")" = "32" ]
90	rm "${TMPDIR:?}"/*
91}
92TEST_FUNCS+=(cplusplus_test)
93
94untracked_files_test()
95{
96	log "Check that build doesn't produce untracked files"
97	$MAKE CFLAGS="-Werror" all test_programs
98	if git status --short | grep -q '^??'; then
99		git status
100		fail "Build produced untracked files (check 'git status').  Missing gitignore entry?"
101	fi
102}
103TEST_FUNCS+=(untracked_files_test)
104
105uninstall_test()
106{
107	log "Test that 'make uninstall' uninstalls all files"
108	make DESTDIR="$TMPDIR" install
109	if [ "$(find "$TMPDIR" -type f -o -type l | wc -l)" = 0 ]; then
110		fail "'make install' didn't install any files"
111	fi
112	make DESTDIR="$TMPDIR" uninstall
113	if [ "$(find "$TMPDIR" -type f -o -type l | wc -l)" != 0 ]; then
114		fail "'make uninstall' didn't uninstall all files"
115	fi
116	rm -r "${TMPDIR:?}"/*
117}
118TEST_FUNCS+=(uninstall_test)
119
120dash_test()
121{
122	log "Build, install, and uninstall with dash"
123	make clean SHELL=/bin/dash
124	make DESTDIR="$TMPDIR" SHELL=/bin/dash install
125	make DESTDIR="$TMPDIR" SHELL=/bin/dash uninstall
126}
127TEST_FUNCS+=(dash_test)
128
129license_test()
130{
131	log "Check that all files have license and copyright info"
132	list="$TMPDIR/filelist"
133	filter_license_info() {
134		# files to exclude from license and copyright info checks
135		grep -E -v '(\.gitignore|LICENSE|.*\.md|testdata|fsverity_uapi\.h|libfsverity\.pc\.in)'
136	}
137	git grep -L 'SPDX-License-Identifier: MIT' \
138		| filter_license_info > "$list" || true
139	if [ -s "$list" ]; then
140		fail "The following files are missing an appropriate SPDX license identifier: $(<"$list")"
141	fi
142	# For now some people still prefer a free-form license statement, not just SPDX.
143	git grep -L 'Use of this source code is governed by an MIT-style' \
144		| filter_license_info > "$list" || true
145	if [ -s "$list" ]; then
146		fail "The following files are missing an appropriate license statement: $(<"$list")"
147	fi
148	git grep -L '\<Copyright\>' | filter_license_info > "$list" || true
149	if [ -s "$list" ]; then
150		fail "The following files are missing a copyright statement: $(<"$list")"
151	fi
152	rm "$list"
153}
154TEST_FUNCS+=(license_test)
155
156gcc_test()
157{
158	log "Build and test with gcc (-O2)"
159	$MAKE CC=gcc CFLAGS="-O2 -Werror" check
160
161	log "Build and test with gcc (-O3)"
162	$MAKE CC=gcc CFLAGS="-O3 -Werror" check
163}
164TEST_FUNCS+=(gcc_test)
165
166clang_test()
167{
168	log "Build and test with clang (-O2)"
169	$MAKE CC=clang CFLAGS="-O2 -Werror" check
170
171	log "Build and test with clang (-O3)"
172	$MAKE CC=clang CFLAGS="-O3 -Werror" check
173}
174TEST_FUNCS+=(clang_test)
175
17632bit_test()
177{
178	log "Build and test with gcc (32-bit)"
179	$MAKE CC=gcc CFLAGS="-O2 -Werror -m32" check
180}
181TEST_FUNCS+=(32bit_test)
182
183sanitizers_test()
184{
185	log "Build and test with clang + UBSAN"
186	$MAKE CC=clang \
187		CFLAGS="-O2 -Werror -fsanitize=undefined -fno-sanitize-recover=undefined" \
188		check
189
190	log "Build and test with clang + ASAN"
191	$MAKE CC=clang \
192		CFLAGS="-O2 -Werror -fsanitize=address -fno-sanitize-recover=address" \
193		check
194
195	log "Build and test with clang + unsigned integer overflow sanitizer"
196	$MAKE CC=clang \
197		CFLAGS="-O2 -Werror -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=unsigned-integer-overflow" \
198		check
199
200	log "Build and test with clang + CFI"
201	$MAKE CC=clang CFLAGS="-O2 -Werror -fsanitize=cfi -flto -fvisibility=hidden" \
202		AR=llvm-ar check
203}
204TEST_FUNCS+=(sanitizers_test)
205
206valgrind_test()
207{
208	log "Build and test with valgrind"
209	$MAKE TEST_WRAPPER_PROG="valgrind --quiet --error-exitcode=100 --leak-check=full --errors-for-leak-kinds=all" \
210		CFLAGS="-O2 -Werror" check
211}
212TEST_FUNCS+=(valgrind_test)
213
214boringssl_test()
215{
216	log "Build and test using BoringSSL instead of OpenSSL"
217	log "-> Building BoringSSL"
218	$MAKE boringssl
219	log "-> Building fsverity-utils linked to BoringSSL"
220	$MAKE CFLAGS="-O2 -Werror" LDFLAGS="-Lboringssl/build/crypto" \
221		CPPFLAGS="-Iboringssl/include" LDLIBS="-lcrypto -lpthread" check
222}
223TEST_FUNCS+=(boringssl_test)
224
225openssl1_test()
226{
227	log "Build and test using OpenSSL 1.0"
228	$MAKE CFLAGS="-O2 -Werror" LDFLAGS="-L/usr/lib/openssl-1.0" \
229		CPPFLAGS="-I/usr/include/openssl-1.0" check
230}
231TEST_FUNCS+=(openssl1_test)
232
233openssl3_test()
234{
235	log "Build and test using OpenSSL 3.0"
236	OSSL3=$HOME/src/openssl/inst/usr/local
237	LD_LIBRARY_PATH="$OSSL3/lib64" $MAKE CFLAGS="-O2 -Werror" \
238		LDFLAGS="-L$OSSL3/lib64" CPPFLAGS="-I$OSSL3/include" check
239}
240TEST_FUNCS+=(openssl3_test)
241
242unsigned_char_test()
243{
244	log "Build and test using -funsigned-char"
245	$MAKE CFLAGS="-O2 -Werror -funsigned-char" check
246}
247TEST_FUNCS+=(unsigned_char_test)
248
249signed_char_test()
250{
251	log "Build and test using -fsigned-char"
252	$MAKE CFLAGS="-O2 -Werror -fsigned-char" check
253}
254TEST_FUNCS+=(signed_char_test)
255
256windows_build_test()
257{
258	log "Cross-compile for Windows (32-bit)"
259	$MAKE CC=i686-w64-mingw32-gcc CFLAGS="-O2 -Werror"
260
261	log "Cross-compile for Windows (64-bit)"
262	$MAKE CC=x86_64-w64-mingw32-gcc CFLAGS="-O2 -Werror"
263}
264TEST_FUNCS+=(windows_build_test)
265
266sparse_test()
267{
268	log "Run sparse"
269	./scripts/run-sparse.sh
270}
271TEST_FUNCS+=(sparse_test)
272
273clang_analyzer_test()
274{
275	log "Run clang static analyzer"
276	scan-build --status-bugs make CFLAGS="-O2 -Werror" all test_programs
277}
278TEST_FUNCS+=(clang_analyzer_test)
279
280shellcheck_test()
281{
282	log "Run shellcheck"
283	shellcheck scripts/*.sh 1>&2
284}
285TEST_FUNCS+=(shellcheck_test)
286
287test_exists()
288{
289	local tst=$1
290	local func
291	for func in "${TEST_FUNCS[@]}"; do
292		if [ "${tst}_test" = "$func" ]; then
293			return 0
294		fi
295	done
296	return 1
297}
298
299if [[ $# == 0 ]]; then
300	for func in "${TEST_FUNCS[@]}"; do
301		eval "$func"
302	done
303else
304	for tst; do
305		if ! test_exists "$tst"; then
306			echo 1>&2 "Unknown test: $tst"
307			exit 2
308		fi
309	done
310	for tst; do
311		eval "${tst}_test"
312	done
313fi
314
315log "All tests passed!"
316