ci: add test suite for verity+luks disk images

This commit is contained in:
Lennart Poettering
2026-07-16 07:10:07 +02:00
parent 1423d78dc9
commit d14c40919a
+162
View File
@@ -1556,6 +1556,168 @@ EOF
veritysetup dump "${loop}p2" | grep 'Data blocks:' | grep "$data_verity_blocks" >/dev/null
}
testcase_verity_encrypt() {
local defs imgs output loop drh hrh part_size dm_devno verity_dep
if ( . /etc/os-release && [[ "$ID" == "postmarketos" ]] ); then
echo "Skipping verity+encrypt test on postmarketOS."
return
fi
defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod 0755 "$defs"
echo "*** dm-verity + LUKS2 (verity envelope around encrypted data) ***"
echo -n "wetterfrosch" >"$imgs/key"
# Encrypting verity hash partitions must be refused
tee "$defs/verity-data.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyFiles=${defs}
Verity=data
VerityMatchKey=root
Encrypt=key-file
SizeMaxBytes=1G
EOF
tee "$defs/verity-hash.conf" <<EOF
[Partition]
Type=root-${architecture}-verity
Verity=hash
VerityMatchKey=root
Encrypt=key-file
EOF
(! systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \
--seed="$seed" \
--dry-run=yes \
--empty=create \
--size=auto \
--key-file="$imgs/key" \
"$imgs/refused")
# Minimize= on the hash partition of an encrypted data partition must be refused. Set Minimize= on the
# data partition as well, so that the generic "data partition does not set CopyBlocks= or Minimize="
# check doesn't fire first and the encryption-specific check is actually reached.
tee "$defs/verity-data.conf" <<EOF
[Partition]
Type=root-${architecture}
Format=ext4
CopyFiles=${defs}
Verity=data
VerityMatchKey=root
Encrypt=key-file
Minimize=guess
SizeMaxBytes=1G
EOF
tee "$defs/verity-hash.conf" <<EOF
[Partition]
Type=root-${architecture}-verity
Verity=hash
VerityMatchKey=root
Minimize=yes
EOF
(! systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \
--seed="$seed" \
--dry-run=yes \
--empty=create \
--size=auto \
--key-file="$imgs/key" \
"$imgs/refused") |& grep "Minimize= cannot be set for verity hash partitions whose data partition is encrypted" >/dev/null
# Now a valid combination: the hash partition is sized via SizeMaxBytes= of the data partition
tee "$defs/verity-data.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyFiles=${defs}
Verity=data
VerityMatchKey=root
Encrypt=key-file
SizeMaxBytes=1G
EOF
tee "$defs/verity-hash.conf" <<EOF
[Partition]
Type=root-${architecture}-verity
Verity=hash
VerityMatchKey=root
EOF
output=$(systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \
--seed="$seed" \
--dry-run=no \
--empty=create \
--size=auto \
--key-file="$imgs/key" \
--json=pretty \
"$imgs/verity-encrypt")
drh=$(jq -r ".[] | select(.type == \"root-${architecture}\") | .roothash" <<<"$output")
hrh=$(jq -r ".[] | select(.type == \"root-${architecture}-verity\") | .roothash" <<<"$output")
assert_neq "$drh" "null"
assert_eq "$drh" "$hrh"
if systemd-detect-virt --quiet --container; then
echo "Skipping verity+encrypt test dissect part in container."
return
fi
loop="$(systemd-dissect --attach "$imgs/verity-encrypt")"
# Make sure the loopback device gets cleaned up
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs' ; systemd-dissect --detach '$loop'" RETURN ERR
# The data partition must contain LUKS ciphertext as its outermost layer ...
blkid --output value --match-tag TYPE "${loop}p1" | grep -x crypto_LUKS
# ... and the verity hash data must cover exactly that ciphertext
veritysetup verify "${loop}p1" "${loop}p2" "$drh"
# Dissection must set up verity as the outer envelope and LUKS inside of it. The LUKS passphrase is
# picked up via the dissect.passphrase credential.
mkdir -p "$imgs/creds"
echo -n "wetterfrosch" >"$imgs/creds/dissect.passphrase"
systemd-dissect --root-hash "$drh" "$imgs/verity-encrypt"
systemd-dissect --root-hash "$drh" --validate --image-policy "root=encrypted+verity" "$imgs/verity-encrypt"
# A policy that doesn't allow encryption must be refused
(! systemd-dissect --root-hash "$drh" --validate --image-policy "root=verity" "$imgs/verity-encrypt")
CREDENTIALS_DIRECTORY="$imgs/creds" systemd-dissect --root-hash "$drh" -M "$imgs/verity-encrypt" "$imgs/mnt"
# shellcheck disable=SC2064
trap "umount --quiet --recursive '$imgs/mnt' || : ; rm -rf '$defs' '$imgs' ; systemd-dissect --detach '$loop'" RETURN ERR
# Check that both DM layers are stacked as expected: the mounted device is a LUKS volume backed by a
# dm-verity device
dm_devno=$(findmnt --noheadings --output MAJ:MIN "$imgs/mnt" | tr -d ' ')
[[ "$(dmsetup table -j "${dm_devno%%:*}" -m "${dm_devno##*:}" | cut -d' ' -f3)" == "crypt" ]]
verity_dep=$(dmsetup deps -o devname -j "${dm_devno%%:*}" -m "${dm_devno##*:}" | sed 's/.*(\(.*\))/\1/')
[[ "$(dmsetup table "/dev/mapper/$verity_dep" | cut -d' ' -f3)" == "verity" ]]
# The copied-in files must be intact
cmp "$defs/verity-data.conf" "$imgs/mnt$defs/verity-data.conf"
systemd-dissect -U "$imgs/mnt"
# Now corrupt a block in the middle of the encrypted data partition and check that verification fails
part_size=$(blockdev --getsize64 "${loop}p1")
dd if=/dev/urandom of="${loop}p1" bs=4096 count=1 seek=$(( part_size / 2 / 4096 )) oflag=direct conv=notrunc
(! veritysetup verify "${loop}p1" "${loop}p2" "$drh")
}
testcase_exclude_files() {
local defs imgs root output