mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
common/verity: add common functions for testing fs-verity
Add common functions for setting up and testing fs-verity. fs-verity is an ext4 and f2fs filesystem feature which provides Merkle tree based hashing (similar to dm-verity) for individual read-only files, mainly for the purpose of efficient authenticity verification. Other filesystems may add fs-verity support later, using the same API. Running the fs-verity tests will require: - Kernel v5.4-rc1 or later configured with CONFIG_FS_VERITY=y - The 'fsverity' utility program from https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/fsverity-utils.git - e2fsprogs v1.45.2 or later for ext4 tests, or f2fs-tools v1.11.0 or later for f2fs tests Some individual tests will have additional requirements. For more information about fs-verity, see https://www.kernel.org/doc/html/latest/filesystems/fsverity.html Signed-off-by: Eric Biggers <ebiggers@google.com> Reviewed-by: Eryu Guan <guaneryu@gmail.com> Signed-off-by: Eryu Guan <guaneryu@gmail.com>
This commit is contained in:
@@ -213,6 +213,7 @@ export CHECKBASHISMS_PROG="$(type -P checkbashisms)"
|
||||
export XFS_INFO_PROG="$(type -P xfs_info)"
|
||||
export DUPEREMOVE_PROG="$(type -P duperemove)"
|
||||
export CC_PROG="$(type -P cc)"
|
||||
export FSVERITY_PROG="$(type -P fsverity)"
|
||||
|
||||
# use 'udevadm settle' or 'udevsettle' to wait for lv to be settled.
|
||||
# newer systems have udevadm command but older systems like RHEL5 don't.
|
||||
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Functions for setting up and testing fs-verity
|
||||
|
||||
_require_scratch_verity()
|
||||
{
|
||||
_require_scratch
|
||||
_require_command "$FSVERITY_PROG" fsverity
|
||||
|
||||
if ! _scratch_mkfs_verity &>>$seqres.full; then
|
||||
# ext4: need e2fsprogs v1.44.5 or later (but actually v1.45.2+
|
||||
# is needed for some tests to pass, due to an e2fsck bug)
|
||||
# f2fs: need f2fs-tools v1.11.0 or later
|
||||
_notrun "$FSTYP userspace tools don't support fs-verity"
|
||||
fi
|
||||
|
||||
# Try to mount the filesystem. If this fails then either the kernel
|
||||
# isn't aware of fs-verity, or the mkfs options were not compatible with
|
||||
# verity (e.g. ext4 with block size != PAGE_SIZE).
|
||||
if ! _try_scratch_mount &>>$seqres.full; then
|
||||
_notrun "kernel is unaware of $FSTYP verity feature," \
|
||||
"or mkfs options are not compatible with verity"
|
||||
fi
|
||||
|
||||
# The filesystem may be aware of fs-verity but have it disabled by
|
||||
# CONFIG_FS_VERITY=n. Detect support via sysfs.
|
||||
if [ ! -e /sys/fs/$FSTYP/features/verity ]; then
|
||||
_notrun "kernel $FSTYP isn't configured with verity support"
|
||||
fi
|
||||
|
||||
# The filesystem may have fs-verity enabled but not actually usable by
|
||||
# default. E.g., ext4 only supports verity on extent-based files, so it
|
||||
# doesn't work on ext3-style filesystems. So, try actually using it.
|
||||
echo foo > $SCRATCH_MNT/tmpfile
|
||||
if ! _fsv_enable $SCRATCH_MNT/tmpfile; then
|
||||
_notrun "$FSTYP verity isn't usable by default with these mkfs options"
|
||||
fi
|
||||
rm -f $SCRATCH_MNT/tmpfile
|
||||
|
||||
_scratch_unmount
|
||||
|
||||
# Merkle tree block size. Currently all filesystems only support
|
||||
# PAGE_SIZE for this. This is also the default for 'fsverity enable'.
|
||||
FSV_BLOCK_SIZE=$(get_page_size)
|
||||
}
|
||||
|
||||
_scratch_mkfs_verity()
|
||||
{
|
||||
case $FSTYP in
|
||||
ext4|f2fs)
|
||||
_scratch_mkfs -O verity
|
||||
;;
|
||||
*)
|
||||
_notrun "No verity support for $FSTYP"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_scratch_mkfs_encrypted_verity()
|
||||
{
|
||||
case $FSTYP in
|
||||
ext4)
|
||||
_scratch_mkfs -O encrypt,verity
|
||||
;;
|
||||
f2fs)
|
||||
# f2fs-tools as of v1.11.0 doesn't allow comma-separated
|
||||
# features with -O. Instead -O must be supplied multiple times.
|
||||
_scratch_mkfs -O encrypt -O verity
|
||||
;;
|
||||
*)
|
||||
_notrun "$FSTYP not supported in _scratch_mkfs_encrypted_verity"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_fsv_scratch_begin_subtest()
|
||||
{
|
||||
local msg=$1
|
||||
|
||||
rm -rf "${SCRATCH_MNT:?}"/*
|
||||
echo -e "\n# $msg"
|
||||
}
|
||||
|
||||
_fsv_enable()
|
||||
{
|
||||
$FSVERITY_PROG enable "$@"
|
||||
}
|
||||
|
||||
_fsv_measure()
|
||||
{
|
||||
$FSVERITY_PROG measure "$@" | awk '{print $1}'
|
||||
}
|
||||
|
||||
# Generate a file, then enable verity on it.
|
||||
_fsv_create_enable_file()
|
||||
{
|
||||
local file=$1
|
||||
shift
|
||||
|
||||
head -c $((FSV_BLOCK_SIZE * 2)) /dev/zero > "$file"
|
||||
_fsv_enable "$file" "$@"
|
||||
}
|
||||
|
||||
_fsv_have_hash_algorithm()
|
||||
{
|
||||
local hash_alg=$1
|
||||
local test_file=$2
|
||||
|
||||
rm -f $test_file
|
||||
head -c 4096 /dev/zero > $test_file
|
||||
if ! _fsv_enable --hash-alg=$hash_alg $test_file &>> $seqres.full; then
|
||||
# no kernel support
|
||||
return 1
|
||||
fi
|
||||
rm -f $test_file
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# _fsv_scratch_corrupt_bytes - Write some bytes to a file, bypassing the filesystem
|
||||
#
|
||||
# Write the bytes sent on stdin to the given offset in the given file, but do so
|
||||
# by writing directly to the extents on the block device, with the filesystem
|
||||
# unmounted. This can be used to corrupt a verity file for testing purposes,
|
||||
# bypassing the restrictions imposed by the filesystem.
|
||||
#
|
||||
# The file is assumed to be located on $SCRATCH_DEV.
|
||||
#
|
||||
_fsv_scratch_corrupt_bytes()
|
||||
{
|
||||
local file=$1
|
||||
local offset=$2
|
||||
local lstart lend pstart pend
|
||||
local dd_cmds=()
|
||||
local cmd
|
||||
|
||||
sync # Sync to avoid unwritten extents
|
||||
|
||||
cat > $tmp.bytes
|
||||
local end=$(( offset + $(stat -c %s $tmp.bytes ) ))
|
||||
|
||||
# For each extent that intersects the requested range in order, add a
|
||||
# command that writes the next part of the data to that extent.
|
||||
while read -r lstart lend pstart pend; do
|
||||
lstart=$((lstart * 512))
|
||||
lend=$(((lend + 1) * 512))
|
||||
pstart=$((pstart * 512))
|
||||
pend=$(((pend + 1) * 512))
|
||||
|
||||
if (( lend - lstart != pend - pstart )); then
|
||||
_fail "Logical and physical extent lengths differ for file '$file'"
|
||||
elif (( offset < lstart )); then
|
||||
_fail "Hole in file '$file' at byte $offset. Next extent begins at byte $lstart"
|
||||
elif (( offset < lend )); then
|
||||
local len=$((lend - offset))
|
||||
local seek=$((pstart + (offset - lstart)))
|
||||
dd_cmds+=("head -c $len | dd of=$SCRATCH_DEV oflag=seek_bytes seek=$seek status=none")
|
||||
(( offset += len ))
|
||||
fi
|
||||
done < <($XFS_IO_PROG -r -c "fiemap $offset $((end - offset))" "$file" \
|
||||
| _filter_xfs_io_fiemap)
|
||||
|
||||
if (( offset < end )); then
|
||||
_fail "Extents of file '$file' ended at byte $offset, but needed until $end"
|
||||
fi
|
||||
|
||||
# Execute the commands to write the data
|
||||
_scratch_unmount
|
||||
for cmd in "${dd_cmds[@]}"; do
|
||||
eval "$cmd"
|
||||
done < $tmp.bytes
|
||||
sync # Sync to flush the block device's pagecache
|
||||
_scratch_mount
|
||||
}
|
||||
|
||||
#
|
||||
# _fsv_scratch_corrupt_merkle_tree - Corrupt a file's Merkle tree
|
||||
#
|
||||
# Like _fsv_scratch_corrupt_bytes(), but this corrupts the file's fs-verity
|
||||
# Merkle tree. The offset is given as a byte offset into the Merkle tree.
|
||||
#
|
||||
_fsv_scratch_corrupt_merkle_tree()
|
||||
{
|
||||
local file=$1
|
||||
local offset=$2
|
||||
|
||||
case $FSTYP in
|
||||
ext4|f2fs)
|
||||
# ext4 and f2fs store the Merkle tree after the file contents
|
||||
# itself, starting at the next 65536-byte aligned boundary.
|
||||
(( offset += ($(stat -c %s $file) + 65535) & ~65535 ))
|
||||
_fsv_scratch_corrupt_bytes $file $offset
|
||||
;;
|
||||
*)
|
||||
_fail "_fsv_scratch_corrupt_merkle_tree() unimplemented on $FSTYP"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
Reference in New Issue
Block a user