* [PATCH 1/6] grub-shell: Set exit status to qemu exit status
2023-01-10 22:08 [PATCH 0/6] Cryptomount testing Glenn Washburn
@ 2023-01-10 22:08 ` Glenn Washburn
2023-01-10 22:08 ` [PATCH 2/6] grub-shell: Only cleanup working directory file if QEMU does not fail or timeout Glenn Washburn
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Glenn Washburn @ 2023-01-10 22:08 UTC (permalink / raw)
To: grub-devel, Daniel Kiper; +Cc: Patrick Steinhardt, Glenn Washburn
This allows us to test if unexpected output in test scripts is because of a
bug in grub, because there was an error in qemu, or qemu was killed due to a
timeout.
Signed-off-by: Glenn Washburn <development@efficientek.com>
---
tests/util/grub-shell.in | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
index 43672e0804..2c0e654c1f 100644
--- a/tests/util/grub-shell.in
+++ b/tests/util/grub-shell.in
@@ -502,6 +502,12 @@ copy_extra_files() {
done
}
+setup_qemu_logger() {
+ cat < "$work_directory/qemu-pipe" | tr -d "\r" | tee "${goutfile}" | do_trim &
+}
+
+ret=0
+mkfifo "$work_directory/qemu-pipe"
if [ x$boot = xnet ]; then
netdir="$work_directory/netdir"
mkdir -p "$netdir"
@@ -509,7 +515,8 @@ if [ x$boot = xnet ]; then
cp "${cfgfile}" "$netdir/boot/grub/grub.cfg"
cp "${source}" "$netdir/boot/grub/testcase.cfg"
[ -z "$files" ] || copy_extra_files "$netdir" $files
- timeout -s KILL $timeout "${qemu}" ${qemuopts} ${serial_null} -serial file:/dev/stdout -boot n -net "user,tftp=$netdir,bootfile=/boot/grub/${grub_modinfo_target_cpu}-${grub_modinfo_platform}/core.$netbootext" -net nic | cat | tr -d "\r" | tee "${goutfile}" | do_trim
+ setup_qemu_logger
+ timeout -s KILL $timeout "${qemu}" ${qemuopts} ${serial_null} -serial file:/dev/stdout -boot n -net "user,tftp=$netdir,bootfile=/boot/grub/${grub_modinfo_target_cpu}-${grub_modinfo_platform}/core.$netbootext" -net nic > "$work_directory/qemu-pipe" || ret=$?
elif [ x$boot = xemu ]; then
rootdir="$work_directory/rootdir"
grubdir="$rootdir/boot/grub"
@@ -528,12 +535,18 @@ elif [ x$boot = xemu ]; then
[ -z "$files" ] || copy_extra_files "$rootdir" $files
roottar="$work_directory/root.tar"
(cd "$rootdir"; tar cf "$roottar" .)
- "${builddir}/grub-core/grub-emu" -m "$device_map" --memdisk "$roottar" -r memdisk -d "/boot/grub" | tr -d "\r" | tee "${goutfile}" | do_trim
+ setup_qemu_logger
+ "${builddir}/grub-core/grub-emu" -m "$device_map" --memdisk "$roottar" -r memdisk -d "/boot/grub" > "$work_directory/qemu-pipe" || ret=$?
test -n "$debug" || rm -rf "$rootdir"
test -n "$debug" || rm -f "$roottar"
else
- timeout -s KILL $timeout "${qemu}" ${qemuopts} ${serial_null} -serial file:/dev/stdout -${device}"${isofile}" ${bootdev} | cat | tr -d "\r" | tee "${goutfile}" | do_trim
+ setup_qemu_logger
+ timeout -s KILL $timeout "${qemu}" ${qemuopts} ${serial_null} -serial file:/dev/stdout -${device}"${isofile}" ${bootdev} > "$work_directory/qemu-pipe" || ret=$?
fi
+
+wait
+rm -f "$work_directory/qemu-pipe"
+
if [ x$boot = xcoreboot ]; then
test -n "$debug" || rm -f "${imgfile}"
fi
@@ -541,6 +554,6 @@ test -n "$debug" || rm -f "${isofile}"
test -n "$debug" || rm -rf "${rom_directory}"
test -n "$debug" || rm -f "${tmpfile}" "${cfgfile}" "${goutfile}"
-exit 0
+exit $ret
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 2/6] grub-shell: Only cleanup working directory file if QEMU does not fail or timeout
2023-01-10 22:08 [PATCH 0/6] Cryptomount testing Glenn Washburn
2023-01-10 22:08 ` [PATCH 1/6] grub-shell: Set exit status to qemu exit status Glenn Washburn
@ 2023-01-10 22:08 ` Glenn Washburn
2023-01-10 22:08 ` [PATCH 3/6] grub-shell: Allow specifying non-default trim line contents Glenn Washburn
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Glenn Washburn @ 2023-01-10 22:08 UTC (permalink / raw)
To: grub-devel, Daniel Kiper; +Cc: Patrick Steinhardt, Glenn Washburn
This keeps the generated files to aid in diagnosing the source of the
failure.
Signed-off-by: Glenn Washburn <development@efficientek.com>
---
tests/util/grub-shell.in | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
index 2c0e654c1f..e5d34d1d35 100644
--- a/tests/util/grub-shell.in
+++ b/tests/util/grub-shell.in
@@ -537,8 +537,6 @@ elif [ x$boot = xemu ]; then
(cd "$rootdir"; tar cf "$roottar" .)
setup_qemu_logger
"${builddir}/grub-core/grub-emu" -m "$device_map" --memdisk "$roottar" -r memdisk -d "/boot/grub" > "$work_directory/qemu-pipe" || ret=$?
- test -n "$debug" || rm -rf "$rootdir"
- test -n "$debug" || rm -f "$roottar"
else
setup_qemu_logger
timeout -s KILL $timeout "${qemu}" ${qemuopts} ${serial_null} -serial file:/dev/stdout -${device}"${isofile}" ${bootdev} > "$work_directory/qemu-pipe" || ret=$?
@@ -547,8 +545,16 @@ fi
wait
rm -f "$work_directory/qemu-pipe"
+if [ "$ret" -ne 0 ]; then
+ # If QEMU failure, keep generated files to reproduce
+ exit $ret
+fi
+
if [ x$boot = xcoreboot ]; then
test -n "$debug" || rm -f "${imgfile}"
+elif [ x$boot = xemu ]; then
+ test -n "$debug" || rm -rf "$rootdir"
+ test -n "$debug" || rm -f "$roottar"
fi
test -n "$debug" || rm -f "${isofile}"
test -n "$debug" || rm -rf "${rom_directory}"
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 3/6] grub-shell: Allow specifying non-default trim line contents
2023-01-10 22:08 [PATCH 0/6] Cryptomount testing Glenn Washburn
2023-01-10 22:08 ` [PATCH 1/6] grub-shell: Set exit status to qemu exit status Glenn Washburn
2023-01-10 22:08 ` [PATCH 2/6] grub-shell: Only cleanup working directory file if QEMU does not fail or timeout Glenn Washburn
@ 2023-01-10 22:08 ` Glenn Washburn
2023-01-10 22:08 ` [PATCH 4/6] grub-shell: Trim line should always be matched from the beginning of the line Glenn Washburn
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Glenn Washburn @ 2023-01-10 22:08 UTC (permalink / raw)
To: grub-devel, Daniel Kiper; +Cc: Patrick Steinhardt, Glenn Washburn
This will be useful for tests that have unwanted output from setup. This is
not documented because its only intended to be internal at the moment. Also,
--no-trim is allowed to explicitly turn off trim.
Signed-off-by: Glenn Washburn <development@efficientek.com>
---
tests/util/grub-shell.in | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
index e5d34d1d35..585f0d066e 100644
--- a/tests/util/grub-shell.in
+++ b/tests/util/grub-shell.in
@@ -32,6 +32,7 @@ PATH="${builddir}:$PATH"
export PATH
trim=0
+trim_head=664cbea8-132f-4770-8aa4-1696d59ac35c
# Usage: usage
# Print the usage.
@@ -226,8 +227,13 @@ for option in "$@"; do
echo "$0 (GNU GRUB ${PACKAGE_VERSION})"
exit 0 ;;
--trim)
- trim=1
+ trim=1 ;;
+ --trim=*)
+ trim=2
+ trim_head=`echo "$option" | sed -e 's/--trim=//' -e 's/,/ /g'`
;;
+ --no-trim)
+ trim=0 ;;
--debug)
debug=1 ;;
--modules=*)
@@ -353,8 +359,6 @@ terminal_input ${term}
terminal_output ${term}
EOF
-trim_head=664cbea8-132f-4770-8aa4-1696d59ac35c
-
if [ $trim = 1 ]; then
echo "echo $trim_head" >>${cfgfile}
fi
@@ -479,8 +483,8 @@ fi
do_trim ()
{
- if [ $trim = 1 ]; then
- awk '{ if (have_head == 1) print $0; } /664cbea8-132f-4770-8aa4-1696d59ac35c/ { have_head=1; }'
+ if [ $trim = 1 ] || [ $trim = 2 ]; then
+ awk '{ if (have_head == 1) print $0; } /'"$trim_head"'/ { have_head=1; }'
else
cat
fi
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 4/6] grub-shell: Trim line should always be matched from the beginning of the line
2023-01-10 22:08 [PATCH 0/6] Cryptomount testing Glenn Washburn
` (2 preceding siblings ...)
2023-01-10 22:08 ` [PATCH 3/6] grub-shell: Allow specifying non-default trim line contents Glenn Washburn
@ 2023-01-10 22:08 ` Glenn Washburn
2023-01-10 22:08 ` [PATCH 5/6] grub-shell: Add halt_cmd variable to testcase namespace Glenn Washburn
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Glenn Washburn @ 2023-01-10 22:08 UTC (permalink / raw)
To: grub-devel, Daniel Kiper; +Cc: Patrick Steinhardt, Glenn Washburn
When turning on shell tracing the trim line will be output before we
actually want to start the trim. However, in this case the trim line never
starts from the beginning of the line. So start trimming from the correct
line by matching from the beginning of the line.
Signed-off-by: Glenn Washburn <development@efficientek.com>
---
tests/util/grub-shell.in | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
index 585f0d066e..f41e1a0b68 100644
--- a/tests/util/grub-shell.in
+++ b/tests/util/grub-shell.in
@@ -360,7 +360,7 @@ terminal_output ${term}
EOF
if [ $trim = 1 ]; then
- echo "echo $trim_head" >>${cfgfile}
+ echo "echo; echo $trim_head" >>${cfgfile}
fi
rom_directory="$work_directory/rom_directory"
@@ -484,7 +484,7 @@ fi
do_trim ()
{
if [ $trim = 1 ] || [ $trim = 2 ]; then
- awk '{ if (have_head == 1) print $0; } /'"$trim_head"'/ { have_head=1; }'
+ awk '{ if (have_head == 1) print $0; } /^'"$trim_head"'/ { have_head=1; }'
else
cat
fi
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 5/6] grub-shell: Add halt_cmd variable to testcase namespace
2023-01-10 22:08 [PATCH 0/6] Cryptomount testing Glenn Washburn
` (3 preceding siblings ...)
2023-01-10 22:08 ` [PATCH 4/6] grub-shell: Trim line should always be matched from the beginning of the line Glenn Washburn
@ 2023-01-10 22:08 ` Glenn Washburn
2023-01-10 22:09 ` [PATCH 6/6] tests: Add cryptomount functional test Glenn Washburn
2023-01-12 16:23 ` [PATCH 0/6] Cryptomount testing Daniel Kiper
6 siblings, 0 replies; 9+ messages in thread
From: Glenn Washburn @ 2023-01-10 22:08 UTC (permalink / raw)
To: grub-devel, Daniel Kiper; +Cc: Patrick Steinhardt, Glenn Washburn
This allows test case scripts to use the appropriate halt command for the
built architecture to end execution early. Otherwise, test case scripts
have no way to know the appropriate mechanism for halting the test case
early.
Signed-off-by: Glenn Washburn <development@efficientek.com>
---
tests/util/grub-shell.in | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
index f41e1a0b68..8db6ba86ec 100644
--- a/tests/util/grub-shell.in
+++ b/tests/util/grub-shell.in
@@ -331,6 +331,8 @@ fi
cfgfile="$work_directory/grub.cfg"
cat <<EOF >${cfgfile}
grubshell=yes
+halt_cmd=${halt_cmd}
+export halt_cmd
enable_progress_indicator=0
export enable_progress_indicator
EOF
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 6/6] tests: Add cryptomount functional test
2023-01-10 22:08 [PATCH 0/6] Cryptomount testing Glenn Washburn
` (4 preceding siblings ...)
2023-01-10 22:08 ` [PATCH 5/6] grub-shell: Add halt_cmd variable to testcase namespace Glenn Washburn
@ 2023-01-10 22:09 ` Glenn Washburn
2023-01-12 16:23 ` [PATCH 0/6] Cryptomount testing Daniel Kiper
6 siblings, 0 replies; 9+ messages in thread
From: Glenn Washburn @ 2023-01-10 22:09 UTC (permalink / raw)
To: grub-devel, Daniel Kiper; +Cc: Patrick Steinhardt, Glenn Washburn
The grub_cmd_cryptomount make check test performs some functional testing
of cryptomount and by extension the underlying cryptodisk infrastructure.
A utility test script named grub-shell-luks-tester is created to handle the
complexities of the testing, making it simpler to add new test cases in
grub_cmd_cryptomount.
Signed-off-by: Glenn Washburn <development@efficientek.com>
---
Makefile.util.def | 12 +
tests/grub_cmd_cryptomount.in | 185 ++++++++++++++
tests/util/grub-shell-luks-tester.in | 366 +++++++++++++++++++++++++++
3 files changed, 563 insertions(+)
create mode 100644 tests/grub_cmd_cryptomount.in
create mode 100644 tests/util/grub-shell-luks-tester.in
diff --git a/Makefile.util.def b/Makefile.util.def
index d919c562c4..22dabba358 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -743,6 +743,12 @@ script = {
installdir = noinst;
};
+script = {
+ name = grub-shell-luks-tester;
+ common = tests/util/grub-shell-luks-tester.in;
+ installdir = noinst;
+};
+
script = {
name = grub-fs-tester;
common = tests/util/grub-fs-tester.in;
@@ -1039,6 +1045,12 @@ script = {
common = tests/grub_script_return.in;
};
+script = {
+ testcase = nonnative;
+ name = grub_cmd_cryptomount;
+ common = tests/grub_cmd_cryptomount.in;
+};
+
script = {
testcase = nonnative;
name = grub_cmd_regexp;
diff --git a/tests/grub_cmd_cryptomount.in b/tests/grub_cmd_cryptomount.in
new file mode 100644
index 0000000000..b05cd3800e
--- /dev/null
+++ b/tests/grub_cmd_cryptomount.in
@@ -0,0 +1,185 @@
+#! @BUILD_SHEBANG@ -e
+
+# Run all grub cryptomount tests in a Qemu instance
+# Copyright (C) 2023 Free Software Foundation, Inc.
+#
+# GRUB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GRUB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+
+if [ "x$EUID" = "x" ] ; then
+ EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+ echo "not root; cannot test cryptomount."
+ exit 77
+fi
+
+if ! which cryptsetup >/dev/null 2>&1; then
+ echo "cryptsetup not installed; cannot test cryptomount."
+ exit 77
+fi
+
+if ! which mkfs.vfat >/dev/null 2>&1; then
+ echo "mkfs.vfat not installed; cannot test cryptomount."
+ exit 77
+fi
+
+COMMON_OPTS='${V:+--debug=$V} --cs-opts="--pbkdf-force-iterations 1000"'
+
+_testcase() {
+ local EXPECTEDRES=$1
+ local LOGPREFIX=$2
+ local res=0
+ local output
+ shift 2
+
+ # Create a subdir in TMPDIR for each testcase
+ _TMPDIR=$TMPDIR
+ TMPDIR=$TMPDIR/`echo -n "$(date +%s).$LOGPREFIX" | sed -e 's,[ /],_,g' -e 's,:$,,g'`
+ mkdir -p "$TMPDIR"
+
+ output=`"$@" 2>&1` || res=$?
+ TMPDIR=$_TMPDIR
+
+ if [ "$res" -eq "$EXPECTEDRES" ]; then
+ if [ "$res" -eq 0 ]; then
+ echo $LOGPREFIX PASS
+ else
+ echo $LOGPREFIX XFAIL
+ fi
+ else
+ echo "Error[$res]: $output"
+ if [ "$res" -eq 0 ]; then
+ echo $LOGPREFIX XPASS
+ elif [ "$res" -eq 1 ]; then
+ echo $LOGPREFIX FAIL
+ else
+ # Any exit code other than 1 or 0, indicates a hard error,
+ # not a test error
+ echo $LOGPREFIX ERROR
+ return 99
+ fi
+ return 1
+ fi
+}
+
+testcase() { _testcase 0 "$@"; }
+testcase_fail() { _testcase 1 "$@"; }
+
+### LUKS1 tests
+eval testcase "'LUKS1 test cryptsetup defaults:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS
+
+eval testcase "'LUKS1 test with twofish cipher:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS \
+ "--cs-opts='--cipher twofish-xts-plain64'"
+
+eval testcase "'LUKS1 test key file support:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS \
+ --keyfile
+
+eval testcase "'LUKS1 test key file with offset:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS \
+ --keyfile --cs-opts="--keyfile-offset=237"
+
+eval testcase "'LUKS1 test key file with offset and size:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS \
+ --keyfile "--cs-opts='--keyfile-offset=237 --keyfile-size=1023'"
+
+eval testcase "'LUKS1 test detached header support:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS \
+ --detached-header
+
+eval testcase "'LUKS1 test both detached header and key file:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS \
+ --keyfile --detached-header
+
+### LUKS2 tests (mirroring the LUKS1 tests above)
+LUKS2_COMMON_OPTS="--luks=2 --cs-opts=--pbkdf=pbkdf2"
+eval testcase "'LUKS2 test cryptsetup defaults:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS
+
+eval testcase "'LUKS2 test with twofish cipher:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ "--cs-opts='--cipher twofish-xts-plain64'"
+
+eval testcase "'LUKS2 test key file support:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ --keyfile
+
+eval testcase "'LUKS2 test key file with offset:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ --keyfile --cs-opts="--keyfile-offset=237"
+
+eval testcase "'LUKS2 test key file with offset and size:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ --keyfile "--cs-opts='--keyfile-offset=237 --keyfile-size=1023'"
+
+eval testcase "'LUKS2 test detached header support:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ --detached-header
+
+eval testcase "'LUKS2 test both detached header and key file:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ --keyfile --detached-header
+
+### LUKS1 specific tests
+# Tests for xts-plain and xts-plain64 modes
+eval testcase "'LUKS1 test cryptsetup xts-plain:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS \
+ "--cs-opts='--cipher aes-xts-plain'"
+
+eval testcase "'LUKS1 test cryptsetup xts-plain64:'" \
+ @builddir@/grub-shell-luks-tester --luks=1 $COMMON_OPTS \
+ "--cs-opts='--cipher aes-xts-plain64'"
+
+### LUKS2 specific tests
+eval testcase "'LUKS2 test with 1k sector size:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ "--cs-opts='--sector-size 1024'"
+
+eval testcase "'LUKS2 test with 2k sector size:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ "--cs-opts='--sector-size 2048'"
+
+eval testcase "'LUKS2 test with 4k sector size:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ "--cs-opts='--sector-size 4096'"
+
+eval testcase "'LUKS2 test with non-default key slot:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ "--cs-opts='--key-slot 5'"
+
+eval testcase "'LUKS2 test with different metadata size:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ "--cs-opts='--luks2-metadata-size 512k'"
+
+# TODO: Expect a failure with LUKS2 volumes with argon2 key derivation
+eval testcase_fail "'LUKS2 test with argon2 pbkdf:'" \
+ @builddir@/grub-shell-luks-tester --luks=2 $COMMON_OPTS \
+ "--cs-opts='--pbkdf-memory 32'" "--cs-opts='--pbkdf-parallel 1'"
+
+# Add good password to second slot and change first slot to unchecked password
+csscript=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 99
+cat >$csscript <<'EOF'
+ CSOPTS="--pbkdf-force-iterations 1000 --pbkdf=pbkdf2"
+ cryptsetup $CSOPTS --key-file $lukskeyfile luksAddKey $luksdiskfile $lukskeyfile
+ echo "newpass" | cryptsetup $CSOPTS --key-file $lukskeyfile --key-slot 0 luksChangeKey $luksdiskfile
+EOF
+
+eval testcase "'LUKS2 test with second key slot and first slot using different password:'" \
+ @builddir@/grub-shell-luks-tester $LUKS2_COMMON_OPTS $COMMON_OPTS \
+ "--cs-script='$csscript'"
+
+exit 0
diff --git a/tests/util/grub-shell-luks-tester.in b/tests/util/grub-shell-luks-tester.in
new file mode 100644
index 0000000000..258f043a68
--- /dev/null
+++ b/tests/util/grub-shell-luks-tester.in
@@ -0,0 +1,366 @@
+#! @BUILD_SHEBANG@ -e
+
+# Test GRUBs ability to read various LUKS containers
+# Copyright (C) 2023 Free Software Foundation, Inc.
+#
+# GRUB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GRUB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+
+# Initialize some variables.
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+datarootdir="@datarootdir@"
+builddir="@builddir@"
+PACKAGE_NAME=@PACKAGE_NAME@
+PACKAGE_TARNAME=@PACKAGE_TARNAME@
+PACKAGE_VERSION=@PACKAGE_VERSION@
+
+# Force build directory components
+PATH="${builddir}:$PATH"
+export PATH
+
+grub_shell_opts=
+disksize=20M
+detached_header=
+keyfile=
+keyfile_offset=
+keyfile_size=
+KEYFILE_SIZE_MAX=4096
+
+# Usage: usage
+# Print the usage.
+usage () {
+ cat <<EOF
+Usage: $0 [OPTION] [SOURCE]
+Create a LUKS disk with cryptsetup, then verify that it is accessible by grub
+running in a QEMU instance.
+
+ -h, --help print this message and exit
+ -v, --version print the version information and exit
+ --modules=MODULES pre-load specified modules MODULES
+ --qemu-opts=OPTIONS extra options to pass to Qemu instance
+ --cs-opts=OPTIONS extra options to pass to cryptsetup instance
+ --cs-script=FILE script of cryptsetup commands to be run after format
+ --luks=1|2 Use LUKS1 or LUKS2 volumes
+ --detached-header Use a detached header
+ --keyfile[=FILE] Use a randomly generated key file of size $KEYFILE_SIZE_MAX if not
+ given a FILE to use as the key file.
+
+$0 creates a LUKS disk with cryptsetup, then verify that it is accessible by
+grub running in a QEMU instance.
+
+Report bugs to <bug-grub@gnu.org>.
+EOF
+}
+
+. "${builddir}/grub-core/modinfo.sh"
+
+# TODO: We should be selecting the drive based on disk id, change this once
+# grub support searching by disk id.
+disk="hd0"
+case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in
+ i386-qemu)
+ disk="ata0"
+ ;;
+esac
+
+# Check the arguments.
+for option in "$@"; do
+ case "$option" in
+ -h | --help)
+ usage
+ exit 0 ;;
+ -v | --version)
+ echo "$0 (GNU GRUB ${PACKAGE_VERSION})"
+ exit 0 ;;
+ -d | --debug)
+ debug=$((${debug:-0}+1)) ;;
+ --debug=*)
+ debug=$((`echo "$option" | sed -e 's/--debug=//'`)) ;;
+ --modules=*)
+ ms=`echo "$option" | sed -e 's/--modules=//'`
+ modules="$modules,$ms" ;;
+ --qemu-opts=*)
+ qs=`echo "$option" | sed -e 's/--qemu-opts=//'`
+ qemuopts="$qemuopts $qs" ;;
+ --cs-opts=*)
+ qs=`echo "$option" | sed -e 's/--cs-opts=//'`
+ csopts="$csopts $qs" ;;
+ --cs-script=*)
+ qs=`echo "$option" | sed -e 's/--cs-script=//'`
+ csscripts="$csscripts $qs" ;;
+ --luks=*)
+ qs=`echo "$option" | sed -e 's/--luks=//'`
+ csopts="$csopts --type luks$qs" ;;
+ --detached-header)
+ detached_header=1 ;;
+ --keyfile=*)
+ qs=`echo "$option" | sed -e 's/--keyfile=//'`
+ keyfile="$qs" ;;
+ --keyfile)
+ keyfile=1 ;;
+ --disksize=*)
+ qs=`echo "$option" | sed -e 's/--disksize=//'`
+ disksize="$qs" ;;
+ -*)
+ echo "Unrecognized option \`$option'" 1>&2
+ usage
+ exit 3
+ ;;
+ *)
+ if [ "x${source}" != x ] ; then
+ echo "too many parameters at the end" 1>&2
+ usage
+ exit 4
+ fi
+ source="${option}" ;;
+ esac
+done
+
+[ "${debug:-0}" -gt 1 ] && set -x
+
+grub_shell_opts="$grub_shell_opts --timeout=600s"
+
+if [ "${debug:-0}" -gt 2 ]; then
+ grub_shell_opts="$grub_shell_opts --qemu-opts=-nographic"
+fi
+
+# Make sure that the dm-crypto device is shutdown
+cleanup() {
+ if [ -e "$luksdev" ]; then
+ cryptsetup close "$luksdev"
+ fi
+ [ -z "$debug" ] && rm -rf "$lukstestdir" || :
+}
+trap cleanup EXIT INT TERM KILL QUIT
+
+get_random_bytes() {
+ local NUM_BYTES=$1
+ dd if=/dev/urandom bs=512 count=$((($NUM_BYTES / 512)+2)) 2>/dev/null \
+ | tr -d '\0' | dd bs=1 count=$(($NUM_BYTES)) 2>/dev/null
+}
+
+# create a random directory to be hold generated files
+lukstestdir="`mktemp -d "${TMPDIR:-/tmp}/$(basename "$0").XXXXXXXXXX"`" || exit 20
+luksfile=$lukstestdir/luks.disk
+lukshdrfile=$lukstestdir/luks.header
+lukskeyfile=$lukstestdir/luks.key
+vfile=$lukstestdir/mnt/test.verify
+vtext="TEST VERIFIED"
+testvars=$lukstestdir/testvars
+testcase=$lukstestdir/testcase.cfg
+testoutput=$lukstestdir/testoutput
+password=testpass
+
+[ -n "$debug" ] && echo "LUKS TEST directory: $lukstestdir" >&2
+
+# If testing keyfiles, create a big one.
+if [ -e "$keyfile" ]; then
+ password=`cat "$keyfile"`
+elif [ -n "$keyfile" ]; then
+ password=`get_random_bytes $KEYFILE_SIZE_MAX`
+fi
+
+if [ -n "$detached_header" ]; then
+ csopts="$csopts --header $lukshdrfile"
+fi
+
+# create the key file
+echo -n "$password" > $lukskeyfile
+
+# Create a very small LUKS container for the test
+truncate -s $disksize $luksfile || exit 21
+
+# Format the luks disk file
+cryptsetup luksFormat -q $csopts $luksfile $lukskeyfile || exit 22
+
+# Run any cryptsetup scripts
+export luksdiskfile=${detached_header:+$lukshdrfile}${detached_header:-$luksfile}
+export lukskeyfile
+for csscript in $csscripts; do
+ [ -f "$csscript" ] && . $csscript
+done
+
+# Look for --keyfile-offset and --keyfile-size options in the cryptsetup
+# options, and process them specially.
+csopen_opts=
+get_args=0
+varname=
+for option in $csopts; do
+ if [ "$get_args" -gt 0 ]; then
+ csopen_opts=" $csopen_opts $option"
+ get_args=$(($get_args - 1))
+ eval ${varname}=$option
+ continue
+ fi
+
+ case "$option" in
+ --keyfile-offset)
+ varname=keyfile_offset
+ get_args=1 ;;
+ --keyfile-offset=*)
+ keyfile_offset=`echo "$option" | sed -e 's/--keyfile-offset=//'` ;;
+ --keyfile-size | -l)
+ varname=keyfile_size
+ get_args=1 ;;
+ --keyfile-size=*)
+ keyfile_size=`echo "$option" | sed -e 's/--keyfile-size=//'` ;;
+ *)
+ continue ;;
+ esac
+
+ csopen_opts=" $csopen_opts $option"
+done
+
+# Open LUKS device
+luksdev=/dev/mapper/`basename $lukstestdir`
+cryptsetup open ${detached_header:+--header $lukshdrfile} $csopen_opts \
+ --key-file $lukskeyfile $luksfile `basename $luksdev` || exit 23
+
+# Make filesystem on the luks disk
+mkfs.vfat $luksdev >/dev/null 2>&1 || exit 24
+
+# Add verification file to filesystem
+mkdir $lukstestdir/mnt
+mount $luksdev $lukstestdir/mnt || exit 25
+echo "$vtext" > $vfile
+
+# Unmount filesystem
+umount $lukstestdir/mnt || exit 26
+
+. "@builddir@/grub-core/modinfo.sh"
+
+if [ x"${grub_modinfo_platform}" = xemu ]; then
+ grub_testvars="(host)$testvars"
+ grub_key_file="(host)$lukskeyfile"
+ grub_lukshdr_file="(host)$lukshdrfile"
+else
+ grub_testvars="/testvars"
+ grub_key_file="/keyfile"
+ grub_lukshdr_file="/luks.header"
+fi
+
+
+# Can not use --disk with a raw LUKS container because it appears qemu
+# tries to convert the image to and is failing with:
+# "Parameter 'key-secret' is required for cipher"
+qemuopts="$qemuopts -drive file=$luksfile,index=0,media=disk,format=raw"
+
+# Add crypto modules
+modules="$modules cryptodisk luks luks2 fat"
+
+# Create randomly generated trim line
+trim_line=`mktemp -u XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX`
+
+# Create vars to import into grub script
+cat >$testvars <<EOF
+grub_debug="$debug"
+grub_lukshdr_file="$grub_lukshdr_file"
+grub_key_file="$grub_key_file"
+grub_keyfile_offset="$keyfile_offset"
+grub_keyfile_size="$keyfile_size"
+vfilename="`basename $vfile`"
+vtext="$vtext"
+trim_line="$trim_line"
+disk="$disk"
+EOF
+
+# If testing keyfiles, do not use password variable
+if [ -z "$keyfile" ]; then
+ echo "grub_password=\"$password\"" >>$testvars
+fi
+
+# Create testcase script
+cat >$testcase <<'EOF'
+set debug=all
+search -n -f --set=testvarsdev /testvars
+if [ "$?" -ne 0 ]; then
+ echo; echo "$trim_line"
+ echo "Could not find testvars file."
+ ${halt_cmd}
+fi
+set debug=
+
+. ($testvarsdev)/testvars
+
+# If key file exists, use it instead of password
+if [ -e "$grub_key_file" ]; then
+ cryptomount_opts="$cryptomount_opts -k $grub_key_file"
+else
+ cryptomount_opts="$cryptomount_opts -p $grub_password"
+fi
+
+if [ -n "$grub_keyfile_offset" ]; then
+ cryptomount_opts="$cryptomount_opts -O $grub_keyfile_offset"
+fi
+
+if [ -n "$grub_keyfile_size" ]; then
+ cryptomount_opts="$cryptomount_opts -S $grub_keyfile_size"
+fi
+
+if [ -e "$grub_lukshdr_file" ]; then
+ cryptomount_opts="$cryptomount_opts -H $grub_lukshdr_file"
+fi
+
+cdisk=crypto0
+
+if test -n "$grub_debug" -a "$grub_debug" -gt 0; then
+ echo cmd: cryptomount $cryptomount_opts ($disk)
+ echo -n "devices: "
+ ls
+fi
+
+if test -n "$grub_debug" -a "$grub_debug" -gt 1; then
+ set debug=all
+fi
+cryptomount $cryptomount_opts ($disk)
+ret="$?"
+if test -n "$grub_debug" -a "$grub_debug" -eq 2; then
+ set debug=
+fi
+
+echo; echo "$trim_line"
+if test $ret -eq 0; then
+ cat ($cdisk)/$vfilename
+else
+ echo "cryptomount failed: $ret"
+fi
+EOF
+
+grub_shell_opts="$grub_shell_opts --trim=${trim_line}"
+if [ -n "$keyfile" ]; then
+ grub_shell_opts="$grub_shell_opts --files=${keyfile:+${grub_key_file}=${lukskeyfile}}"
+fi
+
+if [ -n "$detached_header" ]; then
+ grub_shell_opts="$grub_shell_opts --files=${detached_header:+${grub_lukshdr_file}=${lukshdrfile}}"
+fi
+
+# Run the test in grub-shell
+@builddir@/grub-shell ${debug:+--debug} $grub_shell_opts \
+ --modules="$modules" --qemu-opts="$qemuopts" \
+ --files="${grub_testvars}=${testvars}" "$testcase" \
+ >$testoutput
+ret=$?
+
+if [ "$ret" -eq 0 ]; then
+ if ! grep -q "^${vtext}$" "$testoutput"; then
+ echo "error: test not verified [`cat $testoutput`]" >&2
+ exit 1
+ fi
+else
+ echo "grub-shell exited with error: $ret" >&2
+ exit 27
+fi
+
+exit $ret
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 0/6] Cryptomount testing
2023-01-10 22:08 [PATCH 0/6] Cryptomount testing Glenn Washburn
` (5 preceding siblings ...)
2023-01-10 22:09 ` [PATCH 6/6] tests: Add cryptomount functional test Glenn Washburn
@ 2023-01-12 16:23 ` Daniel Kiper
2023-01-13 8:13 ` Patrick Steinhardt
6 siblings, 1 reply; 9+ messages in thread
From: Daniel Kiper @ 2023-01-12 16:23 UTC (permalink / raw)
To: Glenn Washburn; +Cc: grub-devel, Patrick Steinhardt
On Tue, Jan 10, 2023 at 04:08:54PM -0600, Glenn Washburn wrote:
> This patch series adds a variety of functional cryptomount LUKS1/2 tests by
> creating a LUKS container on the host and verifying that data inside can be
> read accurately from a virtualized GRUB. This should be especially useful
> when we eventually get around to upgrading the gcrypt library.
>
> Glenn
>
> Glenn Washburn (6):
> grub-shell: Set exit status to qemu exit status
> grub-shell: Only cleanup working directory file if QEMU does not fail
> or timeout
> grub-shell: Allow specifying non-default trim line contents
> grub-shell: Trim line should always be matched from the beginning of
> the line
> grub-shell: Add halt_cmd variable to testcase namespace
> tests: Add cryptomount functional test
For all the patches Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
Thank you for adding the LUKS tests.
Daniel
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 0/6] Cryptomount testing
2023-01-12 16:23 ` [PATCH 0/6] Cryptomount testing Daniel Kiper
@ 2023-01-13 8:13 ` Patrick Steinhardt
0 siblings, 0 replies; 9+ messages in thread
From: Patrick Steinhardt @ 2023-01-13 8:13 UTC (permalink / raw)
To: The development of GNU GRUB; +Cc: Glenn Washburn
[-- Attachment #1: Type: text/plain, Size: 1097 bytes --]
On Thu, Jan 12, 2023 at 05:23:24PM +0100, Daniel Kiper wrote:
> On Tue, Jan 10, 2023 at 04:08:54PM -0600, Glenn Washburn wrote:
> > This patch series adds a variety of functional cryptomount LUKS1/2 tests by
> > creating a LUKS container on the host and verifying that data inside can be
> > read accurately from a virtualized GRUB. This should be especially useful
> > when we eventually get around to upgrading the gcrypt library.
> >
> > Glenn
> >
> > Glenn Washburn (6):
> > grub-shell: Set exit status to qemu exit status
> > grub-shell: Only cleanup working directory file if QEMU does not fail
> > or timeout
> > grub-shell: Allow specifying non-default trim line contents
> > grub-shell: Trim line should always be matched from the beginning of
> > the line
> > grub-shell: Add halt_cmd variable to testcase namespace
> > tests: Add cryptomount functional test
>
> For all the patches Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
>
> Thank you for adding the LUKS tests.
>
> Daniel
Seconded, thanks a bunch for these!
Patrick
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread