ci: add test suite for verity+luks disk images
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user