#! /bin/bash # SPDX-License-Identifier: GPL-2.0-only # Copyright 2021 Google LLC # # FS QA Test No. 624 # # Test retrieving the Merkle tree and fs-verity descriptor of a verity file # using FS_IOC_READ_VERITY_METADATA. # . ./common/preamble _begin_fstest auto quick verity # Override the default cleanup function. _cleanup() { cd / _restore_fsverity_signatures rm -f $tmp.* } . ./common/filter . ./common/verity _supported_fs generic _require_scratch_verity _disable_fsverity_signatures fsv_orig_file=$SCRATCH_MNT/file fsv_file=$SCRATCH_MNT/file.fsv _scratch_mkfs_verity &>> $seqres.full _scratch_mount _fsv_create_enable_file $fsv_file _require_fsverity_dump_metadata $fsv_file # Test FS_IOC_READ_VERITY_METADATA on a file that uses the given Merkle tree # block size. test_block_size() { local block_size=$1 local digest_size=32 # assuming SHA-256 local i # Create the file. Make the file size big enough to result in multiple # Merkle tree levels being needed. The following expression computes a # file size that needs 2 blocks at level 0, and thus 1 block at level 1. local file_size=$((block_size * (2 * (block_size / digest_size)))) head -c $file_size /dev/zero > $fsv_orig_file local tree_params=("--salt=abcd" "--block-size=$block_size") cp $fsv_orig_file $fsv_file _fsv_enable $fsv_file "${tree_params[@]}" # Use the 'fsverity digest' command to compute the expected Merkle tree, # descriptor, and file digest. # # Ideally we'd just hard-code expected values into the .out file and # echo the actual values. That doesn't quite work here, since all these # values depend on the Merkle tree block size, and the Merkle tree block # sizes that are supported (and thus get tested here) vary. Therefore, # we calculate the expected values in userspace with the help of # 'fsverity digest', then do explicit comparisons with them. This works # fine as long as fsverity-utils and the kernel don't get broken in the # same way, in which case generic/575 should detect the problem anyway. local expected_file_digest=$(_fsv_digest $fsv_orig_file \ "${tree_params[@]}" \ --out-merkle-tree=$tmp.merkle_tree.expected \ --out-descriptor=$tmp.descriptor.expected) local merkle_tree_size=$(_get_filesize $tmp.merkle_tree.expected) local descriptor_size=$(_get_filesize $tmp.descriptor.expected) # 'fsverity measure' should return the expected file digest. local actual_file_digest=$(_fsv_measure $fsv_file) if [ "$actual_file_digest" != "$expected_file_digest" ]; then echo "Measure returned $actual_file_digest but expected $expected_file_digest" fi # Test dumping the Merkle tree. _fsv_dump_merkle_tree $fsv_file > $tmp.merkle_tree.actual if ! cmp $tmp.merkle_tree.expected $tmp.merkle_tree.actual; then echo "Dumped Merkle tree didn't match" fi # Test dumping the Merkle tree in chunks. for (( i = 0; i < merkle_tree_size; i += 997 )); do _fsv_dump_merkle_tree $fsv_file --offset=$i --length=997 done > $tmp.merkle_tree.actual if ! cmp $tmp.merkle_tree.expected $tmp.merkle_tree.actual; then echo "Dumped Merkle tree (in chunks) didn't match" fi # Test dumping the descriptor. _fsv_dump_descriptor $fsv_file > $tmp.descriptor.actual if ! cmp $tmp.descriptor.expected $tmp.descriptor.actual; then echo "Dumped descriptor didn't match" fi # Test dumping the descriptor in chunks. for (( i = 0; i < descriptor_size; i += 13 )); do _fsv_dump_descriptor $fsv_file --offset=$i --length=13 done > $tmp.descriptor.actual if ! cmp $tmp.descriptor.expected $tmp.descriptor.actual; then echo "Dumped descriptor (in chunks) didn't match" fi } # Always test FSV_BLOCK_SIZE. Also test some other block sizes if they happen # to be supported. _fsv_scratch_begin_subtest "Testing block_size=FSV_BLOCK_SIZE" test_block_size $FSV_BLOCK_SIZE for block_size in 1024 4096 16384 65536; do _fsv_scratch_begin_subtest "Testing block_size=$block_size if supported" if (( block_size == FSV_BLOCK_SIZE )); then continue # Skip redundant test case. fi if ! _fsv_can_enable $fsv_file --block-size=$block_size; then echo "block_size=$block_size is unsupported" >> $seqres.full continue fi test_block_size $block_size done # success, all done status=0 exit