From 55335879dafa3c0be55892f7714a8e1269e1e6d7 Mon Sep 17 00:00:00 2001 From: Andrea Manzini Date: Wed, 23 Nov 2022 14:48:31 +0100 Subject: [PATCH] sign lkm with key enrolled into UEFI MOK --- tests/console/verify_efi_mok.pm | 134 ++++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 39 deletions(-) diff --git a/tests/console/verify_efi_mok.pm b/tests/console/verify_efi_mok.pm index 51d5d12a019b..ff973a034d86 100644 --- a/tests/console/verify_efi_mok.pm +++ b/tests/console/verify_efi_mok.pm @@ -162,14 +162,95 @@ sub get_esp_info { } sub verification { - my ($self, $msg, $expected, $setup) = @_; + my ($self, $msg, $expected, $before_reboot, $after_reboot) = @_; - $setup->() if ($setup && ref($setup) eq 'CODE'); + $before_reboot->() if ($before_reboot && ref($before_reboot) eq 'CODE'); $self->reboot_image($msg) if ($msg); check_efi_state $expected; + $after_reboot->() if ($after_reboot && ref($after_reboot) eq 'CODE'); check_mok; } +sub download_file { + my $datafile = shift; + assert_script_run "curl " . data_url("kernel/module/$datafile") . " -o $datafile"; +} + +sub download_kernel_source { + my @kv = split /\./, script_output "uname -r"; + my ($kv0, $kv1, $kv2) = ($kv[0], $kv[1], (split /-/, $kv[2])[0]); ## keep only numerical part of the last item + ## ex. https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.10.58.tar.gz + my $url = "https://mirrors.edge.kernel.org/pub/linux/kernel/v$kv0.x/linux-$kv0.$kv1.$kv2.tar.gz"; + ## high timeout bc can take longer to download and extract kernel source + assert_script_run "curl " . $url . "| tar xz --strip-components=1 -C /usr/src/linux", timeout => 600; +} + + +sub enable_verbosity { + my $self = shift; + assert_script_run 'mokutil --set-verbosity true'; + $self->verification('After shim-install', $self->{exp_data}, sub { + assert_script_run('rpm -q shim'); + assert_script_run('shim-install --config-file=' . GRUB_CFG); + assert_script_run('grub2-mkconfig -o ' . GRUB_CFG); + } + ); +} + + +sub sign_kernel_module { + my $self = shift; + $self->verification('Import key to MOK and sign kernel module', $self->{exp_data}, sub { + assert_script_run qq(openssl req -new -x509 -newkey rsa:2048 -sha256 -keyout key.asc -out ${\MOCK_CRT} -outform der -nodes -days 444 -addext "extendedKeyUsage=codeSigning" -subj "/CN=MOCK/"); + # compile and sign a simple kernel module + zypper_call "in kernel-devel flex bison libopenssl-devel"; + download_kernel_source; + assert_script_run "pushd /usr/src/linux && make olddefconfig && make scripts && popd"; + download_file 'Makefile'; + download_file 'hello.c'; + assert_script_run "make"; + # check module not signed, output must be empty + validate_script_output "modinfo hello.ko|grep signer:", sub { !$_ }, proceed_on_failure => 1; + assert_script_run "/usr/src/linux/scripts/sign-file sha256 key.asc ${\MOCK_CRT} hello.ko"; + # ensure module is signed now + validate_script_output "modinfo hello.ko|grep signer:", qr/MOCK/; + # try to insert module before enrolling the key, should give a fail message + validate_script_output "insmod hello.ko", qr/Key was rejected by service/, proceed_on_failure => 1; + # enroll module into UEFI + assert_script_run "mokutil --import ${\MOCK_CRT} --root-pw"; + assert_script_run 'mokutil --list-new'; + set_var('_EXPECT_EFI_MOK_MANAGER', 1); + }, + sub { + # This code is executed after reboot + # try to insert module once key is enrolled + assert_script_run "insmod hello.ko"; + # dmesg output should contain 'Hello world.' + validate_script_output "dmesg | tail -3", qr/Hello world./s; + } + ); +} +sub disable_secureboot { + my $self = shift; + $self->verification('After grub2-install', $self->{exp_data}, sub { + assert_script_run('sed -ie s/SECURE_BOOT=.*/SECURE_BOOT=no/ ' . SYSCONFIG_BOOTLADER); + assert_script_run "grub2-install --efi-directory=$self->{esp_details}->{mount} --target=x86_64-efi $self->{esp_details}->{drive}"; + assert_script_run('grub2-mkconfig -o ' . GRUB_CFG); + } + ); +} + +sub restore_prev_config { + my $self = shift; + ## Keep previous configuration + $self->verification('After pbl reinit', $self->{exp_data}, sub { + my $state = !get_var('DISABLE_SECUREBOOT', 0) ? 'yes' : 'no'; + assert_script_run(q|grep -E "SECURE_BOOT=['\"]?| . $state . q|[\"']?" | . SYSCONFIG_BOOTLADER); + assert_script_run 'update-bootloader --reinit'; + } + ); +} + sub run { my $self = shift; select_serial_terminal; @@ -180,66 +261,41 @@ sub run { $pkgs .= ' pesign' unless get_var('DISABLE_SECUREBOOT', 0); zypper_call "in $pkgs"; - my $esp_details = get_esp_info; + $self->{esp_details} = get_esp_info; # run fs check on ESP - record_info "ESP", "Partition [$esp_details->{partition}], \nFilesystem [$esp_details->{fs}],\nMountPoint [$esp_details->{mount}]"; - assert_script_run "umount $esp_details->{mount}"; - assert_script_run "fsck.vfat -vV $esp_details->{partition}"; - assert_script_run "mount $esp_details->{mount}"; + record_info "ESP", "Partition [$self->{esp_details}->{partition}], \nFilesystem [$self->{esp_details}->{fs}],\nMountPoint [$self->{esp_details}->{mount}]"; + assert_script_run "umount $self->{esp_details}->{mount}"; + assert_script_run "fsck.vfat -vV $self->{esp_details}->{partition}"; + assert_script_run "mount $self->{esp_details}->{mount}"; # SUT can boot from removable (firstboot of HDD, ISO, USB bootable medium) or boot entry (non-removable) # JeOS always boots firstly from removable, but the boot record will be changed to non-removable by updates # Therefore the expected boot for JeOS under development and maintenance updates test slow might be different # Installed SUT by YaST2 boots from non-removable by default - my $exp_data = get_expected_efi_settings; + $self->{exp_data} = get_expected_efi_settings; my $booted_from_removable = is_jeos; if ($booted_from_removable && is_updates_tests) { # Updates got installed, so it might no longer be removable - $booted_from_removable = efibootmgr_current_boot()->{label} ne $exp_data->{label}; + $booted_from_removable = efibootmgr_current_boot()->{label} ne $self->{exp_data}->{label}; } ## default efi boot, no restart, but set gfxmode before reboot - $self->verification(undef, $booted_from_removable ? undef : $exp_data, sub { + $self->verification(undef, $booted_from_removable ? undef : $self->{exp_data}, sub { set_grub_gfxmode; assert_script_run('grub2-script-check --verbose ' . GRUB_CFG); } ); ## Test efi without secure boot if (get_var('DISABLE_SECUREBOOT')) { - $self->verification('After grub2-install', $exp_data, sub { - assert_script_run('sed -ie s/SECURE_BOOT=.*/SECURE_BOOT=no/ ' . SYSCONFIG_BOOTLADER); - assert_script_run "grub2-install --efi-directory=$esp_details->{mount} --target=x86_64-efi $esp_details->{drive}"; - assert_script_run('grub2-mkconfig -o ' . GRUB_CFG); - } - ); + $self->disable_secureboot; } else { ## Test efi with secure boot # enable verbosity in shim - assert_script_run 'mokutil --set-verbosity true'; - $self->verification('After shim-install', $exp_data, sub { - assert_script_run('rpm -q shim'); - assert_script_run('shim-install --config-file=' . GRUB_CFG); - assert_script_run('grub2-mkconfig -o ' . GRUB_CFG); - } - ); - $self->verification('Import mock key to MOK', $exp_data, sub { - assert_script_run 'openssl req -new -x509 -newkey rsa:2048 -sha256 -keyout key.asc -out cert.pem -nodes -days 666 -subj "/CN=MOCK/"'; - assert_script_run "openssl x509 -in cert.pem -outform der -out ${\MOCK_CRT}"; - assert_script_run "mokutil --import ${\MOCK_CRT} --root-pw"; - assert_script_run 'mokutil --list-new'; - set_var('_EXPECT_EFI_MOK_MANAGER', 1); - } - ) if get_var('CHECK_MOK_IMPORT'); + $self->enable_verbosity; + $self->sign_kernel_module if get_var('CHECK_MOK_IMPORT'); } - - ## Keep previous configuration - $self->verification('After pbl reinit', $exp_data, sub { - my $state = !get_var('DISABLE_SECUREBOOT', 0) ? 'yes' : 'no'; - assert_script_run(q|grep -E "SECURE_BOOT=['\"]?| . $state . q|[\"']?" | . SYSCONFIG_BOOTLADER); - assert_script_run 'update-bootloader --reinit'; - } - ); + $self->restore_prev_config; set_var('_EXPECT_EFI_MOK_MANAGER', 0); # Print errors