blob: d1d6d846339a80aaa28db556ffea684c02409219 [file] [log] [blame]
#! /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