common/fuzzy: try to clear blocking flags first in _scratch_fuzz_modify
[xfstests-dev.git] / tests / generic / 574
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright 2018 Google LLC
4 #
5 # FS QA Test generic/574
6 #
7 # Test corrupting verity files.  This test corrupts various parts of the
8 # contents of a verity file, or parts of its Merkle tree, by writing directly to
9 # the block device.  It verifies that this causes I/O errors when the relevant
10 # part of the contents is later read by any means.
11 #
12 seq=`basename $0`
13 seqres=$RESULT_DIR/$seq
14 echo "QA output created by $seq"
15
16 here=`pwd`
17 tmp=/tmp/$$
18 status=1        # failure is the default!
19 trap "_cleanup; exit \$status" 0 1 2 3 15
20
21 _cleanup()
22 {
23         cd /
24         _restore_fsverity_signatures
25         rm -f $tmp.*
26 }
27
28 # get standard environment, filters and checks
29 . ./common/rc
30 . ./common/filter
31 . ./common/verity
32
33 # remove previous $seqres.full before test
34 rm -f $seqres.full
35
36 # real QA test starts here
37 _supported_fs generic
38 _supported_os Linux
39 _require_scratch_verity
40 _disable_fsverity_signatures
41
42 _scratch_mkfs_verity &>> $seqres.full
43 _scratch_mount
44 fsv_orig_file=$SCRATCH_MNT/file
45 fsv_file=$SCRATCH_MNT/file.fsv
46
47 setup_zeroed_file()
48 {
49         local len=$1
50         local sparse=$2
51
52         if $sparse; then
53                 dd if=/dev/zero of=$fsv_orig_file bs=1 count=0 seek=$len \
54                         status=none
55         else
56                 head -c $len /dev/zero > $fsv_orig_file
57         fi
58         cp $fsv_orig_file $fsv_file
59         _fsv_enable $fsv_file
60         md5sum $fsv_file |& _filter_scratch
61 }
62
63 filter_sigbus()
64 {
65         sed -e 's/.*Bus error.*/Bus error/'
66 }
67
68 round_up_to_page_boundary()
69 {
70         local n=$1
71         local page_size=$(get_page_size)
72
73         echo $(( (n + page_size - 1) & ~(page_size - 1) ))
74 }
75
76 corruption_test()
77 {
78         local file_len=$1
79         local zap_offset=$2
80         local zap_len=$3
81         local is_merkle_tree=${4:-false} # if true, zap tree instead of data
82         local use_sparse_file=${5:-false}
83         local page_aligned_eof=$(round_up_to_page_boundary $file_len)
84         local measurement
85
86         if $is_merkle_tree; then
87                 local corrupt_func=_fsv_scratch_corrupt_merkle_tree
88         else
89                 local corrupt_func=_fsv_scratch_corrupt_bytes
90         fi
91
92         local msg="Corruption test:"
93         msg+=" file_len=$file_len"
94         if $use_sparse_file; then
95                 msg+=" (sparse)"
96         fi
97         msg+=" zap_offset=$zap_offset"
98         if $is_merkle_tree; then
99                 msg+=" (in Merkle tree)"
100         fi
101         msg+=" zap_len=$zap_len"
102
103         _fsv_scratch_begin_subtest "$msg"
104         setup_zeroed_file $file_len $use_sparse_file
105         cmp $fsv_file $fsv_orig_file
106         echo "Corrupting bytes..."
107         head -c $zap_len /dev/zero | tr '\0' X \
108                 | $corrupt_func $fsv_file $zap_offset
109
110         echo "Validating corruption (reading full file)..."
111         _scratch_cycle_mount
112         md5sum $fsv_file |& _filter_scratch
113
114         echo "Validating corruption (direct I/O)..."
115         _scratch_cycle_mount
116         dd if=$fsv_file bs=$FSV_BLOCK_SIZE iflag=direct status=none \
117                 of=/dev/null |& _filter_scratch
118
119         if ! $is_merkle_tree; then
120                 echo "Validating corruption (reading just corrupted part)..."
121                 dd if=$fsv_file bs=1 skip=$zap_offset count=$zap_len \
122                         of=/dev/null status=none |& _filter_scratch
123         fi
124
125         echo "Validating corruption (reading full file via mmap)..."
126         bash -c "trap '' SIGBUS; $XFS_IO_PROG -r $fsv_file \
127                 -c 'mmap -r 0 $page_aligned_eof' \
128                 -c 'mread 0 $file_len'" |& filter_sigbus
129
130         if ! $is_merkle_tree; then
131                 echo "Validating corruption (reading just corrupted part via mmap)..."
132                 bash -c "trap '' SIGBUS; $XFS_IO_PROG -r $fsv_file \
133                         -c 'mmap -r 0 $page_aligned_eof' \
134                         -c 'mread $zap_offset $zap_len'" |& filter_sigbus
135         fi
136 }
137
138 corruption_test 131072 0 1
139 corruption_test 131072 4095 1
140 corruption_test 131072 65536 65536
141 corruption_test 131072 131071 1
142
143 # Non-zeroed bytes in the final partial block beyond EOF should cause reads to
144 # fail too.  Such bytes would be visible via mmap().
145 corruption_test 130999 131000 72
146
147 # Merkle tree corruption.
148 corruption_test 200000 100 10 true
149
150 # Sparse file.  Corrupting the Merkle tree should still cause reads to fail,
151 # i.e. the filesystem must verify holes.
152 corruption_test 200000 100 10 true true
153
154 # success, all done
155 status=0
156 exit