Commit 3e15cda3b3 for qemu.org
commit 3e15cda3b358a6e791737f95879a316c96af5338
Author: Joshua Daley <jdaley@linux.ibm.com>
Date: Thu Sep 3 17:58:05 2026 +0200
tests/functional/s390x/test_secure_ipl: Add virtio-blk-pci boot dev case
Split test_s390x_secure_ipl() into two subtests. Each tests with a
different boot device: virtio-blk-ccw or virtio-blk-pci. Use class-level
variables and a temporary shared workdir such that the time-consuming
setup is not run multiple times.
Signed-off-by: Joshua Daley <jdaley@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Link: https://lore.kernel.org/qemu-devel/20260903155805.1881366-4-jdaley@linux.ibm.com
Signed-off-by: Eric Farman <farman@linux.ibm.com>
diff --git a/tests/functional/s390x/test_secure_ipl.py b/tests/functional/s390x/test_secure_ipl.py
index 5af36b91d8..461d73c0d7 100755
--- a/tests/functional/s390x/test_secure_ipl.py
+++ b/tests/functional/s390x/test_secure_ipl.py
@@ -8,6 +8,9 @@
secure-boot enabled, and verifying cryptographic validation results.
"""
+import os
+import shutil
+import tempfile
from subprocess import check_call, DEVNULL
from qemu_test import QemuSystemTest, Asset, get_qemu_img
@@ -22,12 +25,25 @@ class S390xSecureIpl(QemuSystemTest):
'Fedora-Server-KVM-40-1.14.s390x.qcow2'),
'091c232a7301be14e19c76ce9a0c1cbd2be2c4157884a731e1fc4f89e7455a5f')
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.root_password = None
- self.qcow2_path = None
- self.cert_path = None
- self.prompt = None
+ _shared_workdir = None
+ _root_password = None
+ _qcow2_path = None
+ _cert_path = None
+ _prompt = None
+ _setup_done = None
+ _host_lacks_sipl_support = False
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls._shared_workdir = tempfile.mkdtemp(prefix='qemu_sipl_')
+
+ @classmethod
+ def tearDownClass(cls):
+ if cls._shared_workdir is not None:
+ shutil.rmtree(cls._shared_workdir, ignore_errors=True)
+ cls._shared_workdir = None
+ super().tearDownClass()
def _require_host_secure_ipl_support(self, vm):
"""
@@ -40,6 +56,7 @@ def _require_host_secure_ipl_support(self, vm):
missing = [f for f in ('sipl', 'sclaf', 'cstore')
if not props.get(f)]
if missing:
+ S390xSecureIpl._host_lacks_sipl_support = True
self.skipTest(
f"Host CPU does not support Secure IPL: "
f"missing feature(s): {', '.join(missing)}. "
@@ -62,7 +79,7 @@ def _sign_binaries(self, vm):
exec_command_and_wait_for_pattern(self,
'sudo dnf install kernel-devel-$(uname -r) -y',
'Complete!', vm=vm)
- wait_for_console_pattern(self, self.prompt, vm=vm)
+ wait_for_console_pattern(self, S390xSecureIpl._prompt, vm=vm)
exec_command_and_wait_for_pattern(self,
'ls /usr/src/kernels/$(uname -r)/scripts/',
'sign-file', vm=vm)
@@ -71,11 +88,11 @@ def _sign_binaries(self, vm):
exec_command(self, '/usr/src/kernels/$(uname -r)/scripts/sign-file '
'sha256 mykey.pem mycert.pem /lib/s390-tools/stage3.bin',
vm=vm)
- wait_for_console_pattern(self, self.prompt, vm=vm)
+ wait_for_console_pattern(self, S390xSecureIpl._prompt, vm=vm)
exec_command(self, '/usr/src/kernels/$(uname -r)/scripts/sign-file '
'sha256 mykey.pem mycert.pem /boot/vmlinuz-$(uname -r)',
vm=vm)
- wait_for_console_pattern(self, self.prompt, vm=vm)
+ wait_for_console_pattern(self, S390xSecureIpl._prompt, vm=vm)
def _run_zipl_secure(self, vm):
"""Run zipl to prepare for secure boot"""
@@ -91,10 +108,11 @@ def _extract_certificate(self, vm):
cert = "\n".join(out.decode("utf-8").splitlines()[1:])
self.log.info("%s", cert)
- self.cert_path = self.scratch_file("mycert.pem")
+ cert_path = os.path.join(S390xSecureIpl._shared_workdir, "mycert.pem")
- with open(self.cert_path, 'w', encoding="utf-8") as file_object:
+ with open(cert_path, 'w', encoding="utf-8") as file_object:
file_object.write(cert)
+ S390xSecureIpl._cert_path = cert_path
def setup_s390x_secure_ipl(self):
"""
@@ -109,39 +127,42 @@ def setup_s390x_secure_ipl(self):
temp_vm.set_machine('s390-ccw-virtio')
asset_path = self.ASSET_F40_QCOW2.fetch()
- self.qcow2_path = self.scratch_file('f40.qcow2')
+ qcow2_path = os.path.join(S390xSecureIpl._shared_workdir, 'f40.qcow2')
qemu_img = get_qemu_img(self)
check_call([qemu_img, 'create', '-f', 'qcow2', '-b', asset_path,
- '-F', 'qcow2', self.qcow2_path], stdout=DEVNULL, stderr=DEVNULL)
+ '-F', 'qcow2', qcow2_path], stdout=DEVNULL, stderr=DEVNULL)
+ S390xSecureIpl._qcow2_path = qcow2_path
temp_vm.set_console()
temp_vm.add_args('-nographic',
'-accel', 'kvm',
'-m', '1024',
'-drive',
- f'id=drive0,if=none,format=qcow2,file={self.qcow2_path}',
+ f'id=drive0,if=none,format=qcow2,file={qcow2_path}',
'-device', 'virtio-blk-ccw,drive=drive0,bootindex=1')
temp_vm.launch()
self._require_host_secure_ipl_support(temp_vm)
# Initial root account setup (Fedora first boot screen)
- self.root_password = 'fedora40password'
+ S390xSecureIpl._root_password = 'fedora40password'
wait_for_console_pattern(self, 'Please make a selection from the above',
vm=temp_vm)
exec_command_and_wait_for_pattern(self, '4', 'Password:', vm=temp_vm)
- exec_command_and_wait_for_pattern(self, self.root_password,
+ exec_command_and_wait_for_pattern(self, S390xSecureIpl._root_password,
'Password (confirm):', vm=temp_vm)
- exec_command_and_wait_for_pattern(self, self.root_password,
+ exec_command_and_wait_for_pattern(self, S390xSecureIpl._root_password,
'Please make a selection from the above',
vm=temp_vm)
# Login as root
- self.prompt = '[root@localhost ~]#'
- exec_command_and_wait_for_pattern(self, 'c', 'localhost login:', vm=temp_vm)
- exec_command_and_wait_for_pattern(self, 'root', 'Password:', vm=temp_vm)
- exec_command_and_wait_for_pattern(self, self.root_password, self.prompt,
+ S390xSecureIpl._prompt = '[root@localhost ~]#'
+ exec_command_and_wait_for_pattern(self, 'c', 'localhost login:',
vm=temp_vm)
+ exec_command_and_wait_for_pattern(self, 'root', 'Password:',
+ vm=temp_vm)
+ exec_command_and_wait_for_pattern(self, S390xSecureIpl._root_password,
+ S390xSecureIpl._prompt, vm=temp_vm)
self._create_certificate(temp_vm)
self._sign_binaries(temp_vm)
@@ -150,41 +171,71 @@ def setup_s390x_secure_ipl(self):
# Shutdown temp vm
temp_vm.shutdown()
+ S390xSecureIpl._setup_done = True
- @skipBigDataTest()
- def test_s390x_secure_ipl(self):
+ def verify_s390x_secure_ipl(self, boot_dev_bus: str):
"""
Verify secure boot validation during s390x guest boot.
Expects two "Verified component" messages and confirms
/sys/firmware/ipl/secure reports secure boot is active.
"""
- self.require_accelerator('kvm')
- self.setup_s390x_secure_ipl()
-
- self.set_machine('s390-ccw-virtio')
-
- self.vm.set_console()
- self.vm.add_args('-nographic',
- '-machine', 's390-ccw-virtio,secure-boot=on,'
- f'boot-certs.0.path={self.cert_path}',
- '-accel', 'kvm',
- '-m', '1024',
- '-drive',
- f'id=drive1,if=none,format=qcow2,file={self.qcow2_path}',
- '-device', 'virtio-blk-ccw,drive=drive1,bootindex=1')
- self.vm.launch()
+ if boot_dev_bus not in ['ccw', 'pci']:
+ raise ValueError(
+ f"boot_dev_bus must be 'ccw' or 'pci', got {boot_dev_bus}")
+
+ vm = self.get_vm(name=f'sipl_test_vblk_{boot_dev_bus}')
+ vm.set_machine('s390-ccw-virtio')
+
+ vm.set_console()
+ vm.add_args('-nographic',
+ '-machine', 's390-ccw-virtio,secure-boot=on,'
+ f'boot-certs.0.path={S390xSecureIpl._cert_path}',
+ '-accel', 'kvm',
+ '-m', '1024',
+ '-drive',
+ f'id=drive1,if=none,format=qcow2,'
+ f'file={S390xSecureIpl._qcow2_path}',
+ '-device',
+ f'virtio-blk-{boot_dev_bus},drive=drive1,bootindex=1')
+ vm.launch()
# Expect two verified components
verified_output = "Verified component"
- wait_for_console_pattern(self, verified_output)
- wait_for_console_pattern(self, verified_output)
+ wait_for_console_pattern(self, verified_output, vm=vm)
+ wait_for_console_pattern(self, verified_output, vm=vm)
# Login and verify the vm is booted using secure boot
- wait_for_console_pattern(self, 'localhost login:')
- exec_command_and_wait_for_pattern(self, 'root', 'Password:')
- exec_command_and_wait_for_pattern(self, self.root_password, self.prompt)
- exec_command_and_wait_for_pattern(self, 'cat /sys/firmware/ipl/secure', '1')
+ wait_for_console_pattern(self, 'localhost login:', vm=vm)
+ exec_command_and_wait_for_pattern(self, 'root', 'Password:', vm=vm)
+ exec_command_and_wait_for_pattern(
+ self, S390xSecureIpl._root_password, S390xSecureIpl._prompt, vm=vm)
+ exec_command_and_wait_for_pattern(
+ self, 'cat /sys/firmware/ipl/secure', '1', vm=vm)
+
+ vm.shutdown()
+
+ @skipBigDataTest()
+ def test_s390x_secure_ipl_ccw(self):
+ """Test secure IPL with a virtio-blk-ccw boot device."""
+ self.require_accelerator('kvm')
+ if S390xSecureIpl._host_lacks_sipl_support:
+ self.skipTest("Host CPU does not support Secure IPL. "
+ "Secure IPL requires a z16+ host.")
+ if not S390xSecureIpl._setup_done:
+ self.setup_s390x_secure_ipl()
+ self.verify_s390x_secure_ipl('ccw')
+
+ @skipBigDataTest()
+ def test_s390x_secure_ipl_pci(self):
+ """Test secure IPL with a virtio-blk-pci boot device."""
+ self.require_accelerator('kvm')
+ if S390xSecureIpl._host_lacks_sipl_support:
+ self.skipTest("Host CPU does not support Secure IPL. "
+ "Secure IPL requires a z16+ host.")
+ if not S390xSecureIpl._setup_done:
+ self.setup_s390x_secure_ipl()
+ self.verify_s390x_secure_ipl('pci')
if __name__ == '__main__':
QemuSystemTest.main()