Files
snapd/tests/lib/tools/tests.nested
Michael Vogt caf7a137ae boot,secboot: reset DA lockout counter after successful boot
* gadget/device: introduce package which provides helpers for locations of things

Various helpers for getting location of things were spread out or doubled in the
code base. This package aggregates them in one place.

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>

* boot,secboot: reset DA lockout counter after successful boot

The TPM DictionaryAttack lockout counter is incremented after each
unclean shutdown according to Chris Coulson in LP:1979185.

This means that eventually enough unclean shutdowns the system
fails to boot and asks for the recovery key. To fix this snapd
needs to clean the DA lockout counter after each successful
run.

* device: add missing doc string for TpmLockoutAuthUnder

* secboot: add missing tests around MarkSuccessful

* tests: add nested core20-da-lockout test

This commits adds a nested core20 test that triggers a bunch of
unclean shutdowns in a nested VM. On a system that does not have
the new `secboot.MarkSuccessful()` code this will eventually
trigger a recovery key prompt as each unclean reboot increases
the DA lockout counter by one.
```
google-nested:ubuntu-20.04-64 /tmp/work-dir/logs# tail -n1 /tmp/work-dir/logs/serial.log
Please enter the recovery key for disk /dev/disk/by-partuuid/3a1bacae-5d46-ce4b-960a-4074d18a8c05: (press TAB for no echo)
```

* devicestate: fix go fmt error

* tests: set nested/manual/core20-da-lockout to manual and improve comment/description

* secboot: improve docstrings

* secboot: shuffle code around so that tests with `-tags nosecboot` work correctly

* boot,device: extract StampSealedKeys,SealedKeysMethod from boot to device

* secboot: use new device.SealedKeysMethod()

* tests: make core20-da-lockout faster by reading the da lockout counter directly (thanks to Chris Coulson)

* tests: add new 'test.nested vm unclean-reboot` and use in da lockout test

* tests: retry on lockout counter reading

The lockout counter is cleared during snapd startup so we need
to retry for a bit to see it cleared.

* tests: fix whitespace

* secboot: improve test around testMarkSuccessfulEncrypted and also check authValue

* secboot: fix silly typo (thanks to Samuele)

Co-authored-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
2022-07-12 18:38:05 +02:00

457 lines
11 KiB
Bash
Executable File

#!/bin/bash -e
show_help() {
echo "usage: prepare"
echo " restore"
echo " build-image IMAGE-TYPE"
echo " create-vm IMAGE-TYPE [--param-cdrom PARAM] [--param-mem PARAM]"
echo " is-nested [core|classic|uc16|uc18|uc20|uc22]"
echo " show [ATTRIBUTE]"
echo " vm <ACTION>"
echo " exec [--user <USER>] [--pwd <PWD>] <CMD>"
echo " copy <FILEPATH>"
echo " get <ARTIFACT>"
echo " download <REMOTE_FILE>"
echo " wait-for <EVENT>"
echo " boot-id"
echo " is-enabled <tpm|kvm|secboot>"
echo " secboot-sign <file|gadget> <PATH> <KEY> <CERT>"
echo " transition <recovery-system> <system-mode>"
echo " snap-rev <snap-name> [channel]"
echo " build-seed <seed-dir> <seed-name> <label>"
echo ""
echo "Available options:"
echo " -h --help show this help message."
echo ""
echo "COMMANDS:"
echo " prepare: creates all the directories needed to run a nested test"
echo " restore: removes all the directories and data used by nested tests"
echo " build-image: creates an image using ubuntu image tool"
echo " create-vm: creates new virtual machine and leave it running"
echo " is-nested: indicates if the execution is using a nested vm"
echo " vm: runs an action for the current vm"
echo " exec: executes a command in the vm"
echo " copy: copies a file to the vm"
echo " get: retrieves an artifact"
echo " download: download an artifact"
echo " wait-for: waits for the specified event"
echo " boot-id: prints the boot id"
echo " is-enabled: indicated if the feature is enabled"
echo " secboot-sign: signs an artifact"
echo " transition: transition to system mode (just available for uc20)"
echo " snap-rev: get the snap rev in the vm (prints the installed rev if no channel provided)"
echo " build-seed build a seed that can be used to boot a vm"
echo ""
echo "IMAGE-TYPES:"
echo " core: work with a core image"
echo " classic: work with a classic image"
echo ""
echo "ATTRIBUTE:"
echo " version: the version of the system i.e. 16, 18, 20, 22"
echo ""
echo "ACTION:"
echo " start: starts a stopped vm"
echo " stop: shutdowns a running vm"
echo " remove: removes a vm"
echo " status: retrieves status for a running vm"
echo ""
echo "ARTIFACT:"
echo " serial-log: serial log for the nested vm"
echo " model-authority: authority id for the current model"
echo " image-name: then name of the image used for the test"
echo " current-name: then name of the image being executed"
echo " extra-snaps-path: paths used to store extra snaps"
echo " assets-path: path used to store vm assets"
echo " images-path: path used to store vm images"
echo ""
echo "REMOTE_FILE:"
echo " snakeoil-key: snakeoil key"
echo " image-url: url used to build a classic vm"
echo " spread: the spread binary"
echo ""
echo "EVENT:"
echo " ssh: it is possible to ssh to the vm"
echo " no-ssh: is not possible to ssh to the vm"
echo " snap-command: snap command is available in the vm"
echo " reboot: reboot is done in the vm"
echo " device-initialized: the device is initialized and has a serial"
echo ""
}
prepare() {
nested_prepare_env
}
restore() {
nested_cleanup_env
}
build_image() {
if [ $# -eq 0 ]; then
show_help
exit 1
fi
while [ $# -gt 0 ]; do
case "$1" in
classic)
nested_create_classic_vm
exit
;;
core)
nested_create_core_vm
exit
;;
*)
echo "tests.nested: expected either classic or core as argument" >&2
exit 1
;;
esac
done
}
create_vm() {
if [ $# -eq 0 ]; then
show_help
exit 1
fi
local action=
case "$1" in
classic)
shift 1
action=nested_start_classic_vm
;;
core)
shift 1
action=nested_start_core_vm
;;
*)
echo "tests.nested: unsupported parameter $1" >&2
exit 1
;;
esac
while [ $# -gt 0 ]; do
case "$1" in
--param-cdrom)
export NESTED_PARAM_CD="$2"
shift 2
;;
--param-mem)
export NESTED_PARAM_MEM="$2"
shift 2
;;
*)
echo "tests.nested: unsupported parameter $1" >&2
exit 1
;;
esac
done
"$action"
}
is_nested() {
if [ $# -eq 0 ]; then
nested_is_nested_system
else
case "$1" in
core)
nested_is_core_system
;;
classic)
nested_is_classic_system
;;
uc16)
nested_is_core_16_system
;;
uc18)
nested_is_core_18_system
;;
uc20)
nested_is_core_20_system
;;
uc22)
nested_is_core_22_system
;;
*)
echo "tests.nested: parameter not supported: $1" >&2
exit 1
;;
esac
fi
}
show() {
if [ $# -eq 0 ]; then
echo "tests.nested: attribute to show is required" >&2
exit 1
else
case "$1" in
version)
nested_get_version
;;
*)
echo "tests.nested: attribute not supported: $1" >&2
exit 1
;;
esac
fi
}
vm() {
case "$1" in
start)
nested_start
;;
stop)
nested_shutdown
;;
remove)
nested_destroy_vm
;;
status)
nested_status_vm
;;
unclean-reboot)
nested_force_restart_vm
;;
*)
echo "tests.nested: action not supported: $1" >&2
exit 1
;;
esac
}
exec() {
local user pwd
while [ $# -gt 0 ]; do
case "$1" in
--user)
user="$2"
shift 2
;;
--pwd)
pwd="$2"
shift 2
;;
*)
break
;;
esac
done
if [ -n "$user" ]; then
if [ -z "$pwd" ]; then
echo "tests.nested: password needed to execute command" >&2
exit 1
fi
nested_exec_as "$user" "$pwd" "$@"
else
nested_exec "$@"
fi
}
copy() {
nested_copy "$@"
}
get() {
if [ $# -eq 0 ]; then
show_help
exit 1
fi
local action=
case "$1" in
serial-log)
action=nested_print_serial_log
shift
;;
model-authority)
action=nested_model_authority
shift
;;
image-name)
action=nested_get_image_name
shift
;;
current-name)
action=nested_get_current_image_name
shift
;;
extra-snaps-path)
action=nested_get_extra_snaps_path
shift
;;
assets-path)
action=nested_get_assets_path
shift
;;
images-path)
action=nested_get_images_path
shift
;;
*)
echo "tests.nested: unsupported parameter $1" >&2
exit 1
;;
esac
"$action" "$@"
}
download() {
if [ $# -eq 0 ]; then
show_help
exit 1
fi
local action=
case "$1" in
snakeoil-key)
action=nested_get_snakeoil_key
shift
;;
image-url)
action=nested_get_image_url_for_vm
shift
;;
spread)
action=nested_fetch_spread
shift
;;
*)
echo "tests.nested: unsupported parameter $1" >&2
exit 1
;;
esac
"$action" "$@"
}
wait_for() {
if [ $# -eq 0 ]; then
show_help
exit 1
fi
local action=
case "$1" in
ssh)
action=nested_wait_for_ssh
shift
;;
no-ssh)
action=nested_wait_for_no_ssh
shift
;;
snap-command)
action=nested_wait_for_snap_command
shift
;;
reboot)
action=nested_wait_for_reboot
shift
;;
device-initialized)
action=nested_wait_for_device_initialized_change
shift
;;
*)
echo "tests.nested: unsupported parameter $1" >&2
exit 1
;;
esac
"$action" "$@"
}
boot_id() {
nested_get_boot_id
}
is_enabled() {
case "$1" in
kvm)
nested_is_kvm_enabled
;;
tpm)
nested_is_tpm_enabled
;;
secboot)
nested_is_secure_boot_enabled
;;
*)
echo "tests.nested: feature not supported: $1" >&2
exit 1
;;
esac
}
secboot_sign() {
case "$1" in
file)
shift
nested_secboot_sign_file "$@"
;;
gadget)
shift
nested_secboot_sign_gadget "$@"
;;
*)
echo "tests.nested: action not supported: $1" >&2
exit 1
;;
esac
}
transition() {
nested_uc20_transition_to_system_mode "$@"
}
snap_rev() {
if [ $# -eq 0 ] || [ $# -gt 2 ]; then
show_help
exit 1
elif [ $# -eq 1 ]; then
nested_get_core_revision_installed "$@"
else
nested_get_core_revision_for_channel "$@"
fi
}
build_seed() {
nested_build_seed_cdrom "$@"
}
main() {
if [ $# -eq 0 ]; then
show_help
exit 0
fi
local subcommand="$1"
local action=
while [ $# -gt 0 ]; do
case "$1" in
-h|--help)
show_help
exit 0
;;
*)
action=$(echo "$subcommand" | tr '-' '_')
shift
break
;;
esac
done
if [ -z "$(declare -f "$action")" ]; then
echo "tests.nested: no such command: $subcommand"
show_help
exit 1
fi
#shellcheck source=tests/lib/nested.sh
. "$TESTSLIB/nested.sh"
"$action" "$@"
}
main "$@"