Message ID | 166379417897.433612.16268594042547006566.stgit@djiang5-desk3.ch.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ndctl: Add security test for cxl devices through nvdimm | expand |
On Wed, 2022-09-21 at 14:02 -0700, Dave Jiang wrote: > Create security-cxl.sh based off of security.sh for nfit security testing. > The test will test a cxl_test based security commands enabling through > nvdimm. Since the new test is largely a copy of the NFIT security test, I think it might be better to split out the common portions into a script that can be sourced, and then from the main tests, call functions defined by the sourced script with appropriate arguments to specify the module (cxl_test) and bus ($CXL_TEST_BUS). If the actual test sequence of tests 1 through 6 is the same between NFIT and CXL, those could be wrapped in a run_security_tests wrapper which can be called as: run_security_tests "cxl_test" "$CXL_TEST_BUS" or run_security_tests "nfit_test" "$NFIT_TEST_BUS0" This would allow Jeff's recent fix to get pulled in for the CXL test too. > > Signed-off-by: Dave Jiang <dave.jiang@intel.com> > --- > test/common | 7 + > test/meson.build | 7 + > test/security-cxl.sh | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 296 insertions(+) > create mode 100755 test/security-cxl.sh I think in line with the other cxl tests, a better name would be cxl-security.sh > > diff --git a/test/common b/test/common > index 65615cc09a3e..e13b79728b0c 100644 > --- a/test/common > +++ b/test/common > @@ -47,6 +47,7 @@ fi > # > NFIT_TEST_BUS0="nfit_test.0" > NFIT_TEST_BUS1="nfit_test.1" > +CXL_TEST_BUS="cxl_test" > ACPI_BUS="ACPI.NFIT" > E820_BUS="e820" > > @@ -125,6 +126,12 @@ _cleanup() > modprobe -r nfit_test > } > > +_cxl_cleanup() > +{ > + $NDCTL disable-region -b $CXL_TEST_BUS all > + modprobe -r cxl_test > +} > + > # json2var > # stdin: json > # > diff --git a/test/meson.build b/test/meson.build > index 5953c286d13f..485deb89bbe2 100644 > --- a/test/meson.build > +++ b/test/meson.build > @@ -219,6 +219,13 @@ if get_option('keyutils').enabled() > ] > endif > > +if get_option('keyutils').enabled() > + security_cxl = find_program('security-cxl.sh') > + tests += [ > + [ 'security-cxl.sh', security_cxl, 'ndctl' ] > + ] > +endif > + > foreach t : tests > test(t[0], t[1], > is_parallel : false, > diff --git a/test/security-cxl.sh b/test/security-cxl.sh > new file mode 100755 > index 000000000000..0ec9b335bf41 > --- /dev/null > +++ b/test/security-cxl.sh > @@ -0,0 +1,282 @@ > +#!/bin/bash -Ex > +# SPDX-License-Identifier: GPL-2.0 > +# Copyright (C) 2022 Intel Corporation. All rights reserved. > + > +rc=77 > +dev="" > +id="" > +keypath="/etc/ndctl/keys" > +masterkey="nvdimm-master" > +masterpath="$keypath/$masterkey.blob" > +backup_key=0 > +backup_handle=0 > + > +. $(dirname $0)/common > + > +trap 'err $LINENO' ERR > + > +setup() > +{ > + $NDCTL disable-region -b "$CXL_TEST_BUS" all > +} > + > +detect() > +{ > + dev="$($NDCTL list -b "$CXL_TEST_BUS" -D | jq -r 'sort_by(.id) | .[0].dev')" > + [ -n "$dev" ] || err "$LINENO" > + id="$($NDCTL list -b "$CXL_TEST_BUS" -D | jq -r 'sort_by(.id) | .[0].id')" > + [ -n "$id" ] || err "$LINENO" > +} > + > +setup_keys() > +{ > + if [ ! -d "$keypath" ]; then > + mkdir -p "$keypath" > + fi > + > + if [ -f "$masterpath" ]; then > + mv "$masterpath" "$masterpath.bak" > + backup_key=1 > + fi > + if [ -f "$keypath/tpm.handle" ]; then > + mv "$keypath/tpm.handle" "$keypath/tpm.handle.bak" > + backup_handle=1 > + fi > + > + dd if=/dev/urandom bs=1 count=32 2>/dev/null | keyctl padd user "$masterkey" @u > + keyctl pipe "$(keyctl search @u user $masterkey)" > "$masterpath" > +} > + > +test_cleanup() > +{ > + if keyctl search @u encrypted nvdimm:"$id"; then > + keyctl unlink "$(keyctl search @u encrypted nvdimm:"$id")" > + fi > + > + if keyctl search @u user "$masterkey"; then > + keyctl unlink "$(keyctl search @u user "$masterkey")" > + fi > + > + if [ -f "$keypath"/nvdimm_"$id"_"$(hostname)".blob ]; then > + rm -f "$keypath"/nvdimm_"$id"_"$(hostname)".blob > + fi > +} > + > +post_cleanup() > +{ > + if [ -f $masterpath ]; then > + rm -f "$masterpath" > + fi > + if [ "$backup_key" -eq 1 ]; then > + mv "$masterpath.bak" "$masterpath" > + fi > + if [ "$backup_handle" -eq 1 ]; then > + mv "$keypath/tpm.handle.bak" "$keypath/tpm.handle" > + fi > +} > + > +lock_dimm() > +{ > + $NDCTL disable-dimm "$dev" > + test_dimm_path="" > + > + nmem_rpath=$(readlink -f "/sys/bus/nd/devices/${dev}") > + nmem_bus=$(dirname ${nmem_rpath}); > + bus_provider_path="${nmem_bus}/provider" > + test -e "$bus_provider_path" || err "$LINENO" > + bus_provider=$(cat ${bus_provider_path}) > + > + [[ "$bus_provider" == "$CXL_TEST_BUS" ]] || err "$LINENO" > + bus="cxl" > + nmem_provider_path="/sys/bus/nd/devices/${dev}/${bus}/provider" > + nmem_provider=$(cat ${nmem_provider_path}) > + > + test_dimm_path=$(readlink -f /sys/bus/$bus/devices/${nmem_provider}) > + test_dimm_path=$(dirname $(dirname ${test_dimm_path}))/security_lock > + > + test -e "$test_dimm_path" > + > + # now lock the dimm > + echo 1 > "${test_dimm_path}" > + sstate="$(get_security_state)" > + if [ "$sstate" != "locked" ]; then > + echo "Incorrect security state: $sstate expected: locked" > + err "$LINENO" > + fi > +} > + > +get_frozen_state() > +{ > + $NDCTL list -i -b "$CXL_TEST_BUS" -d "$dev" | jq -r .[].dimms[0].security_frozen > +} > + > +get_security_state() > +{ > + $NDCTL list -i -b "$CXL_TEST_BUS" -d "$dev" | jq -r .[].dimms[0].security > +} > + > +setup_passphrase() > +{ > + $NDCTL setup-passphrase "$dev" -k user:"$masterkey" > + sstate="$(get_security_state)" > + if [ "$sstate" != "unlocked" ]; then > + echo "Incorrect security state: $sstate expected: unlocked" > + err "$LINENO" > + fi > +} > + > +remove_passphrase() > +{ > + $NDCTL remove-passphrase "$dev" > + sstate="$(get_security_state)" > + if [ "$sstate" != "disabled" ]; then > + echo "Incorrect security state: $sstate expected: disabled" > + err "$LINENO" > + fi > +} > + > +erase_security() > +{ > + $NDCTL sanitize-dimm -c "$dev" > + sstate="$(get_security_state)" > + if [ "$sstate" != "disabled" ]; then > + echo "Incorrect security state: $sstate expected: disabled" > + err "$LINENO" > + fi > +} > + > +update_security() > +{ > + $NDCTL update-passphrase "$dev" > + sstate="$(get_security_state)" > + if [ "$sstate" != "unlocked" ]; then > + echo "Incorrect security state: $sstate expected: unlocked" > + err "$LINENO" > + fi > +} > + > +freeze_security() > +{ > + $NDCTL freeze-security "$dev" > +} > + > +test_1_security_setup_and_remove() > +{ > + setup_passphrase > + remove_passphrase > +} > + > +test_2_security_setup_and_update() > +{ > + setup_passphrase > + update_security > + remove_passphrase > +} > + > +test_3_security_setup_and_erase() > +{ > + setup_passphrase > + erase_security > +} > + > +test_4_security_unlock() > +{ > + setup_passphrase > + lock_dimm > + $NDCTL enable-dimm "$dev" > + sstate="$(get_security_state)" > + if [ "$sstate" != "unlocked" ]; then > + echo "Incorrect security state: $sstate expected: unlocked" > + err "$LINENO" > + fi > + $NDCTL disable-region -b "$CXL_TEST_BUS" all > + remove_passphrase > +} > + > +# This should always be the last nvdimm security test. > +# with security frozen, cxl_test must be removed and is no longer usable > +test_5_security_freeze() > +{ > + setup_passphrase > + freeze_security > + sstate="$(get_security_state)" > + fstate="$(get_frozen_state)" > + if [ "$fstate" != "true" ]; then > + echo "Incorrect security state: expected: frozen" > + err "$LINENO" > + fi > + > + # need to simulate a soft reboot here to clean up > + lock_dimm > + $NDCTL enable-dimm "$dev" > + sstate="$(get_security_state)" > + if [ "$sstate" != "unlocked" ]; then > + echo "Incorrect security state: $sstate expected: unlocked" > + err "$LINENO" > + fi > +} > + > +test_6_load_keys() > +{ > + if keyctl search @u encrypted nvdimm:"$id"; then > + keyctl unlink "$(keyctl search @u encrypted nvdimm:"$id")" > + fi > + > + if keyctl search @u user "$masterkey"; then > + keyctl unlink "$(keyctl search @u user "$masterkey")" > + fi > + > + $NDCTL load-keys > + > + if keyctl search @u user "$masterkey"; then > + echo "master key loaded" > + else > + echo "master key failed to loaded" > + err "$LINENO" > + fi > + > + if keyctl search @u encrypted nvdimm:"$id"; then > + echo "dimm key loaded" > + else > + echo "dimm key failed to load" > + err "$LINENO" > + fi > +} > + > +check_min_kver "5.0" || do_skip "may lack security handling" > +uid="$(keyctl show | grep -Eo "_uid.[0-9]+" | head -1 | cut -d. -f2-)" > +if [ "$uid" -ne 0 ]; then > + do_skip "run as root or with a sudo login shell for test to work" > +fi > + > +modprobe cxl_test > +setup > +check_prereq "keyctl" > +rc=1 > +detect > +test_cleanup > +setup_keys > +echo "Test 1, security setup and remove" > +test_1_security_setup_and_remove > +echo "Test 2, security setup, update, and remove" > +test_2_security_setup_and_update > +echo "Test 3, security setup and erase" > +test_3_security_setup_and_erase > +echo "Test 4, unlock dimm" > +test_4_security_unlock > + > +# Freeze should always be the last nvdimm security test because it locks > +# security state and require cxl_test module unload. However, this does > +# not impact any key management testing via libkeyctl. > +echo "Test 5, freeze security" > +test_5_security_freeze > + > +# Load-keys is independent of actual nvdimm security and is part of key > +# mangement testing. > +echo "Test 6, test load-keys" > +test_6_load_keys > + > +test_cleanup > +post_cleanup > +_cxl_cleanup > +exit 0 > >
Dave Jiang wrote: > Create security-cxl.sh based off of security.sh for nfit security testing. > The test will test a cxl_test based security commands enabling through > nvdimm. > > Signed-off-by: Dave Jiang <dave.jiang@intel.com> > --- > test/common | 7 + > test/meson.build | 7 + > test/security-cxl.sh | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 296 insertions(+) > create mode 100755 test/security-cxl.sh > > diff --git a/test/common b/test/common > index 65615cc09a3e..e13b79728b0c 100644 > --- a/test/common > +++ b/test/common > @@ -47,6 +47,7 @@ fi > # > NFIT_TEST_BUS0="nfit_test.0" > NFIT_TEST_BUS1="nfit_test.1" > +CXL_TEST_BUS="cxl_test" > ACPI_BUS="ACPI.NFIT" > E820_BUS="e820" > > @@ -125,6 +126,12 @@ _cleanup() > modprobe -r nfit_test > } > > +_cxl_cleanup() > +{ > + $NDCTL disable-region -b $CXL_TEST_BUS all > + modprobe -r cxl_test > +} > + > # json2var > # stdin: json > # > diff --git a/test/meson.build b/test/meson.build > index 5953c286d13f..485deb89bbe2 100644 > --- a/test/meson.build > +++ b/test/meson.build > @@ -219,6 +219,13 @@ if get_option('keyutils').enabled() > ] > endif > > +if get_option('keyutils').enabled() > + security_cxl = find_program('security-cxl.sh') > + tests += [ > + [ 'security-cxl.sh', security_cxl, 'ndctl' ] > + ] > +endif > + I had this folded on top for my local testing: diff --git a/test/meson.build b/test/meson.build index c9853421ce69..1df115f82fef 100644 --- a/test/meson.build +++ b/test/meson.build @@ -216,15 +216,10 @@ endif if get_option('keyutils').enabled() security = find_program('security.sh') - tests += [ - [ 'security.sh', security, 'ndctl' ] - ] -endif - -if get_option('keyutils').enabled() security_cxl = find_program('security-cxl.sh') tests += [ - [ 'security-cxl.sh', security_cxl, 'ndctl' ] + [ 'security.sh', security, 'ndctl' ], + [ 'security-cxl.sh', security_cxl, 'cxl' ], ] endif ...although I like Vishal's suggestion to name this cxl-security.sh to match the other cxl test in the suite.
diff --git a/test/common b/test/common index 65615cc09a3e..e13b79728b0c 100644 --- a/test/common +++ b/test/common @@ -47,6 +47,7 @@ fi # NFIT_TEST_BUS0="nfit_test.0" NFIT_TEST_BUS1="nfit_test.1" +CXL_TEST_BUS="cxl_test" ACPI_BUS="ACPI.NFIT" E820_BUS="e820" @@ -125,6 +126,12 @@ _cleanup() modprobe -r nfit_test } +_cxl_cleanup() +{ + $NDCTL disable-region -b $CXL_TEST_BUS all + modprobe -r cxl_test +} + # json2var # stdin: json # diff --git a/test/meson.build b/test/meson.build index 5953c286d13f..485deb89bbe2 100644 --- a/test/meson.build +++ b/test/meson.build @@ -219,6 +219,13 @@ if get_option('keyutils').enabled() ] endif +if get_option('keyutils').enabled() + security_cxl = find_program('security-cxl.sh') + tests += [ + [ 'security-cxl.sh', security_cxl, 'ndctl' ] + ] +endif + foreach t : tests test(t[0], t[1], is_parallel : false, diff --git a/test/security-cxl.sh b/test/security-cxl.sh new file mode 100755 index 000000000000..0ec9b335bf41 --- /dev/null +++ b/test/security-cxl.sh @@ -0,0 +1,282 @@ +#!/bin/bash -Ex +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2022 Intel Corporation. All rights reserved. + +rc=77 +dev="" +id="" +keypath="/etc/ndctl/keys" +masterkey="nvdimm-master" +masterpath="$keypath/$masterkey.blob" +backup_key=0 +backup_handle=0 + +. $(dirname $0)/common + +trap 'err $LINENO' ERR + +setup() +{ + $NDCTL disable-region -b "$CXL_TEST_BUS" all +} + +detect() +{ + dev="$($NDCTL list -b "$CXL_TEST_BUS" -D | jq -r 'sort_by(.id) | .[0].dev')" + [ -n "$dev" ] || err "$LINENO" + id="$($NDCTL list -b "$CXL_TEST_BUS" -D | jq -r 'sort_by(.id) | .[0].id')" + [ -n "$id" ] || err "$LINENO" +} + +setup_keys() +{ + if [ ! -d "$keypath" ]; then + mkdir -p "$keypath" + fi + + if [ -f "$masterpath" ]; then + mv "$masterpath" "$masterpath.bak" + backup_key=1 + fi + if [ -f "$keypath/tpm.handle" ]; then + mv "$keypath/tpm.handle" "$keypath/tpm.handle.bak" + backup_handle=1 + fi + + dd if=/dev/urandom bs=1 count=32 2>/dev/null | keyctl padd user "$masterkey" @u + keyctl pipe "$(keyctl search @u user $masterkey)" > "$masterpath" +} + +test_cleanup() +{ + if keyctl search @u encrypted nvdimm:"$id"; then + keyctl unlink "$(keyctl search @u encrypted nvdimm:"$id")" + fi + + if keyctl search @u user "$masterkey"; then + keyctl unlink "$(keyctl search @u user "$masterkey")" + fi + + if [ -f "$keypath"/nvdimm_"$id"_"$(hostname)".blob ]; then + rm -f "$keypath"/nvdimm_"$id"_"$(hostname)".blob + fi +} + +post_cleanup() +{ + if [ -f $masterpath ]; then + rm -f "$masterpath" + fi + if [ "$backup_key" -eq 1 ]; then + mv "$masterpath.bak" "$masterpath" + fi + if [ "$backup_handle" -eq 1 ]; then + mv "$keypath/tpm.handle.bak" "$keypath/tpm.handle" + fi +} + +lock_dimm() +{ + $NDCTL disable-dimm "$dev" + test_dimm_path="" + + nmem_rpath=$(readlink -f "/sys/bus/nd/devices/${dev}") + nmem_bus=$(dirname ${nmem_rpath}); + bus_provider_path="${nmem_bus}/provider" + test -e "$bus_provider_path" || err "$LINENO" + bus_provider=$(cat ${bus_provider_path}) + + [[ "$bus_provider" == "$CXL_TEST_BUS" ]] || err "$LINENO" + bus="cxl" + nmem_provider_path="/sys/bus/nd/devices/${dev}/${bus}/provider" + nmem_provider=$(cat ${nmem_provider_path}) + + test_dimm_path=$(readlink -f /sys/bus/$bus/devices/${nmem_provider}) + test_dimm_path=$(dirname $(dirname ${test_dimm_path}))/security_lock + + test -e "$test_dimm_path" + + # now lock the dimm + echo 1 > "${test_dimm_path}" + sstate="$(get_security_state)" + if [ "$sstate" != "locked" ]; then + echo "Incorrect security state: $sstate expected: locked" + err "$LINENO" + fi +} + +get_frozen_state() +{ + $NDCTL list -i -b "$CXL_TEST_BUS" -d "$dev" | jq -r .[].dimms[0].security_frozen +} + +get_security_state() +{ + $NDCTL list -i -b "$CXL_TEST_BUS" -d "$dev" | jq -r .[].dimms[0].security +} + +setup_passphrase() +{ + $NDCTL setup-passphrase "$dev" -k user:"$masterkey" + sstate="$(get_security_state)" + if [ "$sstate" != "unlocked" ]; then + echo "Incorrect security state: $sstate expected: unlocked" + err "$LINENO" + fi +} + +remove_passphrase() +{ + $NDCTL remove-passphrase "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "disabled" ]; then + echo "Incorrect security state: $sstate expected: disabled" + err "$LINENO" + fi +} + +erase_security() +{ + $NDCTL sanitize-dimm -c "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "disabled" ]; then + echo "Incorrect security state: $sstate expected: disabled" + err "$LINENO" + fi +} + +update_security() +{ + $NDCTL update-passphrase "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "unlocked" ]; then + echo "Incorrect security state: $sstate expected: unlocked" + err "$LINENO" + fi +} + +freeze_security() +{ + $NDCTL freeze-security "$dev" +} + +test_1_security_setup_and_remove() +{ + setup_passphrase + remove_passphrase +} + +test_2_security_setup_and_update() +{ + setup_passphrase + update_security + remove_passphrase +} + +test_3_security_setup_and_erase() +{ + setup_passphrase + erase_security +} + +test_4_security_unlock() +{ + setup_passphrase + lock_dimm + $NDCTL enable-dimm "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "unlocked" ]; then + echo "Incorrect security state: $sstate expected: unlocked" + err "$LINENO" + fi + $NDCTL disable-region -b "$CXL_TEST_BUS" all + remove_passphrase +} + +# This should always be the last nvdimm security test. +# with security frozen, cxl_test must be removed and is no longer usable +test_5_security_freeze() +{ + setup_passphrase + freeze_security + sstate="$(get_security_state)" + fstate="$(get_frozen_state)" + if [ "$fstate" != "true" ]; then + echo "Incorrect security state: expected: frozen" + err "$LINENO" + fi + + # need to simulate a soft reboot here to clean up + lock_dimm + $NDCTL enable-dimm "$dev" + sstate="$(get_security_state)" + if [ "$sstate" != "unlocked" ]; then + echo "Incorrect security state: $sstate expected: unlocked" + err "$LINENO" + fi +} + +test_6_load_keys() +{ + if keyctl search @u encrypted nvdimm:"$id"; then + keyctl unlink "$(keyctl search @u encrypted nvdimm:"$id")" + fi + + if keyctl search @u user "$masterkey"; then + keyctl unlink "$(keyctl search @u user "$masterkey")" + fi + + $NDCTL load-keys + + if keyctl search @u user "$masterkey"; then + echo "master key loaded" + else + echo "master key failed to loaded" + err "$LINENO" + fi + + if keyctl search @u encrypted nvdimm:"$id"; then + echo "dimm key loaded" + else + echo "dimm key failed to load" + err "$LINENO" + fi +} + +check_min_kver "5.0" || do_skip "may lack security handling" +uid="$(keyctl show | grep -Eo "_uid.[0-9]+" | head -1 | cut -d. -f2-)" +if [ "$uid" -ne 0 ]; then + do_skip "run as root or with a sudo login shell for test to work" +fi + +modprobe cxl_test +setup +check_prereq "keyctl" +rc=1 +detect +test_cleanup +setup_keys +echo "Test 1, security setup and remove" +test_1_security_setup_and_remove +echo "Test 2, security setup, update, and remove" +test_2_security_setup_and_update +echo "Test 3, security setup and erase" +test_3_security_setup_and_erase +echo "Test 4, unlock dimm" +test_4_security_unlock + +# Freeze should always be the last nvdimm security test because it locks +# security state and require cxl_test module unload. However, this does +# not impact any key management testing via libkeyctl. +echo "Test 5, freeze security" +test_5_security_freeze + +# Load-keys is independent of actual nvdimm security and is part of key +# mangement testing. +echo "Test 6, test load-keys" +test_6_load_keys + +test_cleanup +post_cleanup +_cxl_cleanup +exit 0
Create security-cxl.sh based off of security.sh for nfit security testing. The test will test a cxl_test based security commands enabling through nvdimm. Signed-off-by: Dave Jiang <dave.jiang@intel.com> --- test/common | 7 + test/meson.build | 7 + test/security-cxl.sh | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 296 insertions(+) create mode 100755 test/security-cxl.sh