#! /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 measurement via FS_IOC_MEASURE_VERITY # seq=`basename $0` seqres=$RESULT_DIR/$seq echo "QA output created by $seq" here=`pwd` tmp=/tmp/$$ status=1 # failure is the default! trap "_cleanup; exit \$status" 0 1 2 3 15 _cleanup() { cd / _restore_fsverity_signatures rm -f $tmp.* } # get standard environment, filters and checks . ./common/rc . ./common/filter . ./common/verity # remove previous $seqres.full before test rm -f $seqres.full # 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 verify_data_readable() { local file=$1 md5sum $file > /dev/null } verify_data_unreadable() { local file=$1 # try both reading just the first data block, and reading until EOF head -c $FSV_BLOCK_SIZE $file 2>&1 >/dev/null | _filter_scratch md5sum $file |& _filter_scratch } _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_scratch _fsv_scratch_begin_subtest "Enabling verity with invalid hash algorithm fails with EINVAL" _fsv_create_enable_file $fsv_file --hash-alg=257 |& _filter_scratch 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_scratch 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_scratch _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_scratch 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_scratch _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_scratch 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 $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 $fsv_file & sleep 0.5 _fsv_enable $fsv_file |& _filter_scratch 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_scratch echo "* bash >>, should be O_APPEND" bash -c "echo >> $fsv_file" |& _filter_scratch echo "* bash >, should be O_WRONLY|O_CREAT|O_TRUNC" bash -c "echo > $fsv_file" |& _filter_scratch _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 _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_scratch 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. for size in 1 $((FSV_BLOCK_SIZE - 1)) $FSV_BLOCK_SIZE; do _fsv_scratch_begin_subtest "verity on $size-byte file" 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 100M 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