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