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