summaryrefslogtreecommitdiffstats
path: root/tests/verity-compat-test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 00:31:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 00:31:19 +0000
commit6e33fee6f4a7e2041dd276995b402ca036fcab14 (patch)
tree85be5c41f2715d7d4d24cfa220197f1e2c778259 /tests/verity-compat-test
parentInitial commit. (diff)
downloadcryptsetup-6e33fee6f4a7e2041dd276995b402ca036fcab14.tar.xz
cryptsetup-6e33fee6f4a7e2041dd276995b402ca036fcab14.zip
Adding upstream version 2:2.1.0.upstream/2%2.1.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/verity-compat-test')
-rwxr-xr-xtests/verity-compat-test439
1 files changed, 439 insertions, 0 deletions
diff --git a/tests/verity-compat-test b/tests/verity-compat-test
new file mode 100755
index 0000000..33e5d57
--- /dev/null
+++ b/tests/verity-compat-test
@@ -0,0 +1,439 @@
+#!/bin/bash
+
+VERITYSETUP=../veritysetup
+VERITYSETUP_VALGRIND=../.libs/veritysetup
+VERITYSETUP_LIB_VALGRIND=../.libs
+
+DEV_NAME=verity3273
+DEV_OUT="$DEV_NAME.out"
+IMG=verity-data
+IMG_HASH=verity-hash
+IMG_TMP=tst-dev
+FEC_DEV=tst_fec123
+
+function remove_mapping()
+{
+ [ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME >/dev/null 2>&1
+ [ ! -z "$LOOPDEV1" ] && losetup -d $LOOPDEV1 >/dev/null 2>&1
+ rm -f $IMG $IMG_HASH $DEV_OUT $FEC_DEV $IMG_TMP >/dev/null 2>&1
+ LOOPDEV1=""
+ LOOPDEV2=""
+}
+
+function fail()
+{
+ [ -n "$1" ] && echo "$1"
+ echo "FAILED at line $(caller)"
+ [ -f $DEV_OUT ] && cat $DEV_OUT
+ remove_mapping
+ exit 2
+}
+
+function skip()
+{
+ [ -n "$1" ] && echo "$1"
+ exit 77
+}
+
+function prepare() # $1 dev1_siz [$2 dev2_size]
+{
+ remove_mapping
+
+ dd if=/dev/zero of=$IMG bs=1k count=$1 >/dev/null 2>&1
+ LOOPDEV1=$(losetup -f 2>/dev/null)
+ [ -z "$LOOPDEV1" ] && fail "No free loop device"
+ losetup $LOOPDEV1 $IMG
+
+ [ -z "$2" ] && return
+ LOOPDEV2=$IMG_HASH
+}
+
+function wipe()
+{
+ dd if=/dev/zero of=$LOOPDEV1 bs=256k >/dev/null 2>&1
+ rm -f $IMG_HASH $DEV_OUT >/dev/null 2>&1
+}
+
+function check_exists()
+{
+ [ -b /dev/mapper/$DEV_NAME ] || fail
+}
+
+function check_version() # MAJ MIN
+{
+ VER_STR=$(dmsetup targets | grep verity | cut -f 3 -dv)
+ [ -z "$VER_STR" ] && fail "Failed to parse dm-verity version."
+
+ VER_MAJ=$(echo $VER_STR | cut -f 1 -d.)
+ VER_MIN=$(echo $VER_STR | cut -f 2 -d.)
+
+ test $VER_MAJ -gt $1 && return 0
+ test $VER_MIN -ge $2 && return 0
+ return 1
+}
+
+function compare_out() # $1 what, $2 expected
+{
+ OPT=$(grep -v "^#" $DEV_OUT | grep -i "$1" | sed -e s/.*\:\ // )
+ [ -z "$OPT" ] && fail
+ [ $OPT != $2 ] && fail "$1 differs ($2)"
+}
+
+function check_root_hash() # $1 size, $2 hash, $3 salt, $4 version, $5 hash, [$6 offset]
+{
+ if [ -z "$LOOPDEV2" ] ; then
+ BLOCKS=$(($6 / $1))
+ DEV_PARAMS="$LOOPDEV1 $LOOPDEV1 \
+ --hash-offset $6 \
+ --data-blocks=$BLOCKS --debug"
+ else
+ DEV_PARAMS="$LOOPDEV1 $LOOPDEV2"
+ fi
+
+ for sb in yes no; do
+ FORMAT_PARAMS="--format=$4 --data-block-size=$1 --hash-block-size=$1 --hash=$5 --salt=$3"
+ if [ $sb == yes ] ; then
+ VERIFY_PARAMS=""
+ else
+ FORMAT_PARAMS="$FORMAT_PARAMS --no-superblock"
+ VERIFY_PARAMS=$FORMAT_PARAMS
+ fi
+
+ for fail in data hash; do
+ wipe
+ echo -n "V$4(sb=$sb) $5 block size $1: "
+ $VERITYSETUP format $DEV_PARAMS $FORMAT_PARAMS >$DEV_OUT || fail
+
+ echo -n "[root hash]"
+ compare_out "root hash" $2
+ compare_out "salt" "$3"
+
+ $VERITYSETUP verify $DEV_PARAMS $VERIFY_PARAMS $2 >>$DEV_OUT 2>&1 || fail
+ echo -n "[verify]"
+
+ $VERITYSETUP create $DEV_NAME $DEV_PARAMS $VERIFY_PARAMS $2 >>$DEV_OUT 2>&1 || fail
+ check_exists
+ echo -n "[activate]"
+
+ dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=$1 2>/dev/null
+ dmsetup status $DEV_NAME | grep "verity V" >/dev/null || fail
+ echo -n "[in-kernel verify]"
+
+ $VERITYSETUP close $DEV_NAME >/dev/null 2>&1 || fail
+
+ case $fail in
+ data)
+ dd if=/dev/urandom of=$LOOPDEV1 bs=1 seek=3456 count=8 conv=notrunc 2>/dev/null
+ TXT="data_dev"
+ ;;
+ hash)
+ if [ -z "$LOOPDEV2" ] ; then
+ dd if=/dev/urandom of=$LOOPDEV1 bs=1 seek=$((8193 + $4)) count=8 conv=notrunc 2>/dev/null
+ else
+ dd if=/dev/urandom of=$LOOPDEV2 bs=1 seek=8193 count=8 conv=notrunc 2>/dev/null
+ fi
+ TXT="hash_dev"
+ ;;
+ esac
+
+ $VERITYSETUP verify $DEV_PARAMS $VERIFY_PARAMS $2 >>$DEV_OUT 2>&1 && \
+ fail "userspace check for $TXT corruption"
+ $VERITYSETUP create $DEV_NAME $DEV_PARAMS $VERIFY_PARAMS $2 >>$DEV_OUT 2>&1 || \
+ fail "activation"
+ dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=$1 2>/dev/null
+ dmsetup status $DEV_NAME | grep "verity V" >/dev/null && \
+ fail "in-kernel check for $TXT corruption"
+ $VERITYSETUP close $DEV_NAME >/dev/null 2>&1 || fail "deactivation"
+ echo "[$TXT corruption]"
+ done
+ done
+}
+
+function corrupt_device() # $1 device, $2 device_size(in bytes), $3 #{corrupted_bytes}
+{
+ # Repeatable magic corruption :-)
+ CORRUPT=$3
+ RANDOM=43
+ while [ "$CORRUPT" -gt 0 ]; do
+ SEEK=$RANDOM
+ while [ $SEEK -ge $2 ] ; do SEEK=$RANDOM; done
+ echo -n -e "\x55" | dd of=$1 bs=1 count=1 seek=$SEEK conv=notrunc > /dev/null 2>&1
+ CORRUPT=$(($CORRUPT - 1))
+ done
+}
+
+# $1 data_device, $2 hash_device, $3 fec_device, $4 data/hash_block_size(in bytes),
+# $5 data_size(in blocks), $6 device_size(in blocks), $7 hash_offset(in bytes),
+# $8 fec_offset(in bytes), $9 fec_roots, ${10} corrupted_bytes, [${11} superblock(y/n), ${12} salt]
+function check_fec()
+{
+ INDEX=25
+ dd if=/dev/zero of=$1 bs=$4 count=$6 > /dev/null 2>&1
+
+ echo -n "Block_size: $4, Data_size: $(($4 * $5))B, FEC_roots: $9, Corrupted_bytes: ${10} "
+
+ PARAMS=" --data-block-size=$4 --hash-block-size=$4 "
+ if [ "$5" -ne "$6" ]; then
+ PARAMS="$PARAMS --data-blocks=$5"
+ fi
+
+ if [ "$7" -ne 0 ]; then
+ PARAMS="$PARAMS --hash-offset=$7"
+ fi
+
+ if [ "$8" -ne 0 ]; then
+ PARAMS="$PARAMS --fec-offset=$8"
+ fi
+
+ if [ "${11}" == "n" ]; then
+ INDEX=24
+ echo -n "[no-superblock]"
+ PARAMS="$PARAMS --no-superblock -s=${12}"
+ elif [ -n "${12}" ]; then
+ PARAMS="$PARAMS -s=${12}"
+ fi
+
+ if [[ "$1" == "$2" && "$1" == "$3" ]]; then
+ echo -n "[one_device_test]"
+ dd if=/dev/zero of=$IMG_TMP bs=$4 count=$5 > /dev/null 2>&1
+ ARR=(`sha256sum $IMG_TMP`)
+ HASH_ORIG=${ARR[0]}
+ else
+ ARR=(`sha256sum $1`)
+ HASH_ORIG=${ARR[0]}
+ fi
+
+ ARR=(`$VERITYSETUP format $1 $2 --fec-device=$3 $PARAMS`)
+ SALT=${ARR[$INDEX]}
+ ROOT_HASH=${ARR[$(($INDEX+3))]}
+
+ corrupt_device $1 $(($5 * $4)) ${10}
+
+ $VERITYSETUP create $DEV_NAME $1 $2 $ROOT_HASH --fec-device=$3 $PARAMS > /dev/null 2>&1
+ if [ "$?" -ne "0" ] ; then
+ echo "[N/A, test skipped]"
+ return 3
+ fi
+
+ udevadm settle
+
+ dd if=/dev/mapper/$DEV_NAME of=$IMG_TMP > /dev/null 2>&1
+ ARR=(`sha256sum $IMG_TMP`)
+
+ HASH_REPAIRED=${ARR[0]}
+
+ $VERITYSETUP close $DEV_NAME
+ rm $1 $2 $3 $IMG_TMP > /dev/null 2>&1
+
+ if [ "$HASH_ORIG" != "$HASH_REPAIRED" ]; then
+ echo -n "[correction failed]"
+ return 1
+ fi
+
+ echo "[file was repaired][OK]"
+}
+
+function check_option() # $1 size, $2 hash, $3 salt, $4 version, $5 hash, $6 CLI option, $7 status option
+{
+ DEV_PARAMS="$LOOPDEV1 $LOOPDEV2"
+ FORMAT_PARAMS="--format=$4 --data-block-size=$1 --hash-block-size=$1 --hash=$5 --salt=$3"
+
+ echo -n "Option $6 "
+ $VERITYSETUP format $DEV_PARAMS $FORMAT_PARAMS >/dev/null 2>&1 || fail
+ $VERITYSETUP create $DEV_NAME $DEV_PARAMS $2 $6 >/dev/null 2>&1 || fail
+ check_exists
+ $VERITYSETUP status $DEV_NAME 2>/dev/null | grep flags | grep -q $7 || fail
+ dmsetup table $DEV_NAME 2>/dev/null | grep -q $7 || fail
+ $VERITYSETUP close $DEV_NAME >/dev/null 2>&1 || fail
+ echo "[OK]"
+}
+
+function valgrind_setup()
+{
+ which valgrind >/dev/null 2>&1 || fail "Cannot find valgrind."
+ [ ! -f $VERITYSETUP_VALGRIND ] && fail "Unable to get location of veritysetup executable."
+ export LD_LIBRARY_PATH="$VERITYSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
+}
+
+function valgrind_run()
+{
+ INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${VERITYSETUP_VALGRIND} "$@"
+}
+
+function checkOffsetBug() # $1 size, $2 hash-offset, $3 data-blocks
+{
+ echo -n "Size :: $1 B | Hash-offset :: $2 blocks | Data-blocks :: $3 "
+ dd if=/dev/zero of=$IMG bs=1 count=0 seek=$1 >/dev/null 2>&1
+ $VERITYSETUP --data-blocks=$3 --hash-offset=$2 format $IMG $IMG >/dev/null 2>&1 || fail "Test [hash-offset greater than 2G] failed"
+ echo "[OK]"
+ remove_mapping
+}
+
+function checkOverlapBug() # $1 size, $2 hash-offset, $3 data-blocks, $4 block_size, $5 fec_offset
+{
+ echo -n "Device-size :: $1 B | "
+ [ $# -ge 3 ] && echo -n "Data-blocks :: $3 blocks| "
+ [ $# -lt 3 ] && echo -n "Data-blocks :: whole device | "
+ [ $# -ge 4 ] && echo -n "Block-size :: $4 B | "
+ [ $# -lt 4 ] && echo -n "Block-size :: 4096 B | "
+ echo -n "Hash-offset :: $2 B | "
+
+ dd if=/dev/zero of=$IMG bs=1 count=0 seek=$1 >/dev/null 2>&1
+ if [ -z $3 ] ; then
+ # veritysetup must fail
+ $VERITYSETUP --hash-offset=$2 format $IMG $IMG >/dev/null 2>&1 && fail "Test [overlap with option \"--data-blocks\" not entered] failed"
+ else
+ $VERITYSETUP --data-block-size=$4 --hash-block-size=$4 --data-blocks=$3 --hash-offset=$2 format $IMG $IMG >/dev/null 2>&1
+ RET=$?
+ [ "$3" -gt "$(($2 / $4))" ] && [ "$RET" -eq "0" ] && fail "Test [overlap - hash-offset in data area] failed"
+ fi
+
+ if [ $# -eq 5 ] ; then
+ echo -n "FEC-offset :: $5 B | "
+ PARAMS="--data-block-size=$4 --hash-block-size=$4 --data-blocks=$3 --fec-device=$IMG --fec-offset=$5"
+
+ # test data-fec area overlap
+ $VERITYSETUP format $IMG $IMG_HASH $PARAMS >/dev/null 2>&1
+ RET=$?
+ [ "$(($3*$4))" -gt "$5" ] && [ "$RET" -eq "0" ] && fail "Test [data/fec area overlap] failed"
+
+ HASH_SIZE=$(stat --printf="%s" $IMG_HASH)
+
+ # test hash-fec area overlap
+ $VERITYSETUP format $IMG $IMG $PARAMS --hash-offset=$2 >/dev/null 2>&1
+ RET=$?
+ [ "$(($2 + $HASH_SIZE))" -gt "$5" ] && [ "$RET" -eq "0" ] && fail "Test [hash/fec area overlap] failed"
+ fi
+
+ echo "[OK]"
+ remove_mapping
+}
+
+# $1 size, $2 block size, $3 roots, $4 hash offset, $5 fec offset,
+# $6 one dev(1 - one device, 2 - one device for data and hash, one device for fec data, 3 - three separate devices),
+# $7 #{corrupted bytes}
+function checkUserSpaceRepair()
+{
+ BS=512
+ COUNT=50000
+ dd if=/dev/zero of=$IMG bs=$BS count=$COUNT >/dev/null 2>&1
+ PARAMS="--data-block-size=$2 --hash-block-size=$2 --fec-roots=$3"
+ [ "$1" -gt 0 ] && PARAMS="$PARAMS --data-blocks=$1" && BS=$2 && COUNT=$1
+
+ # different parameters for different number of devices
+ [ "$6" -eq 1 ] && HASH_DEV=$IMG && FEC=$IMG && PARAMS="$PARAMS --hash-offset=$4 --fec-offset=$5" && echo -n "[One device]"
+ [ "$6" -eq 2 ] && HASH_DEV=$IMG && FEC=$FEC_DEV && PARAMS="$PARAMS --hash-offset=$4" && echo -n "[Two separate data/hash and fec devices]"
+ [ "$6" -eq 3 ] && HASH_DEV=$IMG_HASH && FEC=$FEC_DEV && echo -n "[Three separate devices]"
+
+ echo -n "[nroots::$3]"
+
+ ARR=(`$VERITYSETUP format $IMG $HASH_DEV --fec-device $FEC $PARAMS`)
+ ROOT_HASH=${ARR[28]}
+
+ echo -n "[Errors can be corrected]"
+ corrupt_device $IMG $(($BS*$COUNT)) $7
+ $VERITYSETUP verify $IMG $HASH_DEV $ROOT_HASH --fec-device=$FEC $PARAMS >/dev/null 2>&1
+ RET=$?
+ [ "$RET" -ne 0 ] && fail "Device can be corrected, but it wasn't."
+ echo -n "[OK]"
+
+ echo -n "[Errors cannot be corrected]"
+ dd if=/dev/urandom of=$IMG bs=$BS count=$COUNT conv=notrunc >/dev/null 2>&1
+ $VERITYSETUP verify $IMG $HASH_DEV $ROOT_HASH --fec-device=$FEC $PARAMS >/dev/null 2>&1
+ RET=$?
+ [ "$RET" -eq 0 ] && fail "Device cannot be correct, but it didn't fail."
+ echo "[OK]"
+}
+
+[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
+[ ! -x "$VERITYSETUP" ] && skip "Cannot find $VERITYSETUP, test skipped."
+
+[ -n "$VALG" ] && valgrind_setup && VERITYSETUP=valgrind_run
+modprobe dm-verity >/dev/null 2>&1
+dmsetup targets | grep verity >/dev/null 2>&1 || skip "Cannot find dm-verity target, test skipped."
+
+# VERITYSETUP tests
+
+SALT=e48da609055204e89ae53b655ca2216dd983cf3cb829f34f63a297d106d53e2d
+
+echo "Verity tests [separate devices]"
+prepare 8192 1024
+check_root_hash 512 9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174 $SALT 1 sha256
+check_root_hash 1024 54d92778750495d1f80832b486ebd007617d746271511bbf0e295e143da2b3df $SALT 1 sha256
+check_root_hash 4096 e522df0f97da4febb882ac40f30b37dc0b444bf6df418929463fa25280f09d5c $SALT 1 sha256
+# version 0
+check_root_hash 4096 cbbf4ebd004ef65e29b935bb635a39cf754d677f3fa10b0126da725bbdf10f7d $SALT 0 sha256
+# no salt
+check_root_hash 4096 ef29c902d87350f1da4bfa536e16cebc162a909bf89abe448b81ec500d4fb9bf - 1 sha256
+# sha1
+check_root_hash 1024 d0e9163ca8844aaa2e88fe5265a8c5d9ee494a99 $SALT 1 sha1
+check_root_hash 1024 73509e8e868be6b8ac939817a98a3d35121413b2 dadada 1 sha1
+
+echo "Verity tests [one device offset]"
+prepare $((8192 + 1024))
+check_root_hash 512 9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174 $SALT 1 sha256 8388608
+check_root_hash 1024 54d92778750495d1f80832b486ebd007617d746271511bbf0e295e143da2b3df $SALT 1 sha256 8388608
+check_root_hash 4096 e522df0f97da4febb882ac40f30b37dc0b444bf6df418929463fa25280f09d5c $SALT 1 sha256 8388608
+# version 0
+check_root_hash 4096 cbbf4ebd004ef65e29b935bb635a39cf754d677f3fa10b0126da725bbdf10f7d $SALT 0 sha256 8388608
+# no salt
+check_root_hash 4096 ef29c902d87350f1da4bfa536e16cebc162a909bf89abe448b81ec500d4fb9bf - 1 sha256 8388608
+# sha1
+check_root_hash 1024 d0e9163ca8844aaa2e88fe5265a8c5d9ee494a99 $SALT 1 sha1 8388608
+check_root_hash 1024 73509e8e868be6b8ac939817a98a3d35121413b2 dadada 1 sha1 8388608
+
+if check_version 1 3; then
+ echo "Verity data corruption options test."
+ SALT=e48da609055204e89ae53b655ca2216dd983cf3cb829f34f63a297d106d53e2d
+ HASH=9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174
+ prepare 8192 1024
+ check_option 512 $HASH $SALT 1 sha256 "--ignore-corruption" "ignore_corruption"
+ check_option 512 $HASH $SALT 1 sha256 "--restart-on-corruption" "restart_on_corruption"
+ check_option 512 $HASH $SALT 1 sha256 "--ignore-zero-blocks" "ignore_zero_blocks"
+ check_option 512 $HASH $SALT 1 sha256 "--ignore-corruption --ignore-zero-blocks" "ignore_corruption"
+ if check_version 1 4; then
+ check_option 512 $HASH $SALT 1 sha256 "--check-at-most-once" "check_at_most_once"
+ fi
+fi
+
+echo "Veritysetup [hash-offset bigger than 2G works] "
+checkOffsetBug 3000000000 2499997696 256
+checkOffsetBug 10000000000 8000000000 128
+
+echo "Veritysetup [overlap-detection] "
+checkOverlapBug 2097152 1433600
+checkOverlapBug 2097152 1433600 350 4096
+checkOverlapBug 2097152 1228800 350 4096 # data-hash overlap
+checkOverlapBug 2097152 0 350 4096 1228800 # data-fec overlap
+checkOverlapBug 10240000 256000 400 512 256512 # hash-fec overlap
+
+if check_version 1 3; then
+ echo "Veritysetup [FEC tests]"
+ for INDEX in {1..4}; do
+ # in the first iteration check if we can use FEC (it can be compiled-out)
+ (check_fec $IMG $IMG $IMG 4096 30 150 163840 409600 $(($RANDOM % 23 + 2)) $(($INDEX * 4)) )
+ RET=$?
+ [ "$RET" -eq "3" ] && break
+ [ "$RET" -eq "0" ] || fail "FEC repair failed"
+
+ (check_fec $IMG $IMG_HASH $FEC_DEV 4096 30 30 0 0 $(($RANDOM % 23 + 2)) $(($INDEX * 4)) 'n' $SALT) || fail "FEC repair failed"
+ (check_fec $IMG $IMG_HASH $FEC_DEV 4096 35 35 0 0 $(($RANDOM % 23 + 2)) $(($INDEX * 4))) || fail "FEC repair failed"
+ (check_fec $IMG $IMG_HASH $FEC_DEV 512 2000 2000 0 0 $(($RANDOM % 23 + 2)) $(($INDEX * 4))) || fail "FEC repair failed"
+ (check_fec $IMG $IMG_HASH $FEC_DEV 1024 2000 2000 0 0 $(($RANDOM % 23 + 2)) $(($INDEX * 4))) || fail "FEC repair failed"
+ # this test should fail
+ (check_fec $IMG $IMG_HASH $FEC_DEV 4096 30 30 0 0 $(($RANDOM % 23 + 2)) $(($RANDOM % 200 + 200))) && fail "FEC repair must fail"
+ echo "[OK]"
+ done
+fi
+
+echo "Correction in userspace: "
+# checkUserSpaceRepair <#blocks> <block_size> <roots> <hash_offset> <fec_offset> <#devices> <#corrupted bytes>
+checkUserSpaceRepair -1 512 2 0 0 3 100
+checkUserSpaceRepair 400 512 2 256000 0 2 50
+checkUserSpaceRepair 500 512 2 2457600 4915200 1 1
+checkUserSpaceRepair -1 4096 2 0 0 3 10
+checkUserSpaceRepair 400 4096 2 2048000 0 2 1
+#checkUserSpaceRepair 500 4096 2 2457600 4915200 1 2 # FIXME
+
+remove_mapping
+exit 0