Skip to content

Commit

Permalink
tests/nested, tests/lib/snaps: make core20-fde-dbx test more realistic (
Browse files Browse the repository at this point in the history
#14952)

* tests/lib/snaps/store/test-snapd-efitools: test snap for manipulating efi variables

Signed-off-by: Maciej Borzecki <[email protected]>

* tests/nested/manual/core20-fde-dbx: perform actual DBX update

Update the test to be more realistic and perform an actual update of DBX
EFI variable.

Signed-off-by: Maciej Borzecki <[email protected]>

* tests/nested/manual/core20-fde-dbx: workaround inconsistent dbx content on UC20/UC22+

There is a discrepancy in the content of dbx between UC20 and later
releases, that shows up only after booting the system. It is suspected
that some component of boot chain injects additional keys.

Signed-off-by: Maciej Borzecki <[email protected]>

* tests/nested/manual/core20-fde-dbx: add scenario with a full update cycle followed by reboot

Signed-off-by: Maciej Borzecki <[email protected]>

---------

Signed-off-by: Maciej Borzecki <[email protected]>
  • Loading branch information
bboozzoo authored Feb 14, 2025
1 parent 40abdd0 commit aa4704e
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 5 deletions.
6 changes: 6 additions & 0 deletions tests/lib/snaps/store/test-snapd-efitools/bin/cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

cmd="$1"
shift

exec "$SNAP/usr/bin/$cmd" "$@"
25 changes: 25 additions & 0 deletions tests/lib/snaps/store/test-snapd-efitools/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: test-snapd-efitools
summary: A snap for manipulating EFI tools (for testing snapd and Ubuntu Core).
description: |
A snap for manipulating EFI variables. Used in snapd and Ubuntu Core testing
workflows.
version: 1.9.2-3ubuntu3
base: core24
confinement: strict

apps:
tool:
command: bin/cmd
plugs:
- fwupd
- hardware-observe

parts:
efitools:
plugin: nil
stage-packages:
- efitools

snap-files:
plugin: dump
source: .
Binary file removed tests/nested/manual/core20-fde-dbx/dbx-1-update.auth
Binary file not shown.
126 changes: 121 additions & 5 deletions tests/nested/manual/core20-fde-dbx/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,31 @@ environment:
NESTED_UBUNTU_SEED_SIZE: 1500M

prepare: |
# TODO:FDEM: copy nested vars file to "$NESTED_ASSETS_DIR/OVMF_VARS.snakeoil.fd"
#
tests.pkgs install efitools
tests.nested build-image core
tests.nested create-vm core
tests.nested create-vm core
remote.exec sudo snap install --devmode test-snapd-efitools
remote.exec sudo test-snapd-efitools.tool efi-readvar -v dbx 2>&1 | tee efi-dbx-state-initial.log
# count how many entries we have in DBX initially, this should be identical
# across UC20-UC24+ systems since we are using the same OVMF variables blob,
# but on UC20 2 additional entries get added at runtime
grep -c 'List ' efi-dbx-state-initial.log > initial-dbx-entries-count
keys_dir="$(tests.nested get assets-path)/ovmf/secboot/"
# generate 3 dbx updates
MYGUID="11111111-0000-1111-0000-000000000000"
for i in 1 2 3; do
# generate a key
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=bad key $i/" \
-keyout "bad-key-$i.key" -out "bad-key-$i.crt" -days 3650 -nodes -sha256
# convert to EFI sig list
cert-to-efi-sig-list -g $MYGUID "bad-key-$i.crt" "bad-key-$i.esl"
# and sign as an update for appending
sign-efi-sig-list -a -c "$keys_dir/KEK.crt" -k "$keys_dir/KEK.key" dbx \
"bad-key-$i.esl" "dbx-$i-update.auth"
done
execute: |
echo "Establish initial state"
Expand Down Expand Up @@ -128,9 +149,11 @@ execute: |
fetch_and_check_reseal_count_equal "$((reseal_count_start + 6))"
# TODO:FDEM: update DBX
#
# real DBX update, with reboot between prepare and cleanup
#
echo "Attempt a valid 'prepare' request, followed by a reboot"
echo "Attempt a valid 'prepare' request, followed by a DBX update and then a reboot"
echo "{\"action\":\"efi-secureboot-update-db-prepare\",\"key-database\":\"DBX\",\"payload\":\"$update_payload\"}" | \
remote.exec "sudo snap debug api -X POST -H 'Content-Type: application/json' /v2/system-secureboot" > prepare.out
jq -r .status < prepare.out | MATCH "OK"
Expand All @@ -141,6 +164,22 @@ execute: |
fetch_and_check_reseal_count_equal "$((reseal_count_start + 7))"
echo "Update content of DBX"
initial_dbx_entries_count="$(cat initial-dbx-entries-count)"
# get initial state of all variables
remote.exec sudo test-snapd-efitools.tool efi-readvar 2>&1 | tee efi-vars.log
remote.push dbx-1-update.auth
remote.exec "sudo chattr -i /sys/firmware/efi/efivars/dbx-*"
# update dbx
remote.exec sudo test-snapd-efitools.tool efi-readvar -v dbx 2>&1 | tee efi-dbx-before.log
# expecting no additional entries in the list
grep -c 'List ' efi-dbx-before.log | MATCH "$initial_dbx_entries_count"
remote.exec sudo test-snapd-efitools.tool efi-updatevar -a -f dbx-1-update.auth dbx
remote.exec sudo test-snapd-efitools.tool efi-readvar -v dbx 2>&1 | tee efi-dbx-after.log
# expecting one additional entry in the list
grep -c 'List ' efi-dbx-after.log | MATCH "$((initial_dbx_entries_count + 1))"
# reboot
boot_id="$( tests.nested boot-id )"
remote.exec "sudo reboot" || true
remote.wait-for reboot "${boot_id}"
Expand All @@ -155,3 +194,80 @@ execute: |
remote.exec snap change --last=fde-efi-secureboot-db-update | MATCH 'Done .* Reseal after external EFI DBX update'
fetch_and_check_reseal_count_equal "$((reseal_count_start + 8))"
#
# real DBX update, with reboot after completing the prepare/cleanup cycle
#
echo "Another DBX update with snapd notification, followed by a reboot"
update_payload_2="$(base64 -w0 dbx-2-update.auth)"
echo "{\"action\":\"efi-secureboot-update-db-prepare\",\"key-database\":\"DBX\",\"payload\":\"$update_payload_2\"}" | \
remote.exec "sudo snap debug api -X POST -H 'Content-Type: application/json' /v2/system-secureboot" > prepare.out
jq -r .status < prepare.out | MATCH "OK"
fetch_and_check_reseal_count_equal "$((reseal_count_start + 9))"
remote.push dbx-2-update.auth
remote.exec "sudo chattr -i /sys/firmware/efi/efivars/dbx-*"
# update dbx
remote.exec sudo test-snapd-efitools.tool efi-readvar -v dbx 2>&1 | tee efi-dbx-before-2.log
# one additional entry from previous scenario
grep -c 'List ' efi-dbx-before-2.log | MATCH "$((initial_dbx_entries_count + 1))"
remote.exec sudo test-snapd-efitools.tool efi-updatevar -a -f dbx-2-update.auth dbx
remote.exec sudo test-snapd-efitools.tool efi-readvar -v dbx 2>&1 | tee efi-dbx-after-2.log
# and one more, 2 in total
grep -c 'List ' efi-dbx-after-2.log | MATCH "$((initial_dbx_entries_count + 2))"
echo '{"action":"efi-secureboot-update-db-cleanup"}' | \
remote.exec "sudo snap debug api -X POST -H 'Content-Type: application/json' /v2/system-secureboot" > cleanup.out
jq -r .status < prepare.out | MATCH "OK"
remote.exec snap change --last=fde-efi-secureboot-db-update | MATCH 'Done .* Reseal after external EFI DBX update'
fetch_and_check_reseal_count_equal "$((reseal_count_start + 10))"
# reboot
boot_id="$( tests.nested boot-id )"
remote.exec "sudo reboot" || true
remote.wait-for reboot "${boot_id}"
# the system should come up
remote.exec "snap list"
#
# real DBX update without notifying snapd, stops asking for recovery key during boot
#
echo "Push a DBX update without notifying snapd, which should result in requesting a recovery key on boot"
remote.push dbx-3-update.auth
remote.exec "sudo chattr -i /sys/firmware/efi/efivars/dbx-*"
remote.exec sudo test-snapd-efitools.tool efi-readvar -v dbx 2>&1 | tee efi-dbx-before-3.log
# 2 entries based on the previous updates
grep -c 'List ' efi-dbx-before-3.log | MATCH "$((initial_dbx_entries_count + 2))"
remote.exec sudo test-snapd-efitools.tool efi-updatevar -a -f dbx-3-update.auth dbx
remote.exec sudo test-snapd-efitools.tool efi-readvar -v dbx 2>&1 | tee efi-dbx-after-3.log
# a new key appeared as well
grep -c 'List ' efi-dbx-after-3.log | MATCH "$((initial_dbx_entries_count + 3))"
# get the recovery key first
recovery_key=$(remote.exec "sudo snap recovery --show-keys" | sed 's/^recovery: *//')
boot_id="$(tests.nested boot-id)"
remote.exec "sudo reboot" || true
sent_recovery=0
for (( i=0 ; i < 100 ; i++ )); do
if [ "${sent_recovery}" -lt "$(tests.nested get serial-log | grep -c "Please enter the recovery key for volume")" ]; then
sent_recovery=$((sent_recovery+1))
echo "${recovery_key}" | nc -q 0 127.0.0.1 7777
break
fi
echo "-- still trying"
sleep 10
done
test "${sent_recovery}" -gt 0
remote.wait-for reboot "$boot_id"
remote.exec "snap list"
remote.exec "sudo journalctl -b0" | MATCH "successfully activated encrypted device .* using a fallback activation method"

0 comments on commit aa4704e

Please sign in to comment.