Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

testcases/OpTestKexec.py: add new test cases with -s and -c options #816

Merged
merged 2 commits into from
Apr 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 122 additions & 8 deletions testcases/OpTestKexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
kexec, except for the kexec in loop test.
'''

import os
import unittest
import OpTestLogger

Expand All @@ -58,6 +59,7 @@

log = OpTestLogger.optest_logger_glob.get_logger(__name__)


class OpTestKexec(unittest.TestCase):
"""kexec test class"""

Expand All @@ -75,10 +77,8 @@ def populate_kernel_initrd_image(self):
and initrd_image instance variable
"""

distro = self.op_test_util.distro_name()

# Skip the test for unsupported distro
if distro == "unknown":
if self.distro == "unknown":
self.skipTest("Unsupported distro")

# Find kexec kernel version. If user provided the kernel source
Expand All @@ -99,13 +99,13 @@ def populate_kernel_initrd_image(self):
# Set kernel_image and initrd_image instance variable with
# corresponding filenames path
k_ver = str(k_ver)
if distro == "rhel":
if self.distro == "rhel":
self.kernel_image = "vmlinuz-" + k_ver
self.initrd_image = "initramfs-" + k_ver + ".img"
elif distro == "sles":
elif self.distro == "sles":
self.kernel_image = "vmlinux-" + k_ver
self.initrd_image = "initrd-" + k_ver
elif distro == "ubuntu":
elif self.distro == "ubuntu":
self.kernel_image = "vmlinux-" + k_ver
self.initrd_image = "initrd.img-" + k_ver

Expand All @@ -115,7 +115,7 @@ def setUp(self):
self.cv_SYSTEM = conf.system()
self.c = self.cv_SYSTEM.console
self.cv_HOST = conf.host()
self.distro = None
self.distro = self.op_test_util.distro_name()
self.num_of_iterations = conf.args.num_of_iterations
self.kernel_image = conf.args.kernel_image
self.initrd_image = conf.args.initrd_image
Expand All @@ -132,7 +132,7 @@ def setUp(self):
self.os_level_secureboot = sb_utilities.check_os_level_secureboot_state()

def get_kexec_load_cmd(self, load_opt=True, copy_cmdline=True,
file_load=False, add_arg=None):
syscall_load=False, file_load=False, add_arg=None):
"""
Generates a kexec command for loading a kernel image with various
optional arguments.
Expand All @@ -159,6 +159,9 @@ def get_kexec_load_cmd(self, load_opt=True, copy_cmdline=True,
if file_load:
kexec_cmd = kexec_cmd + " -s"

if syscall_load:
kexec_cmd = "%s -c" % kexec_cmd

if copy_cmdline:
kexec_cmd = kexec_cmd + " --append=\"`cat /proc/cmdline`\""

Expand Down Expand Up @@ -350,10 +353,59 @@ def test_load_and_exec(self):
ret = self.load_kexec_kernel(kexec_load_cmd)
self.assertTrue(ret, "Kexec load failed")

kexec_exec_cmd = self.get_kexec_exec_command(exec_opt=True)
ret = self.execute_kexec_cmd(kexec_exec_cmd, raw_pty_console=True)
self.assertTrue(ret, "kexec exec failed: %s " % kexec_exec_cmd)

def test_file_load_and_exec(self):
"""
Test kexec functionality by loading with kexec-file-syscall and exec
into kexec kernel.

First load the kexec kernel using -s, -l and --append(command line
arguments of currently running kenrel form /proc/cmdline) option.
Then exec into kexec kernel.

Test passes if both the kexec load and the execution into the
kexec kernel go fine; otherwise, it fails."
"""

kexec_load_cmd = self.get_kexec_load_cmd(file_load=True)
ret = self.load_kexec_kernel(kexec_load_cmd)
self.assertTrue(ret, "Kexec load failed")

kexec_exec_cmd = self.get_kexec_exec_command(exec_opt=True)
ret = self.execute_kexec_cmd(kexec_exec_cmd, raw_pty_console=True)
self.assertTrue(ret, "kexec exec failed: " + kexec_exec_cmd)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use %s to concatenate string

Copy link
Collaborator

@PraveenPenguin PraveenPenguin Apr 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address this style issue and where ever it required


def test_syscall_load_and_exec(self):
"""
Test kexec functionality by loading with kexec-syscall and exec
into kexec kernel.

First load the kexec kernel using -c, -l and --append(command line
arguments of currently running kenrel form /proc/cmdline) option.
Then exec into kexec kernel.

Test passes if both the kexec load and the execution into the
kexec kernel go fine; otherwise, it fails."
"""

kexec_load_cmd = self.get_kexec_load_cmd(syscall_load=True)
ret = self.load_kexec_kernel(kexec_load_cmd)
if self.os_level_secureboot:
self.assertFalse(ret, "Kexec load pass, with -c option")
else:
self.assertTrue(ret, "Kexec load failed, with -c option")

kexec_exec_cmd = self.get_kexec_exec_command(exec_opt=True)
if self.os_level_secureboot:
ret = self.execute_kexec_cmd(kexec_exec_cmd)
self.assertFalse(ret, "Kexec exec pass, with -c option")
else:
ret = self.execute_kexec_cmd(kexec_exec_cmd, raw_pty_console=True)
self.assertTrue(ret, "Kexec exec failed, with -c option")

def test_kexec_force(self):
"""
Test kexec load and exec into kexec kernel using --force (-f) option.
Expand Down Expand Up @@ -397,6 +449,65 @@ def test_kexec_in_loop(self):
self.assertTrue(ret, "kexec failed, at iteration cnt: " + str(i))
log.info("Completed kexec iteration cnt %s." % str(i))

def test_kexec_unsigned_kernel(self):
"""
Tests the unsigned kernel when secure boot is enabled.

From the signed kernel image, create unsigned kernel image. The same
used for 'kexec' when secure boot is enabled. Expected failure while
loading kexec.
"""
if self.os_level_secureboot:
if self.op_test_util.check_kernel_signature():
if self.distro in ["unknown", "ubuntu"]:
self.skipTest("Unsupported Linux distribution.")
install_cmd = "wget"
wget_bool = True
res = self.cv_HOST.host_run_command('which %s' % install_cmd,
timeout=120)
if install_cmd not in res[0]:
wget_bool = False
if not wget_bool:
if self.distro == "rhel":
install_cmd = "yum install -y %s" % install_cmd
elif self.distro == "sles":
install_cmd = "zypper install -y %s" % install_cmd
self.cv_HOST.host_run_command(install_cmd, timeout=120)
try:
url = "https://raw.githubusercontent.com/torvalds/linux/master/scripts/extract-module-sig.pl"
self.cv_HOST.host_run_command("wget %s -P /tmp/" % url, timeout=120)
except CommandFailed:
self.skipTest("Can't get extract-module-sig.pl file.")
module_sig_file = '/tmp/extract-module-sig.pl'
self.cv_HOST.host_run_command("chmod u+x %s" % module_sig_file)
self.kernel_image = "/boot/%s" % self.kernel_image
cmd = "%s -0 %s > %s.unsigned" % \
(module_sig_file, self.kernel_image, self.kernel_image)
out = self.cv_HOST.host_run_command(cmd)
if '0' not in out[3]:
self.skipTest("Can not create unsigned binary. Using- %s"
% cmd)
cmd = "kexec -s -l %s.unsigned" % self.kernel_image
ret = self.execute_kexec_cmd(cmd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute_kexec_cmd () will attempt to perform kexec reboot correct? If so is the test here to actually attempt to perform kexec with unsigned image or just an attempt to load an unsigned image. If its the later then can't we use load_kexec_kernel() instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function creates the unsigned kernel image from the existing signed kernel image and tries to load when guest secure boot is enabled.

if ret:
self.fail("kexec loaded unsigned kernel when secure boot"
" is enabled.")
else:
log.info("kexec loading with unsigned kernel failed. "
"Which is expected.")
else:
self.skipTest("secure boot is disabled.")

def tearDown(self):
unsigned_kernel = "%s.unsigned" % self.kernel_image
if 'boot' not in unsigned_kernel:
unsigned_kernel = "/boot/%s" % unsigned_kernel
if os.path.exists(unsigned_kernel):
os.remove(unsigned_kernel)
sign_file = "/tmp/extract-module-sig.pl"
if os.path.exists(sign_file):
os.remove(sign_file)


def kexec_suite():
"""kexec test suite"""
Expand All @@ -406,5 +517,8 @@ def kexec_suite():
suite.addTest(OpTestKexec('test_load_and_exec'))
suite.addTest(OpTestKexec('test_kexec_force'))
suite.addTest(OpTestKexec('test_kexec_single_step'))
suite.addTest(OpTestKexec('test_file_load_and_exec'))
suite.addTest(OpTestKexec('test_syscall_load_and_exec'))
suite.addTest(OpTestKexec('test_kexec_in_loop'))
suite.addTest(OpTestKexec('test_kexec_unsigned_kernel'))
return suite