#! /bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright 2018 Google LLC # # FS QA Test generic/572 # # This is a basic fs-verity test which verifies: # # - conditions for enabling verity # - verity files have correct contents and size # - can't change contents of verity files, but can change metadata # - can retrieve a verity file's digest via FS_IOC_MEASURE_VERITY # . ./common/preamble _begin_fstest auto quick verity # Override the default cleanup function. _cleanup() { cd / _restore_fsverity_signatures rm -f $tmp.* } # Import common functions. . ./common/filter . ./common/verity # real QA test starts here _supported_fs generic _require_scratch_verity _disable_fsverity_signatures _scratch_mkfs_verity &>> $seqres.full _scratch_mount fsv_orig_file=$SCRATCH_MNT/file fsv_file=$SCRATCH_MNT/file.fsv filter_output() { _filter_bash | _filter_scratch } verify_data_readable() { local file=$1 md5sum $file > /dev/null } _fsv_scratch_begin_subtest "Enabling verity on file with verity already enabled fails with EEXIST" _fsv_create_enable_file $fsv_file echo "(trying again)" _fsv_enable $fsv_file |& filter_output _fsv_scratch_begin_subtest "Enabling verity with invalid hash algorithm fails with EINVAL" _fsv_create_enable_file $fsv_file --hash-alg=257 |& filter_output verify_data_readable $fsv_file _fsv_scratch_begin_subtest "Enabling verity with invalid block size fails with EINVAL" _fsv_create_enable_file $fsv_file --block-size=1 |& filter_output verify_data_readable $fsv_file _fsv_scratch_begin_subtest "Enabling verity on directory fails with EISDIR" mkdir $SCRATCH_MNT/dir _fsv_enable $SCRATCH_MNT/dir |& filter_output _fsv_scratch_begin_subtest "Enabling verity with too-long salt fails with EMSGSIZE" _fsv_create_enable_file $fsv_file --salt=$(perl -e 'print "A" x 1000') |& filter_output verify_data_readable $fsv_file _fsv_scratch_begin_subtest "Enabling verity on file on read-only filesystem fails with EROFS" echo foo > $fsv_file _scratch_remount ro _fsv_enable $fsv_file |& filter_output _scratch_remount rw _fsv_scratch_begin_subtest "Enabling verity on file open for writing fails with ETXTBSY" echo foo > $fsv_file exec 3<> $fsv_file _fsv_enable $fsv_file |& filter_output exec 3<&- verify_data_readable $fsv_file _fsv_scratch_begin_subtest "Enabling verity can be interrupted" dd if=/dev/zero of=$fsv_file bs=1 count=0 seek=$((1 << 34)) status=none start_time=$(date +%s) $FSVERITY_PROG enable --block-size=$FSV_BLOCK_SIZE $fsv_file & sleep 0.5 kill %1 wait elapsed=$(( $(date +%s) - start_time )) if (( elapsed > 5 )); then echo "Failed to interrupt FS_IOC_ENABLE_VERITY ($elapsed seconds elapsed)" fi _fsv_scratch_begin_subtest "Enabling verity on file with verity already being enabled fails with EBUSY" dd if=/dev/zero of=$fsv_file bs=1 count=0 seek=$((1 << 34)) status=none start_time=$(date +%s) $FSVERITY_PROG enable --block-size=$FSV_BLOCK_SIZE $fsv_file & sleep 0.5 _fsv_enable $fsv_file |& filter_output kill %1 wait _fsv_scratch_begin_subtest "verity file can't be opened for writing" _fsv_create_enable_file $fsv_file >> $seqres.full echo "* reading" $XFS_IO_PROG -r $fsv_file -c '' echo "* xfs_io writing, should be O_RDWR" $XFS_IO_PROG $fsv_file -c '' |& filter_output echo "* bash >>, should be O_APPEND" bash -c "echo >> $fsv_file" |& filter_output echo "* bash >, should be O_WRONLY|O_CREAT|O_TRUNC" bash -c "echo > $fsv_file" |& filter_output _fsv_scratch_begin_subtest "verity file can be read" _fsv_create_enable_file $fsv_file >> $seqres.full verify_data_readable $fsv_file _fsv_scratch_begin_subtest "verity file can be measured" _fsv_create_enable_file $fsv_file >> $seqres.full _fsv_measure $fsv_file | _filter_fsverity_digest _fsv_scratch_begin_subtest "verity file can be renamed" _fsv_create_enable_file $fsv_file mv $fsv_file $fsv_file.newname _fsv_scratch_begin_subtest "verity file can be unlinked" _fsv_create_enable_file $fsv_file rm $fsv_file _fsv_scratch_begin_subtest "verity file can be linked to" _fsv_create_enable_file $fsv_file ln $fsv_file $fsv_file.newname _fsv_scratch_begin_subtest "verity file can be chmodded" _fsv_create_enable_file $fsv_file chmod 777 $fsv_file chmod 444 $fsv_file _fsv_scratch_begin_subtest "verity file can be chowned" _fsv_create_enable_file $fsv_file chown 1:1 $fsv_file chown 0:0 $fsv_file _fsv_scratch_begin_subtest "verity file has correct contents and size" head -c 100000 /dev/urandom > $fsv_orig_file cp $fsv_orig_file $fsv_file _fsv_enable $fsv_file >> $seqres.full cmp $fsv_file $fsv_orig_file _get_filesize $fsv_file _scratch_cycle_mount cmp $fsv_file $fsv_orig_file _get_filesize $fsv_file _fsv_scratch_begin_subtest "Trying to measure non-verity file fails with ENODATA" echo foo > $fsv_file _fsv_measure $fsv_file |& filter_output verify_data_readable $fsv_file # Test files <= 1 block in size. These are a bit of a special case since there # are no hash blocks; the root hash is calculated directly over the data block. _fsv_scratch_begin_subtest "verity on small files" for size in 1 $((FSV_BLOCK_SIZE - 1)) $FSV_BLOCK_SIZE; do head -c $size /dev/urandom > $fsv_orig_file cp $fsv_orig_file $fsv_file _fsv_enable $fsv_file cmp $fsv_orig_file $fsv_file && echo "Files matched" rm -f $fsv_file done _fsv_scratch_begin_subtest "verity on 100MB file (multiple levels in hash tree)" head -c 100000000 /dev/urandom > $fsv_orig_file cp $fsv_orig_file $fsv_file _fsv_enable $fsv_file cmp $fsv_orig_file $fsv_file && echo "Files matched" _fsv_scratch_begin_subtest "verity on sparse file" dd if=/dev/zero of=$fsv_orig_file bs=1 count=1 seek=1000000 status=none cp $fsv_orig_file $fsv_file _fsv_enable $fsv_file cmp $fsv_orig_file $fsv_file && echo "Files matched" # success, all done status=0 exit