* [PATCH v8 0/5] tests for btrfs fsverity
@ 2022-03-16 20:25 Boris Burkov
2022-03-16 20:25 ` [PATCH v8 1/5] common/verity: require corruption functionality Boris Burkov
` (5 more replies)
0 siblings, 6 replies; 15+ messages in thread
From: Boris Burkov @ 2022-03-16 20:25 UTC (permalink / raw)
To: fstests, linux-fscrypt, linux-btrfs, kernel-team
This patchset provides tests for fsverity support in btrfs.
It includes modifications for generic tests to pass with btrfs as well
as new tests.
--
v8:
- reorganize to have a patch for enabling generic tests followed by the
patches with new and specific tests.
- fix some rebasing miscues from v7.
- fix a chunk of space characters instead of a tab in the new requires
function.
v7:
- add a new patch to make the new corruption requires more clear
- require corruption in generic/576
- require only btrfs_corrupt_block in btrfs/290
- add missing xfs_io requirements in btrfs/290
- remove unneeded zero byte check from btrfs corruption function
- fix sloppy extras in generic/690
v6:
- refactor "requires" for verity corruption tests so that other verity
tests can run on btrfs even without the corruption command available.
Also, explictly require xfs_io fiemap for all corruption tests.
- simplify and clarify "non-trivial EFBIG" calculation and documentation
per suggestions by Eric Biggers.
- remove unnecessary adjustment to max file size in the new EFBIG test;
the bug it worked around has been fixed.
v5:
- more idiomatic requires structure for making efbig test generic
- make efbig test use truncate instead of pwrite for making a big file
- improve documentation for efbig test approximation
- fix underscores vs dashes in btrfs_requires_corrupt_block
- improvements in missing/redundant requires invocations
- move orphan test image file to $TEST_DIR
- make orphan test replay/snapshot device size depend on log device
instead of hard-coding it.
- rebase (signicant: no more "groups" file; use preamble)
v4:
- mark local variables
- get rid of redundant mounts and syncs
- use '_' in function names correctly
- add a test for the EFBIG case
- reduce usage of requires_btrfs_corrupt_block
- handle variable input when corrupting merkle tree
v3: rebase onto xfstests master branch
v2: pass generic tests, add logwrites test
Boris Burkov (5):
common/verity: require corruption functionality
common/verity: support btrfs in generic fsverity tests
btrfs: test btrfs specific fsverity corruption
btrfs: test verity orphans with dmlogwrites
generic: test fs-verity EFBIG scenarios
common/btrfs | 5 ++
common/config | 1 +
common/verity | 40 ++++++++++
tests/btrfs/290 | 168 ++++++++++++++++++++++++++++++++++++++++++
tests/btrfs/290.out | 25 +++++++
tests/btrfs/291 | 161 ++++++++++++++++++++++++++++++++++++++++
tests/btrfs/291.out | 2 +
tests/generic/574 | 1 +
tests/generic/576 | 1 +
tests/generic/690 | 64 ++++++++++++++++
tests/generic/690.out | 7 ++
11 files changed, 475 insertions(+)
create mode 100755 tests/btrfs/290
create mode 100644 tests/btrfs/290.out
create mode 100755 tests/btrfs/291
create mode 100644 tests/btrfs/291.out
create mode 100755 tests/generic/690
create mode 100644 tests/generic/690.out
--
2.31.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v8 1/5] common/verity: require corruption functionality
2022-03-16 20:25 [PATCH v8 0/5] tests for btrfs fsverity Boris Burkov
@ 2022-03-16 20:25 ` Boris Burkov
2022-03-17 18:16 ` Eric Biggers
2022-03-16 20:25 ` [PATCH v8 2/5] common/verity: support btrfs in generic fsverity tests Boris Burkov
` (4 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Boris Burkov @ 2022-03-16 20:25 UTC (permalink / raw)
To: fstests, linux-fscrypt, linux-btrfs, kernel-team
Corrupting ext4 and f2fs relies on xfs_io fiemap. Btrfs corruption
testing will rely on a btrfs specific corruption utility. Add the
ability to require corruption functionality to make this properly
modular. To start, just check for fiemap, as that is needed
universally for _fsv_scratch_corrupt_bytes.
Signed-off-by: Boris Burkov <boris@bur.io>
---
common/verity | 6 ++++++
tests/generic/574 | 1 +
tests/generic/576 | 1 +
3 files changed, 8 insertions(+)
diff --git a/common/verity b/common/verity
index 38eea157..d58cad90 100644
--- a/common/verity
+++ b/common/verity
@@ -141,6 +141,12 @@ _require_fsverity_dump_metadata()
_fail "Unexpected output from 'fsverity dump_metadata': $(<"$tmpfile")"
}
+# Check for userspace tools needed to corrupt verity data or metadata.
+_require_fsverity_corruption()
+{
+ _require_xfs_io_command "fiemap"
+}
+
_scratch_mkfs_verity()
{
case $FSTYP in
diff --git a/tests/generic/574 b/tests/generic/574
index 882baa21..17fdea52 100755
--- a/tests/generic/574
+++ b/tests/generic/574
@@ -28,6 +28,7 @@ _cleanup()
_supported_fs generic
_require_scratch_verity
_disable_fsverity_signatures
+_require_fsverity_corruption
_scratch_mkfs_verity &>> $seqres.full
_scratch_mount
diff --git a/tests/generic/576 b/tests/generic/576
index 82fbdd71..d3e0a2d6 100755
--- a/tests/generic/576
+++ b/tests/generic/576
@@ -28,6 +28,7 @@ _supported_fs generic
_require_scratch_verity
_require_scratch_encryption
_require_command "$KEYCTL_PROG" keyctl
+_require_fsverity_corruption
_disable_fsverity_signatures
_scratch_mkfs_encrypted_verity &>> $seqres.full
--
2.31.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 2/5] common/verity: support btrfs in generic fsverity tests
2022-03-16 20:25 [PATCH v8 0/5] tests for btrfs fsverity Boris Burkov
2022-03-16 20:25 ` [PATCH v8 1/5] common/verity: require corruption functionality Boris Burkov
@ 2022-03-16 20:25 ` Boris Burkov
2022-03-17 18:16 ` Eric Biggers
2022-03-16 20:25 ` [PATCH v8 3/5] btrfs: test btrfs specific fsverity corruption Boris Burkov
` (3 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Boris Burkov @ 2022-03-16 20:25 UTC (permalink / raw)
To: fstests, linux-fscrypt, linux-btrfs, kernel-team
generic/572-579 have tests for fsverity. Now that btrfs supports
fsverity, make these tests function as well. For a majority of the tests
that pass, simply adding the case to mkfs a btrfs filesystem with no
extra options is sufficient.
However, generic/574 has tests for corrupting the merkle tree itself.
Since btrfs uses a different scheme from ext4 and f2fs for storing this
data, the existing logic for corrupting it doesn't work out of the box.
Adapt it to properly corrupt btrfs merkle items.
576 does not run because btrfs does not support transparent encryption.
This test relies on the btrfs implementation of fsverity in the patch:
btrfs: initial fsverity support
and on btrfs-corrupt-block for corruption in the patches titled:
btrfs-progs: corrupt generic item data with btrfs-corrupt-block
btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block
Signed-off-by: Boris Burkov <boris@bur.io>
---
common/btrfs | 5 +++++
common/config | 1 +
common/verity | 23 +++++++++++++++++++++++
3 files changed, 29 insertions(+)
diff --git a/common/btrfs b/common/btrfs
index 670d9d1f..c3a7dc6e 100644
--- a/common/btrfs
+++ b/common/btrfs
@@ -511,3 +511,8 @@ _btrfs_metadump()
$BTRFS_IMAGE_PROG "$device" "$dumpfile"
[ -n "$DUMP_COMPRESSOR" ] && $DUMP_COMPRESSOR -f "$dumpfile" &> /dev/null
}
+
+_require_btrfs_corrupt_block()
+{
+ _require_command "$BTRFS_CORRUPT_BLOCK_PROG" btrfs-corrupt-block
+}
diff --git a/common/config b/common/config
index 479e50d1..67bdf912 100644
--- a/common/config
+++ b/common/config
@@ -296,6 +296,7 @@ export BTRFS_UTIL_PROG=$(type -P btrfs)
export BTRFS_SHOW_SUPER_PROG=$(type -P btrfs-show-super)
export BTRFS_CONVERT_PROG=$(type -P btrfs-convert)
export BTRFS_TUNE_PROG=$(type -P btrfstune)
+export BTRFS_CORRUPT_BLOCK_PROG=$(type -P btrfs-corrupt-block)
export XFS_FSR_PROG=$(type -P xfs_fsr)
export MKFS_NFS_PROG="false"
export MKFS_CIFS_PROG="false"
diff --git a/common/verity b/common/verity
index d58cad90..c6a47013 100644
--- a/common/verity
+++ b/common/verity
@@ -3,6 +3,8 @@
#
# Functions for setting up and testing fs-verity
+. common/btrfs
+
_require_scratch_verity()
{
_require_scratch
@@ -145,6 +147,9 @@ _require_fsverity_dump_metadata()
_require_fsverity_corruption()
{
_require_xfs_io_command "fiemap"
+ if [ $FSTYP == "btrfs" ]; then
+ _require_btrfs_corrupt_block
+ fi
}
_scratch_mkfs_verity()
@@ -153,6 +158,9 @@ _scratch_mkfs_verity()
ext4|f2fs)
_scratch_mkfs -O verity
;;
+ btrfs)
+ _scratch_mkfs
+ ;;
*)
_notrun "No verity support for $FSTYP"
;;
@@ -314,6 +322,21 @@ _fsv_scratch_corrupt_merkle_tree()
(( offset += ($(_get_filesize $file) + 65535) & ~65535 ))
_fsv_scratch_corrupt_bytes $file $offset
;;
+ btrfs)
+ local ino=$(stat -c '%i' $file)
+ _scratch_unmount
+ local byte=""
+ while read -n 1 byte; do
+ local ascii=$(printf "%d" "'$byte'")
+ # This command will find a Merkle tree item for the inode (-I $ino,37,0)
+ # in the default filesystem tree (-r 5) and corrupt one byte (-b 1) at
+ # $offset (-o $offset) with the ascii representation of the byte we read
+ # (-v $ascii)
+ $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,37,0 -v $ascii -o $offset -b 1 $SCRATCH_DEV
+ (( offset += 1 ))
+ done
+ _scratch_mount
+ ;;
*)
_fail "_fsv_scratch_corrupt_merkle_tree() unimplemented on $FSTYP"
;;
--
2.31.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 3/5] btrfs: test btrfs specific fsverity corruption
2022-03-16 20:25 [PATCH v8 0/5] tests for btrfs fsverity Boris Burkov
2022-03-16 20:25 ` [PATCH v8 1/5] common/verity: require corruption functionality Boris Burkov
2022-03-16 20:25 ` [PATCH v8 2/5] common/verity: support btrfs in generic fsverity tests Boris Burkov
@ 2022-03-16 20:25 ` Boris Burkov
2022-04-10 14:53 ` Eryu Guan
2022-03-16 20:25 ` [PATCH v8 4/5] btrfs: test verity orphans with dmlogwrites Boris Burkov
` (2 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Boris Burkov @ 2022-03-16 20:25 UTC (permalink / raw)
To: fstests, linux-fscrypt, linux-btrfs, kernel-team
There are some btrfs specific fsverity scenarios that don't map
neatly onto the tests in generic/574 like holes, inline extents,
and preallocated extents. Cover those in a btrfs specific test.
This test relies on the btrfs implementation of fsverity in the patch:
btrfs: initial fsverity support
and on btrfs-corrupt-block for corruption in the patches titled:
btrfs-progs: corrupt generic item data with btrfs-corrupt-block
btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block
Signed-off-by: Boris Burkov <boris@bur.io>
---
tests/btrfs/290 | 168 ++++++++++++++++++++++++++++++++++++++++++++
tests/btrfs/290.out | 25 +++++++
2 files changed, 193 insertions(+)
create mode 100755 tests/btrfs/290
create mode 100644 tests/btrfs/290.out
diff --git a/tests/btrfs/290 b/tests/btrfs/290
new file mode 100755
index 00000000..f9acd55a
--- /dev/null
+++ b/tests/btrfs/290
@@ -0,0 +1,168 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 Facebook, Inc. All Rights Reserved.
+#
+# FS QA Test 290
+#
+# Test btrfs support for fsverity.
+# This test extends the generic fsverity testing by corrupting inline extents,
+# preallocated extents, holes, and the Merkle descriptor in a btrfs-aware way.
+#
+. ./common/preamble
+_begin_fstest auto quick verity
+
+# Import common functions.
+. ./common/filter
+. ./common/verity
+
+# real QA test starts here
+_supported_fs btrfs
+_require_scratch_verity
+_require_scratch_nocheck
+_require_odirect
+_require_xfs_io_command "falloc"
+_require_xfs_io_command "pread"
+_require_xfs_io_command "pwrite"
+_require_btrfs_corrupt_block
+
+get_ino() {
+ local file=$1
+ stat -c "%i" $file
+}
+
+validate() {
+ local f=$1
+ local sz=$(_get_filesize $f)
+ # buffered io
+ echo $(basename $f)
+ $XFS_IO_PROG -rc "pread -q 0 $sz" $f 2>&1 | _filter_scratch
+ # direct io
+ $XFS_IO_PROG -rdc "pread -q 0 $sz" $f 2>&1 | _filter_scratch
+}
+
+# corrupt the data portion of an inline extent
+corrupt_inline() {
+ local f=$SCRATCH_MNT/inl
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 42" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # inline data starts at disk_bytenr
+ # overwrite the first u64 with random bogus junk
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f disk_bytenr $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# preallocate a file, then corrupt it by changing it to a regular file
+corrupt_prealloc_to_reg() {
+ local f=$SCRATCH_MNT/prealloc
+ $XFS_IO_PROG -fc "falloc 0 12k" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # set extent type from prealloc (2) to reg (1)
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f type -v 1 $SCRATCH_DEV >/dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# corrupt a regular file by changing the type to preallocated
+corrupt_reg_to_prealloc() {
+ local f=$SCRATCH_MNT/reg
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # set type from reg (1) to prealloc (2)
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f type -v 2 $SCRATCH_DEV >/dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# corrupt a file by punching a hole
+corrupt_punch_hole() {
+ local f=$SCRATCH_MNT/punch
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ # make a new extent in the middle, sync so the writes don't coalesce
+ $XFS_IO_PROG -c sync $SCRATCH_MNT
+ $XFS_IO_PROG -fc "pwrite -q -S 0x59 4096 4096" $f
+ _fsv_enable $f
+ _scratch_unmount
+ # change disk_bytenr to 0, representing a hole
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 4096 -f disk_bytenr -v 0 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# plug hole
+corrupt_plug_hole() {
+ local f=$SCRATCH_MNT/plug
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ $XFS_IO_PROG -fc "falloc 4k 4k" $f
+ _fsv_enable $f
+ _scratch_unmount
+ # change disk_bytenr to some value, plugging the hole
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 4096 -f disk_bytenr -v 13639680 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# corrupt the fsverity descriptor item indiscriminately (causes EINVAL)
+corrupt_verity_descriptor() {
+ local f=$SCRATCH_MNT/desc
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # key for the descriptor item is <inode, BTRFS_VERITY_DESC_ITEM_KEY, 1>,
+ # 88 is X. So we write 5 Xs to the start of the descriptor
+ $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,36,1 -v 88 -o 0 -b 5 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# specifically target the root hash in the descriptor (causes EIO)
+corrupt_root_hash() {
+ local f=$SCRATCH_MNT/roothash
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,36,1 -v 88 -o 16 -b 1 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# corrupt the Merkle tree data itself
+corrupt_merkle_tree() {
+ local f=$SCRATCH_MNT/merkle
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # key for the descriptor item is <inode, BTRFS_VERITY_MERKLE_ITEM_KEY, 0>,
+ # 88 is X. So we write 5 Xs to somewhere in the middle of the first
+ # merkle item
+ $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,37,0 -v 88 -o 100 -b 5 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# real QA test starts here
+_scratch_mkfs >/dev/null
+_scratch_mount
+
+corrupt_inline
+corrupt_prealloc_to_reg
+corrupt_reg_to_prealloc
+corrupt_punch_hole
+corrupt_plug_hole
+corrupt_verity_descriptor
+corrupt_root_hash
+corrupt_merkle_tree
+
+status=0
+exit
diff --git a/tests/btrfs/290.out b/tests/btrfs/290.out
new file mode 100644
index 00000000..056b114b
--- /dev/null
+++ b/tests/btrfs/290.out
@@ -0,0 +1,25 @@
+QA output created by 290
+inl
+pread: Input/output error
+pread: Input/output error
+prealloc
+pread: Input/output error
+pread: Input/output error
+reg
+pread: Input/output error
+pread: Input/output error
+punch
+pread: Input/output error
+pread: Input/output error
+plug
+pread: Input/output error
+pread: Input/output error
+desc
+SCRATCH_MNT/desc: Invalid argument
+SCRATCH_MNT/desc: Invalid argument
+roothash
+pread: Input/output error
+pread: Input/output error
+merkle
+pread: Input/output error
+pread: Input/output error
--
2.31.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 4/5] btrfs: test verity orphans with dmlogwrites
2022-03-16 20:25 [PATCH v8 0/5] tests for btrfs fsverity Boris Burkov
` (2 preceding siblings ...)
2022-03-16 20:25 ` [PATCH v8 3/5] btrfs: test btrfs specific fsverity corruption Boris Burkov
@ 2022-03-16 20:25 ` Boris Burkov
2022-03-16 20:25 ` [PATCH v8 5/5] generic: test fs-verity EFBIG scenarios Boris Burkov
2022-03-17 18:19 ` [PATCH v8 0/5] tests for btrfs fsverity Eric Biggers
5 siblings, 0 replies; 15+ messages in thread
From: Boris Burkov @ 2022-03-16 20:25 UTC (permalink / raw)
To: fstests, linux-fscrypt, linux-btrfs, kernel-team
The behavior of orphans is most interesting across mounts, interrupted
at arbitrary points during fsverity enable. To cover as many such cases
as possible, use dmlogwrites and dmsnapshot as in
log-writes/replay-individual.sh. At each log entry, we want to assert a
somewhat complicated invariant:
If verity has not yet started: an orphan indicates that verity has
started.
If verity has started: mount should handle the orphan and blow away
verity data: expect 0 merkle items after mounting the snapshot dev. If
we can measure the file, verity has finished.
If verity has finished: the orphan should be gone, so mount should not
blow away merkle items. Expect the same number of merkle items before
and after mounting the snapshot dev.
Note that this relies on grepping btrfs inspect-internal dump-tree.
Until btrfs-progs has the ability to print the new Merkle items, they
will show up as UNKNOWN.36/37.
Signed-off-by: Boris Burkov <boris@bur.io>
---
tests/btrfs/291 | 161 ++++++++++++++++++++++++++++++++++++++++++++
tests/btrfs/291.out | 2 +
2 files changed, 163 insertions(+)
create mode 100755 tests/btrfs/291
create mode 100644 tests/btrfs/291.out
diff --git a/tests/btrfs/291 b/tests/btrfs/291
new file mode 100755
index 00000000..1bb3f1b3
--- /dev/null
+++ b/tests/btrfs/291
@@ -0,0 +1,161 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 Facebook, Inc. All Rights Reserved.
+#
+# FS QA Test 291
+#
+# Test btrfs consistency after each FUA while enabling verity on a file
+# This test works by following the pattern in log-writes/replay-individual.sh:
+# 1. run a workload (verity + sync) while logging to the log device
+# 2. replay an entry to the replay device
+# 3. snapshot the replay device to the snapshot device
+# 4. run destructive tests on the snapshot device (e.g. mount with orphans)
+# 5. goto 2
+#
+. ./common/preamble
+_begin_fstest auto verity
+
+# Override the default cleanup function.
+_cleanup()
+{
+ cd /
+ _log_writes_cleanup &> /dev/null
+ rm -f $img
+ $LVM_PROG vgremove -f -y $vgname >>$seqres.full 2>&1
+ losetup -d $loop_dev >>$seqres.full 2>&1
+}
+
+# Import common functions.
+. ./common/filter
+. ./common/attr
+. ./common/dmlogwrites
+. ./common/verity
+
+# real QA test starts here
+_supported_fs btrfs
+
+_require_scratch
+_require_test
+_require_log_writes
+_require_dm_target snapshot
+_require_command $LVM_PROG lvm
+_require_scratch_verity
+_require_btrfs_command inspect-internal dump-tree
+_require_test_program "log-writes/replay-log"
+
+sync_loop() {
+ i=$1
+ [ -z "$i" ] && _fail "sync loop needs a number of iterations"
+ while [ $i -gt 0 ]
+ do
+ $XFS_IO_PROG -c sync $SCRATCH_MNT
+ let i-=1
+ done
+}
+
+dump_tree() {
+ local dev=$1
+ $BTRFS_UTIL_PROG inspect-internal dump-tree $dev
+}
+
+count_item() {
+ local dev=$1
+ local item=$2
+ dump_tree $dev | grep -c $item
+}
+
+_log_writes_init $SCRATCH_DEV
+_log_writes_mkfs
+_log_writes_mount
+
+f=$SCRATCH_MNT/fsv
+MB=$((1024 * 1024))
+img=$TEST_DIR/$$.img
+$XFS_IO_PROG -fc "pwrite -q 0 $((10 * $MB))" $f
+$XFS_IO_PROG -c sync $SCRATCH_MNT
+sync_loop 10 &
+sync_proc=$!
+_fsv_enable $f
+$XFS_IO_PROG -c sync $SCRATCH_MNT
+wait $sync_proc
+
+_log_writes_unmount
+_log_writes_remove
+
+# the snapshot and the replay will each be the size of the log writes dev
+# so we create a loop device of size 2 * logwrites and then split it into
+# replay and snapshot with lvm.
+log_writes_blocks=$(blockdev --getsz $LOGWRITES_DEV)
+replay_bytes=$((512 * $log_writes_blocks))
+img_bytes=$((2 * $replay_bytes))
+
+$XFS_IO_PROG -fc "pwrite -q -S 0 $img_bytes $MB" $img >>$seqres.full 2>&1 || \
+ _fail "failed to create image for loop device"
+loop_dev=$(losetup -f --show $img)
+vgname=vg_replay
+lvname=lv_replay
+replay_dev=/dev/mapper/vg_replay-lv_replay
+snapname=lv_snap
+snap_dev=/dev/mapper/vg_replay-$snapname
+
+$LVM_PROG vgcreate -f $vgname $loop_dev >>$seqres.full 2>&1 || _fail "failed to vgcreate $vgname"
+$LVM_PROG lvcreate -L "$replay_bytes"B -n $lvname $vgname -y >>$seqres.full 2>&1 || \
+ _fail "failed to lvcreate $lvname"
+$UDEV_SETTLE_PROG >>$seqres.full 2>&1
+
+replay_log_prog=$here/src/log-writes/replay-log
+num_entries=$($replay_log_prog --log $LOGWRITES_DEV --num-entries)
+entry=$($replay_log_prog --log $LOGWRITES_DEV --replay $replay_dev --find --end-mark mkfs | cut -d@ -f1)
+$replay_log_prog --log $LOGWRITES_DEV --replay $replay_dev --limit $entry || \
+ _fail "failed to replay to start entry $entry"
+let entry+=1
+
+# state = 0: verity hasn't started
+# state = 1: verity underway
+# state = 2: verity done
+state=0
+while [ $entry -lt $num_entries ];
+do
+ $replay_log_prog --limit 1 --log $LOGWRITES_DEV --replay $replay_dev --start $entry || \
+ _fail "failed to take replay step at entry: $entry"
+
+ $LVM_PROG lvcreate -s -L 4M -n $snapname $vgname/$lvname >>$seqres.full 2>&1 || \
+ _fail "Failed to create snapshot"
+ $UDEV_SETTLE_PROG >>$seqres.full 2>&1
+
+ orphan=$(count_item $snap_dev ORPHAN)
+ if [ $state -eq 0 ]; then
+ [ $orphan -gt 0 ] && state=1
+ fi
+
+ pre_mount=$(count_item $snap_dev UNKNOWN.3[67])
+ _mount $snap_dev $SCRATCH_MNT || _fail "mount failed at entry $entry"
+ fsverity measure $SCRATCH_MNT/fsv >>$seqres.full 2>&1
+ measured=$?
+ umount $SCRATCH_MNT
+ [ $state -eq 1 ] && [ $measured -eq 0 ] && state=2
+ [ $state -eq 2 ] && ([ $measured -eq 0 ] || _fail "verity done, but measurement failed at entry $entry")
+ post_mount=$(count_item $snap_dev UNKNOWN.3[67])
+
+ echo "entry: $entry, state: $state, orphan: $orphan, pre_mount: $pre_mount, post_mount: $post_mount" >> $seqres.full
+
+ if [ $state -eq 1 ]; then
+ [ $post_mount -eq 0 ] || \
+ _fail "mount failed to clear under-construction merkle items pre: $pre_mount, post: $post_mount at entry $entry";
+ fi
+ if [ $state -eq 2 ]; then
+ [ $pre_mount -gt 0 ] || \
+ _fail "expected to have verity items before mount at entry $entry"
+ [ $pre_mount -eq $post_mount ] || \
+ _fail "mount cleared merkle items after verity was enabled $pre_mount vs $post_mount at entry $entry";
+ fi
+
+ let entry+=1
+ $LVM_PROG lvremove $vgname/$snapname -y >>$seqres.full
+done
+
+echo "Silence is golden"
+
+# success, all done
+status=0
+exit
diff --git a/tests/btrfs/291.out b/tests/btrfs/291.out
new file mode 100644
index 00000000..04605c70
--- /dev/null
+++ b/tests/btrfs/291.out
@@ -0,0 +1,2 @@
+QA output created by 291
+Silence is golden
--
2.31.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 5/5] generic: test fs-verity EFBIG scenarios
2022-03-16 20:25 [PATCH v8 0/5] tests for btrfs fsverity Boris Burkov
` (3 preceding siblings ...)
2022-03-16 20:25 ` [PATCH v8 4/5] btrfs: test verity orphans with dmlogwrites Boris Burkov
@ 2022-03-16 20:25 ` Boris Burkov
2022-03-17 18:17 ` Eric Biggers
2022-03-17 18:19 ` [PATCH v8 0/5] tests for btrfs fsverity Eric Biggers
5 siblings, 1 reply; 15+ messages in thread
From: Boris Burkov @ 2022-03-16 20:25 UTC (permalink / raw)
To: fstests, linux-fscrypt, linux-btrfs, kernel-team
btrfs, ext4, and f2fs cache the Merkle tree past EOF, which restricts
the maximum file size beneath the normal maximum. Test the logic in
those filesystems against files with sizes near the maximum.
To work properly, this does require some understanding of the practical
but not standardized layout of the Merkle tree. This is a bit unpleasant
and could make the test incorrect in the future, if the implementation
changes. On the other hand, it feels quite useful to test this tricky
edge case. It could perhaps be made more generic by adding some ioctls
to let the file system communicate the maximum file size for a verity
file or some information about the storage of the Merkle tree.
Signed-off-by: Boris Burkov <boris@bur.io>
---
common/verity | 11 ++++++++
tests/generic/690 | 64 +++++++++++++++++++++++++++++++++++++++++++
tests/generic/690.out | 7 +++++
3 files changed, 82 insertions(+)
create mode 100755 tests/generic/690
create mode 100644 tests/generic/690.out
diff --git a/common/verity b/common/verity
index c6a47013..8d08d3ea 100644
--- a/common/verity
+++ b/common/verity
@@ -342,3 +342,14 @@ _fsv_scratch_corrupt_merkle_tree()
;;
esac
}
+
+_require_fsverity_max_file_size_limit()
+{
+ case $FSTYP in
+ btrfs|ext4|f2fs)
+ ;;
+ *)
+ _notrun "$FSTYP does not store verity data past EOF; no special file size limit"
+ ;;
+ esac
+}
diff --git a/tests/generic/690 b/tests/generic/690
new file mode 100755
index 00000000..afdd95f2
--- /dev/null
+++ b/tests/generic/690
@@ -0,0 +1,64 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2021 Facebook, Inc. All Rights Reserved.
+#
+# FS QA Test 690
+#
+# fs-verity requires the filesystem to decide how it stores the Merkle tree,
+# which can be quite large.
+# It is convenient to treat the Merkle tree as past EOF, and ext4, f2fs, and
+# btrfs do so in at least some fashion. This leads to an edge case where a
+# large file can be under the file system file size limit, but trigger EFBIG
+# on enabling fs-verity. Test enabling verity on some large files to exercise
+# EFBIG logic for filesystems with fs-verity specific limits.
+#
+. ./common/preamble
+_begin_fstest auto quick verity
+
+
+# Import common functions.
+. ./common/filter
+. ./common/verity
+
+# real QA test starts here
+_supported_fs generic
+_require_test
+_require_math
+_require_scratch_verity
+_require_fsverity_max_file_size_limit
+
+_scratch_mkfs_verity &>> $seqres.full
+_scratch_mount
+
+fsv_file=$SCRATCH_MNT/file.fsv
+
+max_sz=$(_get_max_file_size)
+_fsv_scratch_begin_subtest "way too big: fail on first merkle block"
+truncate -s $max_sz $fsv_file
+_fsv_enable $fsv_file |& _filter_scratch
+
+# The goal of this second test is to make a big enough file that we trip the
+# EFBIG codepath, but not so big that we hit it immediately when writing the
+# first Merkle leaf.
+#
+# The Merkle tree is stored with the leaf node level (L0) last, but it is
+# written first. To get an interesting overflow, we need the maximum file size
+# (MAX) to be in the middle of L0 -- ideally near the beginning of L0 so that we
+# don't have to write many blocks before getting an error.
+#
+# With SHA-256 and 4K blocks, there are 128 hashes per block. Thus, ignoring
+# padding, L0 is 1/128 of the file size while the other levels in total are
+# 1/128**2 + 1/128**3 + 1/128**4 + ... = 1/16256 of the file size. So still
+# ignoring padding, for L0 start exactly at MAX, the file size must be s such
+# that s + s/16256 = MAX, i.e. s = MAX * (16256/16257). Then to get a file size
+# where MAX occurs *near* the start of L0 rather than *at* the start, we can
+# just subtract an overestimate of the padding: 64K after the file contents,
+# then 4K per level, where the consideration of 8 levels is sufficient.
+sz=$(echo "scale=20; $max_sz * (16256/16257) - 65536 - 4096*8" | $BC -q | cut -d. -f1)
+_fsv_scratch_begin_subtest "still too big: fail on first invalid merkle block"
+truncate -s $sz $fsv_file
+_fsv_enable $fsv_file |& _filter_scratch
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/690.out b/tests/generic/690.out
new file mode 100644
index 00000000..a3e2b9b9
--- /dev/null
+++ b/tests/generic/690.out
@@ -0,0 +1,7 @@
+QA output created by 690
+
+# way too big: fail on first merkle block
+ERROR: FS_IOC_ENABLE_VERITY failed on 'SCRATCH_MNT/file.fsv': File too large
+
+# still too big: fail on first invalid merkle block
+ERROR: FS_IOC_ENABLE_VERITY failed on 'SCRATCH_MNT/file.fsv': File too large
--
2.31.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v8 1/5] common/verity: require corruption functionality
2022-03-16 20:25 ` [PATCH v8 1/5] common/verity: require corruption functionality Boris Burkov
@ 2022-03-17 18:16 ` Eric Biggers
0 siblings, 0 replies; 15+ messages in thread
From: Eric Biggers @ 2022-03-17 18:16 UTC (permalink / raw)
To: Boris Burkov; +Cc: fstests, linux-fscrypt, linux-btrfs, kernel-team
On Wed, Mar 16, 2022 at 01:25:11PM -0700, Boris Burkov wrote:
> Corrupting ext4 and f2fs relies on xfs_io fiemap. Btrfs corruption
> testing will rely on a btrfs specific corruption utility. Add the
> ability to require corruption functionality to make this properly
> modular. To start, just check for fiemap, as that is needed
> universally for _fsv_scratch_corrupt_bytes.
>
> Signed-off-by: Boris Burkov <boris@bur.io>
> ---
> common/verity | 6 ++++++
> tests/generic/574 | 1 +
> tests/generic/576 | 1 +
> 3 files changed, 8 insertions(+)
Reviewed-by: Eric Biggers <ebiggers@google.com>
- Eric
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/5] common/verity: support btrfs in generic fsverity tests
2022-03-16 20:25 ` [PATCH v8 2/5] common/verity: support btrfs in generic fsverity tests Boris Burkov
@ 2022-03-17 18:16 ` Eric Biggers
2022-04-22 23:27 ` Boris Burkov
0 siblings, 1 reply; 15+ messages in thread
From: Eric Biggers @ 2022-03-17 18:16 UTC (permalink / raw)
To: Boris Burkov; +Cc: fstests, linux-fscrypt, linux-btrfs, kernel-team
On Wed, Mar 16, 2022 at 01:25:12PM -0700, Boris Burkov wrote:
> generic/572-579 have tests for fsverity. Now that btrfs supports
> fsverity, make these tests function as well. For a majority of the tests
> that pass, simply adding the case to mkfs a btrfs filesystem with no
> extra options is sufficient.
>
> However, generic/574 has tests for corrupting the merkle tree itself.
> Since btrfs uses a different scheme from ext4 and f2fs for storing this
> data, the existing logic for corrupting it doesn't work out of the box.
> Adapt it to properly corrupt btrfs merkle items.
>
> 576 does not run because btrfs does not support transparent encryption.
>
> This test relies on the btrfs implementation of fsverity in the patch:
> btrfs: initial fsverity support
>
> and on btrfs-corrupt-block for corruption in the patches titled:
> btrfs-progs: corrupt generic item data with btrfs-corrupt-block
> btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block
>
> Signed-off-by: Boris Burkov <boris@bur.io>
> ---
> common/btrfs | 5 +++++
> common/config | 1 +
> common/verity | 23 +++++++++++++++++++++++
> 3 files changed, 29 insertions(+)
Reviewed-by: Eric Biggers <ebiggers@google.com>
- Eric
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 5/5] generic: test fs-verity EFBIG scenarios
2022-03-16 20:25 ` [PATCH v8 5/5] generic: test fs-verity EFBIG scenarios Boris Burkov
@ 2022-03-17 18:17 ` Eric Biggers
0 siblings, 0 replies; 15+ messages in thread
From: Eric Biggers @ 2022-03-17 18:17 UTC (permalink / raw)
To: Boris Burkov; +Cc: fstests, linux-fscrypt, linux-btrfs, kernel-team
On Wed, Mar 16, 2022 at 01:25:15PM -0700, Boris Burkov wrote:
> btrfs, ext4, and f2fs cache the Merkle tree past EOF, which restricts
> the maximum file size beneath the normal maximum. Test the logic in
> those filesystems against files with sizes near the maximum.
>
> To work properly, this does require some understanding of the practical
> but not standardized layout of the Merkle tree. This is a bit unpleasant
> and could make the test incorrect in the future, if the implementation
> changes. On the other hand, it feels quite useful to test this tricky
> edge case. It could perhaps be made more generic by adding some ioctls
> to let the file system communicate the maximum file size for a verity
> file or some information about the storage of the Merkle tree.
>
> Signed-off-by: Boris Burkov <boris@bur.io>
> ---
> common/verity | 11 ++++++++
> tests/generic/690 | 64 +++++++++++++++++++++++++++++++++++++++++++
> tests/generic/690.out | 7 +++++
> 3 files changed, 82 insertions(+)
> create mode 100755 tests/generic/690
> create mode 100644 tests/generic/690.out
>
Reviewed-by: Eric Biggers <ebiggers@google.com>
- Eric
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 0/5] tests for btrfs fsverity
2022-03-16 20:25 [PATCH v8 0/5] tests for btrfs fsverity Boris Burkov
` (4 preceding siblings ...)
2022-03-16 20:25 ` [PATCH v8 5/5] generic: test fs-verity EFBIG scenarios Boris Burkov
@ 2022-03-17 18:19 ` Eric Biggers
5 siblings, 0 replies; 15+ messages in thread
From: Eric Biggers @ 2022-03-17 18:19 UTC (permalink / raw)
To: Boris Burkov; +Cc: fstests, linux-fscrypt, linux-btrfs, kernel-team
On Wed, Mar 16, 2022 at 01:25:10PM -0700, Boris Burkov wrote:
> This patchset provides tests for fsverity support in btrfs.
>
> It includes modifications for generic tests to pass with btrfs as well
> as new tests.
>
This looks good to me now. I don't have time to fully review the btrfs-specific
tests (patches 3 and 4), but their premise looks good.
- Eric
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 3/5] btrfs: test btrfs specific fsverity corruption
2022-03-16 20:25 ` [PATCH v8 3/5] btrfs: test btrfs specific fsverity corruption Boris Burkov
@ 2022-04-10 14:53 ` Eryu Guan
2022-04-11 14:10 ` David Sterba
2022-04-11 21:22 ` Boris Burkov
0 siblings, 2 replies; 15+ messages in thread
From: Eryu Guan @ 2022-04-10 14:53 UTC (permalink / raw)
To: Boris Burkov; +Cc: fstests, linux-fscrypt, linux-btrfs, kernel-team
On Wed, Mar 16, 2022 at 01:25:13PM -0700, Boris Burkov wrote:
> There are some btrfs specific fsverity scenarios that don't map
> neatly onto the tests in generic/574 like holes, inline extents,
> and preallocated extents. Cover those in a btrfs specific test.
>
> This test relies on the btrfs implementation of fsverity in the patch:
> btrfs: initial fsverity support
>
> and on btrfs-corrupt-block for corruption in the patches titled:
> btrfs-progs: corrupt generic item data with btrfs-corrupt-block
> btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block
>
> Signed-off-by: Boris Burkov <boris@bur.io>
> ---
> tests/btrfs/290 | 168 ++++++++++++++++++++++++++++++++++++++++++++
> tests/btrfs/290.out | 25 +++++++
> 2 files changed, 193 insertions(+)
> create mode 100755 tests/btrfs/290
> create mode 100644 tests/btrfs/290.out
>
> diff --git a/tests/btrfs/290 b/tests/btrfs/290
> new file mode 100755
> index 00000000..f9acd55a
> --- /dev/null
> +++ b/tests/btrfs/290
> @@ -0,0 +1,168 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 Facebook, Inc. All Rights Reserved.
I noticed that all patches have 2021 in copyright statement, should be
updated to 2022?
And I'd like btrfs folks to help review these 2 btrfs specific tests.
Thanks,
Eryu
> +#
> +# FS QA Test 290
> +#
> +# Test btrfs support for fsverity.
> +# This test extends the generic fsverity testing by corrupting inline extents,
> +# preallocated extents, holes, and the Merkle descriptor in a btrfs-aware way.
> +#
> +. ./common/preamble
> +_begin_fstest auto quick verity
> +
> +# Import common functions.
> +. ./common/filter
> +. ./common/verity
> +
> +# real QA test starts here
> +_supported_fs btrfs
> +_require_scratch_verity
> +_require_scratch_nocheck
> +_require_odirect
> +_require_xfs_io_command "falloc"
> +_require_xfs_io_command "pread"
> +_require_xfs_io_command "pwrite"
> +_require_btrfs_corrupt_block
> +
> +get_ino() {
> + local file=$1
> + stat -c "%i" $file
> +}
> +
> +validate() {
> + local f=$1
> + local sz=$(_get_filesize $f)
> + # buffered io
> + echo $(basename $f)
> + $XFS_IO_PROG -rc "pread -q 0 $sz" $f 2>&1 | _filter_scratch
> + # direct io
> + $XFS_IO_PROG -rdc "pread -q 0 $sz" $f 2>&1 | _filter_scratch
> +}
> +
> +# corrupt the data portion of an inline extent
> +corrupt_inline() {
> + local f=$SCRATCH_MNT/inl
> + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 42" $f
> + local ino=$(get_ino $f)
> + _fsv_enable $f
> + _scratch_unmount
> + # inline data starts at disk_bytenr
> + # overwrite the first u64 with random bogus junk
> + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f disk_bytenr $SCRATCH_DEV > /dev/null 2>&1
> + _scratch_mount
> + validate $f
> +}
> +
> +# preallocate a file, then corrupt it by changing it to a regular file
> +corrupt_prealloc_to_reg() {
> + local f=$SCRATCH_MNT/prealloc
> + $XFS_IO_PROG -fc "falloc 0 12k" $f
> + local ino=$(get_ino $f)
> + _fsv_enable $f
> + _scratch_unmount
> + # set extent type from prealloc (2) to reg (1)
> + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f type -v 1 $SCRATCH_DEV >/dev/null 2>&1
> + _scratch_mount
> + validate $f
> +}
> +
> +# corrupt a regular file by changing the type to preallocated
> +corrupt_reg_to_prealloc() {
> + local f=$SCRATCH_MNT/reg
> + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> + local ino=$(get_ino $f)
> + _fsv_enable $f
> + _scratch_unmount
> + # set type from reg (1) to prealloc (2)
> + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f type -v 2 $SCRATCH_DEV >/dev/null 2>&1
> + _scratch_mount
> + validate $f
> +}
> +
> +# corrupt a file by punching a hole
> +corrupt_punch_hole() {
> + local f=$SCRATCH_MNT/punch
> + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> + local ino=$(get_ino $f)
> + # make a new extent in the middle, sync so the writes don't coalesce
> + $XFS_IO_PROG -c sync $SCRATCH_MNT
> + $XFS_IO_PROG -fc "pwrite -q -S 0x59 4096 4096" $f
> + _fsv_enable $f
> + _scratch_unmount
> + # change disk_bytenr to 0, representing a hole
> + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 4096 -f disk_bytenr -v 0 $SCRATCH_DEV > /dev/null 2>&1
> + _scratch_mount
> + validate $f
> +}
> +
> +# plug hole
> +corrupt_plug_hole() {
> + local f=$SCRATCH_MNT/plug
> + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> + local ino=$(get_ino $f)
> + $XFS_IO_PROG -fc "falloc 4k 4k" $f
> + _fsv_enable $f
> + _scratch_unmount
> + # change disk_bytenr to some value, plugging the hole
> + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 4096 -f disk_bytenr -v 13639680 $SCRATCH_DEV > /dev/null 2>&1
> + _scratch_mount
> + validate $f
> +}
> +
> +# corrupt the fsverity descriptor item indiscriminately (causes EINVAL)
> +corrupt_verity_descriptor() {
> + local f=$SCRATCH_MNT/desc
> + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> + local ino=$(get_ino $f)
> + _fsv_enable $f
> + _scratch_unmount
> + # key for the descriptor item is <inode, BTRFS_VERITY_DESC_ITEM_KEY, 1>,
> + # 88 is X. So we write 5 Xs to the start of the descriptor
> + $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,36,1 -v 88 -o 0 -b 5 $SCRATCH_DEV > /dev/null 2>&1
> + _scratch_mount
> + validate $f
> +}
> +
> +# specifically target the root hash in the descriptor (causes EIO)
> +corrupt_root_hash() {
> + local f=$SCRATCH_MNT/roothash
> + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> + local ino=$(get_ino $f)
> + _fsv_enable $f
> + _scratch_unmount
> + $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,36,1 -v 88 -o 16 -b 1 $SCRATCH_DEV > /dev/null 2>&1
> + _scratch_mount
> + validate $f
> +}
> +
> +# corrupt the Merkle tree data itself
> +corrupt_merkle_tree() {
> + local f=$SCRATCH_MNT/merkle
> + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> + local ino=$(get_ino $f)
> + _fsv_enable $f
> + _scratch_unmount
> + # key for the descriptor item is <inode, BTRFS_VERITY_MERKLE_ITEM_KEY, 0>,
> + # 88 is X. So we write 5 Xs to somewhere in the middle of the first
> + # merkle item
> + $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,37,0 -v 88 -o 100 -b 5 $SCRATCH_DEV > /dev/null 2>&1
> + _scratch_mount
> + validate $f
> +}
> +
> +# real QA test starts here
> +_scratch_mkfs >/dev/null
> +_scratch_mount
> +
> +corrupt_inline
> +corrupt_prealloc_to_reg
> +corrupt_reg_to_prealloc
> +corrupt_punch_hole
> +corrupt_plug_hole
> +corrupt_verity_descriptor
> +corrupt_root_hash
> +corrupt_merkle_tree
> +
> +status=0
> +exit
> diff --git a/tests/btrfs/290.out b/tests/btrfs/290.out
> new file mode 100644
> index 00000000..056b114b
> --- /dev/null
> +++ b/tests/btrfs/290.out
> @@ -0,0 +1,25 @@
> +QA output created by 290
> +inl
> +pread: Input/output error
> +pread: Input/output error
> +prealloc
> +pread: Input/output error
> +pread: Input/output error
> +reg
> +pread: Input/output error
> +pread: Input/output error
> +punch
> +pread: Input/output error
> +pread: Input/output error
> +plug
> +pread: Input/output error
> +pread: Input/output error
> +desc
> +SCRATCH_MNT/desc: Invalid argument
> +SCRATCH_MNT/desc: Invalid argument
> +roothash
> +pread: Input/output error
> +pread: Input/output error
> +merkle
> +pread: Input/output error
> +pread: Input/output error
> --
> 2.31.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 3/5] btrfs: test btrfs specific fsverity corruption
2022-04-10 14:53 ` Eryu Guan
@ 2022-04-11 14:10 ` David Sterba
2022-04-11 21:22 ` Boris Burkov
1 sibling, 0 replies; 15+ messages in thread
From: David Sterba @ 2022-04-11 14:10 UTC (permalink / raw)
To: Eryu Guan; +Cc: Boris Burkov, fstests, linux-fscrypt, linux-btrfs, kernel-team
On Sun, Apr 10, 2022 at 10:53:04PM +0800, Eryu Guan wrote:
> On Wed, Mar 16, 2022 at 01:25:13PM -0700, Boris Burkov wrote:
> > There are some btrfs specific fsverity scenarios that don't map
> > neatly onto the tests in generic/574 like holes, inline extents,
> > and preallocated extents. Cover those in a btrfs specific test.
> >
> > This test relies on the btrfs implementation of fsverity in the patch:
> > btrfs: initial fsverity support
> >
> > and on btrfs-corrupt-block for corruption in the patches titled:
> > btrfs-progs: corrupt generic item data with btrfs-corrupt-block
> > btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block
> >
> > Signed-off-by: Boris Burkov <boris@bur.io>
> > ---
> > tests/btrfs/290 | 168 ++++++++++++++++++++++++++++++++++++++++++++
> > tests/btrfs/290.out | 25 +++++++
> > 2 files changed, 193 insertions(+)
> > create mode 100755 tests/btrfs/290
> > create mode 100644 tests/btrfs/290.out
> >
> > diff --git a/tests/btrfs/290 b/tests/btrfs/290
> > new file mode 100755
> > index 00000000..f9acd55a
> > --- /dev/null
> > +++ b/tests/btrfs/290
> > @@ -0,0 +1,168 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (C) 2021 Facebook, Inc. All Rights Reserved.
>
> I noticed that all patches have 2021 in copyright statement, should be
> updated to 2022?
>
> And I'd like btrfs folks to help review these 2 btrfs specific tests.
I did not do a deep review so no rev-by tag, but overall it looks sane
to me, also we'd rather like to have some fsverity tests in the suite
and fix them later eventually than nothing.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 3/5] btrfs: test btrfs specific fsverity corruption
2022-04-10 14:53 ` Eryu Guan
2022-04-11 14:10 ` David Sterba
@ 2022-04-11 21:22 ` Boris Burkov
1 sibling, 0 replies; 15+ messages in thread
From: Boris Burkov @ 2022-04-11 21:22 UTC (permalink / raw)
To: Eryu Guan; +Cc: fstests, linux-fscrypt, linux-btrfs, kernel-team
On Sun, Apr 10, 2022 at 10:53:04PM +0800, Eryu Guan wrote:
> On Wed, Mar 16, 2022 at 01:25:13PM -0700, Boris Burkov wrote:
> > There are some btrfs specific fsverity scenarios that don't map
> > neatly onto the tests in generic/574 like holes, inline extents,
> > and preallocated extents. Cover those in a btrfs specific test.
> >
> > This test relies on the btrfs implementation of fsverity in the patch:
> > btrfs: initial fsverity support
> >
> > and on btrfs-corrupt-block for corruption in the patches titled:
> > btrfs-progs: corrupt generic item data with btrfs-corrupt-block
> > btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block
> >
> > Signed-off-by: Boris Burkov <boris@bur.io>
> > ---
> > tests/btrfs/290 | 168 ++++++++++++++++++++++++++++++++++++++++++++
> > tests/btrfs/290.out | 25 +++++++
> > 2 files changed, 193 insertions(+)
> > create mode 100755 tests/btrfs/290
> > create mode 100644 tests/btrfs/290.out
> >
> > diff --git a/tests/btrfs/290 b/tests/btrfs/290
> > new file mode 100755
> > index 00000000..f9acd55a
> > --- /dev/null
> > +++ b/tests/btrfs/290
> > @@ -0,0 +1,168 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (C) 2021 Facebook, Inc. All Rights Reserved.
>
> I noticed that all patches have 2021 in copyright statement, should be
> updated to 2022?
Oops, good catch. I will resend with the right copyright statement along
with any changes from review on the btrfs tests.
Thanks for taking a look,
Boris
>
> And I'd like btrfs folks to help review these 2 btrfs specific tests.
>
> Thanks,
> Eryu
>
> > +#
> > +# FS QA Test 290
> > +#
> > +# Test btrfs support for fsverity.
> > +# This test extends the generic fsverity testing by corrupting inline extents,
> > +# preallocated extents, holes, and the Merkle descriptor in a btrfs-aware way.
> > +#
> > +. ./common/preamble
> > +_begin_fstest auto quick verity
> > +
> > +# Import common functions.
> > +. ./common/filter
> > +. ./common/verity
> > +
> > +# real QA test starts here
> > +_supported_fs btrfs
> > +_require_scratch_verity
> > +_require_scratch_nocheck
> > +_require_odirect
> > +_require_xfs_io_command "falloc"
> > +_require_xfs_io_command "pread"
> > +_require_xfs_io_command "pwrite"
> > +_require_btrfs_corrupt_block
> > +
> > +get_ino() {
> > + local file=$1
> > + stat -c "%i" $file
> > +}
> > +
> > +validate() {
> > + local f=$1
> > + local sz=$(_get_filesize $f)
> > + # buffered io
> > + echo $(basename $f)
> > + $XFS_IO_PROG -rc "pread -q 0 $sz" $f 2>&1 | _filter_scratch
> > + # direct io
> > + $XFS_IO_PROG -rdc "pread -q 0 $sz" $f 2>&1 | _filter_scratch
> > +}
> > +
> > +# corrupt the data portion of an inline extent
> > +corrupt_inline() {
> > + local f=$SCRATCH_MNT/inl
> > + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 42" $f
> > + local ino=$(get_ino $f)
> > + _fsv_enable $f
> > + _scratch_unmount
> > + # inline data starts at disk_bytenr
> > + # overwrite the first u64 with random bogus junk
> > + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f disk_bytenr $SCRATCH_DEV > /dev/null 2>&1
> > + _scratch_mount
> > + validate $f
> > +}
> > +
> > +# preallocate a file, then corrupt it by changing it to a regular file
> > +corrupt_prealloc_to_reg() {
> > + local f=$SCRATCH_MNT/prealloc
> > + $XFS_IO_PROG -fc "falloc 0 12k" $f
> > + local ino=$(get_ino $f)
> > + _fsv_enable $f
> > + _scratch_unmount
> > + # set extent type from prealloc (2) to reg (1)
> > + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f type -v 1 $SCRATCH_DEV >/dev/null 2>&1
> > + _scratch_mount
> > + validate $f
> > +}
> > +
> > +# corrupt a regular file by changing the type to preallocated
> > +corrupt_reg_to_prealloc() {
> > + local f=$SCRATCH_MNT/reg
> > + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> > + local ino=$(get_ino $f)
> > + _fsv_enable $f
> > + _scratch_unmount
> > + # set type from reg (1) to prealloc (2)
> > + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f type -v 2 $SCRATCH_DEV >/dev/null 2>&1
> > + _scratch_mount
> > + validate $f
> > +}
> > +
> > +# corrupt a file by punching a hole
> > +corrupt_punch_hole() {
> > + local f=$SCRATCH_MNT/punch
> > + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> > + local ino=$(get_ino $f)
> > + # make a new extent in the middle, sync so the writes don't coalesce
> > + $XFS_IO_PROG -c sync $SCRATCH_MNT
> > + $XFS_IO_PROG -fc "pwrite -q -S 0x59 4096 4096" $f
> > + _fsv_enable $f
> > + _scratch_unmount
> > + # change disk_bytenr to 0, representing a hole
> > + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 4096 -f disk_bytenr -v 0 $SCRATCH_DEV > /dev/null 2>&1
> > + _scratch_mount
> > + validate $f
> > +}
> > +
> > +# plug hole
> > +corrupt_plug_hole() {
> > + local f=$SCRATCH_MNT/plug
> > + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> > + local ino=$(get_ino $f)
> > + $XFS_IO_PROG -fc "falloc 4k 4k" $f
> > + _fsv_enable $f
> > + _scratch_unmount
> > + # change disk_bytenr to some value, plugging the hole
> > + $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 4096 -f disk_bytenr -v 13639680 $SCRATCH_DEV > /dev/null 2>&1
> > + _scratch_mount
> > + validate $f
> > +}
> > +
> > +# corrupt the fsverity descriptor item indiscriminately (causes EINVAL)
> > +corrupt_verity_descriptor() {
> > + local f=$SCRATCH_MNT/desc
> > + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> > + local ino=$(get_ino $f)
> > + _fsv_enable $f
> > + _scratch_unmount
> > + # key for the descriptor item is <inode, BTRFS_VERITY_DESC_ITEM_KEY, 1>,
> > + # 88 is X. So we write 5 Xs to the start of the descriptor
> > + $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,36,1 -v 88 -o 0 -b 5 $SCRATCH_DEV > /dev/null 2>&1
> > + _scratch_mount
> > + validate $f
> > +}
> > +
> > +# specifically target the root hash in the descriptor (causes EIO)
> > +corrupt_root_hash() {
> > + local f=$SCRATCH_MNT/roothash
> > + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> > + local ino=$(get_ino $f)
> > + _fsv_enable $f
> > + _scratch_unmount
> > + $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,36,1 -v 88 -o 16 -b 1 $SCRATCH_DEV > /dev/null 2>&1
> > + _scratch_mount
> > + validate $f
> > +}
> > +
> > +# corrupt the Merkle tree data itself
> > +corrupt_merkle_tree() {
> > + local f=$SCRATCH_MNT/merkle
> > + $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
> > + local ino=$(get_ino $f)
> > + _fsv_enable $f
> > + _scratch_unmount
> > + # key for the descriptor item is <inode, BTRFS_VERITY_MERKLE_ITEM_KEY, 0>,
> > + # 88 is X. So we write 5 Xs to somewhere in the middle of the first
> > + # merkle item
> > + $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,37,0 -v 88 -o 100 -b 5 $SCRATCH_DEV > /dev/null 2>&1
> > + _scratch_mount
> > + validate $f
> > +}
> > +
> > +# real QA test starts here
> > +_scratch_mkfs >/dev/null
> > +_scratch_mount
> > +
> > +corrupt_inline
> > +corrupt_prealloc_to_reg
> > +corrupt_reg_to_prealloc
> > +corrupt_punch_hole
> > +corrupt_plug_hole
> > +corrupt_verity_descriptor
> > +corrupt_root_hash
> > +corrupt_merkle_tree
> > +
> > +status=0
> > +exit
> > diff --git a/tests/btrfs/290.out b/tests/btrfs/290.out
> > new file mode 100644
> > index 00000000..056b114b
> > --- /dev/null
> > +++ b/tests/btrfs/290.out
> > @@ -0,0 +1,25 @@
> > +QA output created by 290
> > +inl
> > +pread: Input/output error
> > +pread: Input/output error
> > +prealloc
> > +pread: Input/output error
> > +pread: Input/output error
> > +reg
> > +pread: Input/output error
> > +pread: Input/output error
> > +punch
> > +pread: Input/output error
> > +pread: Input/output error
> > +plug
> > +pread: Input/output error
> > +pread: Input/output error
> > +desc
> > +SCRATCH_MNT/desc: Invalid argument
> > +SCRATCH_MNT/desc: Invalid argument
> > +roothash
> > +pread: Input/output error
> > +pread: Input/output error
> > +merkle
> > +pread: Input/output error
> > +pread: Input/output error
> > --
> > 2.31.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/5] common/verity: support btrfs in generic fsverity tests
2022-03-17 18:16 ` Eric Biggers
@ 2022-04-22 23:27 ` Boris Burkov
2022-04-23 0:59 ` Eric Biggers
0 siblings, 1 reply; 15+ messages in thread
From: Boris Burkov @ 2022-04-22 23:27 UTC (permalink / raw)
To: Eric Biggers; +Cc: fstests, linux-fscrypt, linux-btrfs, kernel-team
On Thu, Mar 17, 2022 at 06:16:45PM +0000, Eric Biggers wrote:
> On Wed, Mar 16, 2022 at 01:25:12PM -0700, Boris Burkov wrote:
> > generic/572-579 have tests for fsverity. Now that btrfs supports
> > fsverity, make these tests function as well. For a majority of the tests
> > that pass, simply adding the case to mkfs a btrfs filesystem with no
> > extra options is sufficient.
> >
> > However, generic/574 has tests for corrupting the merkle tree itself.
> > Since btrfs uses a different scheme from ext4 and f2fs for storing this
> > data, the existing logic for corrupting it doesn't work out of the box.
> > Adapt it to properly corrupt btrfs merkle items.
> >
> > 576 does not run because btrfs does not support transparent encryption.
> >
> > This test relies on the btrfs implementation of fsverity in the patch:
> > btrfs: initial fsverity support
> >
> > and on btrfs-corrupt-block for corruption in the patches titled:
> > btrfs-progs: corrupt generic item data with btrfs-corrupt-block
> > btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block
> >
> > Signed-off-by: Boris Burkov <boris@bur.io>
> > ---
> > common/btrfs | 5 +++++
> > common/config | 1 +
> > common/verity | 23 +++++++++++++++++++++++
> > 3 files changed, 29 insertions(+)
>
> Reviewed-by: Eric Biggers <ebiggers@google.com>
>
> - Eric
Eric,
Unfortunately, I think I found a more serious problem with the
compatibility of generic/574 and btrfs while working on testing the
enable/disable sysctls.
I realized that I had forgotten to customize the mount options for btrfs
to use "nodatasum" and as a result, this test was passing for btrfs
inappropriately, since we were getting EIOs for failing data checksums,
not verity checks.
I fixed the mount option issue only to realize that some of the test
cases make assumptions that don't apply to btrfs. For example:
"corruption_test 130999 131000 72"
Btrfs zeros pages past EOF in readpage before they make it to the user
via read or mmap, and the fsverity check is done at that point, so
corrupting the disk past EOF does not cause a verity failure (or get
leaked to the user) but it does cause csum failures since those are done
on bios, like verity checks in ext4. I verified that removing that
zeroing in readpage makes the test case pass.
Do you have a preference for how I might fix this? My first thought is
to try to factor out any such test cases into a new test with a new
requires clause that btrfs fails but ext4/f2fs pass, kind of like what
we did for the EFBIG test for future FSes that might not logically
address the Merkle tree in the past-EOF space.
Thanks,
Boris
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/5] common/verity: support btrfs in generic fsverity tests
2022-04-22 23:27 ` Boris Burkov
@ 2022-04-23 0:59 ` Eric Biggers
0 siblings, 0 replies; 15+ messages in thread
From: Eric Biggers @ 2022-04-23 0:59 UTC (permalink / raw)
To: Boris Burkov; +Cc: fstests, linux-fscrypt, linux-btrfs, kernel-team
On Fri, Apr 22, 2022 at 04:27:29PM -0700, Boris Burkov wrote:
> On Thu, Mar 17, 2022 at 06:16:45PM +0000, Eric Biggers wrote:
> > On Wed, Mar 16, 2022 at 01:25:12PM -0700, Boris Burkov wrote:
> > > generic/572-579 have tests for fsverity. Now that btrfs supports
> > > fsverity, make these tests function as well. For a majority of the tests
> > > that pass, simply adding the case to mkfs a btrfs filesystem with no
> > > extra options is sufficient.
> > >
> > > However, generic/574 has tests for corrupting the merkle tree itself.
> > > Since btrfs uses a different scheme from ext4 and f2fs for storing this
> > > data, the existing logic for corrupting it doesn't work out of the box.
> > > Adapt it to properly corrupt btrfs merkle items.
> > >
> > > 576 does not run because btrfs does not support transparent encryption.
> > >
> > > This test relies on the btrfs implementation of fsverity in the patch:
> > > btrfs: initial fsverity support
> > >
> > > and on btrfs-corrupt-block for corruption in the patches titled:
> > > btrfs-progs: corrupt generic item data with btrfs-corrupt-block
> > > btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block
> > >
> > > Signed-off-by: Boris Burkov <boris@bur.io>
> > > ---
> > > common/btrfs | 5 +++++
> > > common/config | 1 +
> > > common/verity | 23 +++++++++++++++++++++++
> > > 3 files changed, 29 insertions(+)
> >
> > Reviewed-by: Eric Biggers <ebiggers@google.com>
> >
> > - Eric
>
> Eric,
>
> Unfortunately, I think I found a more serious problem with the
> compatibility of generic/574 and btrfs while working on testing the
> enable/disable sysctls.
>
> I realized that I had forgotten to customize the mount options for btrfs
> to use "nodatasum" and as a result, this test was passing for btrfs
> inappropriately, since we were getting EIOs for failing data checksums,
> not verity checks.
>
> I fixed the mount option issue only to realize that some of the test
> cases make assumptions that don't apply to btrfs. For example:
> "corruption_test 130999 131000 72"
>
> Btrfs zeros pages past EOF in readpage before they make it to the user
> via read or mmap, and the fsverity check is done at that point, so
> corrupting the disk past EOF does not cause a verity failure (or get
> leaked to the user) but it does cause csum failures since those are done
> on bios, like verity checks in ext4. I verified that removing that
> zeroing in readpage makes the test case pass.
>
> Do you have a preference for how I might fix this? My first thought is
> to try to factor out any such test cases into a new test with a new
> requires clause that btrfs fails but ext4/f2fs pass, kind of like what
> we did for the EFBIG test for future FSes that might not logically
> address the Merkle tree in the past-EOF space.
The reason that an error is expected for corruption past EOF in the block
containing EOF, is to ensure that the bad data isn't visible via mmap reads. If
that's not a problem for btrfs due to it always zeroing the part past EOF, I
think it would be fine to change that test case (specifically the one with
parameters "corruption_test 130999 131000 72") to just try a mmap read of the
whole EOF block, and check that it either fails with an error *or* returns
zeroes. I don't think that an entirely new test script would be warranted.
- Eric
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2022-04-23 1:00 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-03-16 20:25 [PATCH v8 0/5] tests for btrfs fsverity Boris Burkov
2022-03-16 20:25 ` [PATCH v8 1/5] common/verity: require corruption functionality Boris Burkov
2022-03-17 18:16 ` Eric Biggers
2022-03-16 20:25 ` [PATCH v8 2/5] common/verity: support btrfs in generic fsverity tests Boris Burkov
2022-03-17 18:16 ` Eric Biggers
2022-04-22 23:27 ` Boris Burkov
2022-04-23 0:59 ` Eric Biggers
2022-03-16 20:25 ` [PATCH v8 3/5] btrfs: test btrfs specific fsverity corruption Boris Burkov
2022-04-10 14:53 ` Eryu Guan
2022-04-11 14:10 ` David Sterba
2022-04-11 21:22 ` Boris Burkov
2022-03-16 20:25 ` [PATCH v8 4/5] btrfs: test verity orphans with dmlogwrites Boris Burkov
2022-03-16 20:25 ` [PATCH v8 5/5] generic: test fs-verity EFBIG scenarios Boris Burkov
2022-03-17 18:17 ` Eric Biggers
2022-03-17 18:19 ` [PATCH v8 0/5] tests for btrfs fsverity Eric Biggers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).