#!/bin/sh # SPDX-License-Identifier: GPL-2.0 # # Loading a kernel image via the kexec_file_load syscall can verify either # the IMA signature stored in the security.ima xattr or the PE signature, # both signatures depending on the IMA policy, or none. # # To determine whether the kernel image is signed, this test depends # on pesign and getfattr. This test also requires the kernel to be # built with CONFIG_IKCONFIG enabled and either CONFIG_IKCONFIG_PROC # enabled or access to the extract-ikconfig script. TEST="KEXEC_FILE_LOAD" . ./kexec_common_lib.sh trap "{ rm -f $IKCONFIG ; }" EXIT # Some of the IMA builtin policies may require the kexec kernel image to # be signed, but these policy rules may be replaced with a custom # policy. Only CONFIG_IMA_APPRAISE_REQUIRE_KEXEC_SIGS persists after # loading a custom policy. Check if it is enabled, before reading the # IMA runtime sysfs policy file. # Return 1 for IMA signature required and 0 for not required. is_ima_sig_required() { local ret=0 kconfig_enabled "CONFIG_IMA_APPRAISE_REQUIRE_KEXEC_SIGS=y" \ "IMA kernel image signature required" if [ $? -eq 1 ]; then log_info "IMA signature required" return 1 fi # The architecture specific or a custom policy may require the # kexec kernel image be signed. Policy rules are walked # sequentially. As a result, a policy rule may be defined, but # might not necessarily be used. This test assumes if a policy # rule is specified, that is the intent. if [ $ima_read_policy -eq 1 ]; then check_ima_policy "appraise" "func=KEXEC_KERNEL_CHECK" \ "appraise_type=imasig" ret=$? [ $ret -eq 1 ] && log_info "IMA signature required"; fi return $ret } # The kexec_file_load_test() is complicated enough, require pesign. # Return 1 for PE signature found and 0 for not found. check_for_pesig() { which pesign > /dev/null 2>&1 || log_skip "pesign not found" pesign -i $KERNEL_IMAGE --show-signature | grep -q "No signatures" local ret=$? if [ $ret -eq 1 ]; then log_info "kexec kernel image PE signed" else log_info "kexec kernel image not PE signed" fi return $ret } # The kexec_file_load_test() is complicated enough, require getfattr. # Return 1 for IMA signature found and 0 for not found. check_for_imasig() { local ret=0 which getfattr > /dev/null 2>&1 if [ $? -eq 1 ]; then log_skip "getfattr not found" fi line=$(getfattr -n security.ima -e hex --absolute-names $KERNEL_IMAGE 2>&1) echo $line | grep -q "security.ima=0x03" if [ $? -eq 0 ]; then ret=1 log_info "kexec kernel image IMA signed" else log_info "kexec kernel image not IMA signed" fi return $ret } kexec_file_load_test() { local succeed_msg="kexec_file_load succeeded" local failed_msg="kexec_file_load failed" local key_msg="try enabling the CONFIG_INTEGRITY_PLATFORM_KEYRING" line=$(kexec --load --kexec-file-syscall $KERNEL_IMAGE 2>&1) if [ $? -eq 0 ]; then kexec --unload --kexec-file-syscall # In secureboot mode with an architecture specific # policy, make sure either an IMA or PE signature exists. if [ $secureboot -eq 1 ] && [ $arch_policy -eq 1 ] && \ [ $ima_signed -eq 0 ] && [ $pe_signed -eq 0 ]; then log_fail "$succeed_msg (missing sig)" fi if [ $kexec_sig_required -eq 1 -o $pe_sig_required -eq 1 ] \ && [ $pe_signed -eq 0 ]; then log_fail "$succeed_msg (missing PE sig)" fi if [ $ima_sig_required -eq 1 ] && [ $ima_signed -eq 0 ]; then log_fail "$succeed_msg (missing IMA sig)" fi if [ $pe_sig_required -eq 0 ] && [ $ima_appraise -eq 1 ] \ && [ $ima_sig_required -eq 0 ] && [ $ima_signed -eq 0 ] \ && [ $ima_read_policy -eq 0 ]; then log_fail "$succeed_msg (possibly missing IMA sig)" fi if [ $pe_sig_required -eq 0 ] && [ $ima_appraise -eq 0 ]; then log_info "No signature verification required" elif [ $pe_sig_required -eq 0 ] && [ $ima_appraise -eq 1 ] \ && [ $ima_sig_required -eq 0 ] && [ $ima_signed -eq 0 ] \ && [ $ima_read_policy -eq 1 ]; then log_info "No signature verification required" fi log_pass "$succeed_msg" fi # Check the reason for the kexec_file_load failure echo $line | grep -q "Required key not available" if [ $? -eq 0 ]; then if [ $platform_keyring -eq 0 ]; then log_pass "$failed_msg (-ENOKEY), $key_msg" else log_pass "$failed_msg (-ENOKEY)" fi fi if [ $kexec_sig_required -eq 1 -o $pe_sig_required -eq 1 ] \ && [ $pe_signed -eq 0 ]; then log_pass "$failed_msg (missing PE sig)" fi if [ $ima_sig_required -eq 1 ] && [ $ima_signed -eq 0 ]; then log_pass "$failed_msg (missing IMA sig)" fi if [ $pe_sig_required -eq 0 ] && [ $ima_appraise -eq 1 ] \ && [ $ima_sig_required -eq 0 ] && [ $ima_read_policy -eq 0 ] \ && [ $ima_signed -eq 0 ]; then log_pass "$failed_msg (possibly missing IMA sig)" fi log_pass "$failed_msg" return 0 } # kexec requires root privileges require_root_privileges # get the kernel config get_kconfig kconfig_enabled "CONFIG_KEXEC_FILE=y" "kexec_file_load is enabled" if [ $? -eq 0 ]; then log_skip "kexec_file_load is not enabled" fi # Determine which kernel config options are enabled kconfig_enabled "CONFIG_IMA_APPRAISE=y" "IMA enabled" ima_appraise=$? kconfig_enabled "CONFIG_IMA_ARCH_POLICY=y" \ "architecture specific policy enabled" arch_policy=$? kconfig_enabled "CONFIG_INTEGRITY_PLATFORM_KEYRING=y" \ "platform keyring enabled" platform_keyring=$? kconfig_enabled "CONFIG_IMA_READ_POLICY=y" "reading IMA policy permitted" ima_read_policy=$? kconfig_enabled "CONFIG_KEXEC_SIG_FORCE=y" \ "kexec signed kernel image required" kexec_sig_required=$? kconfig_enabled "CONFIG_KEXEC_BZIMAGE_VERIFY_SIG=y" \ "PE signed kernel image required" pe_sig_required=$? is_ima_sig_required ima_sig_required=$? get_secureboot_mode secureboot=$? # Are there pe and ima signatures check_for_pesig pe_signed=$? check_for_imasig ima_signed=$? # Test loading the kernel image via kexec_file_load syscall kexec_file_load_test