| #! /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 | 
 | # | 
 | . ./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 | 
 |  | 
 | 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 |