Kernel Module Signing
Work in Progress
UEFI certificate stores
- MOK - Machine Owner Keys
- db - UEFI key database
Keyrings
- .builtin_trusted_keys
- .secondary_trusted_keys
- .platform
- .ima
- .blacklist
Definitions
machine owners -> end users
Impute
Impute -> to attribute or credit to
Impute value to something. Impute value to academics
Impute value to keys?
Imputed trust vs Transitive trust
Source of trust in the kernel
3 Built in sources of trust:
- Built-in trust
- Inherent to the system
- Imputed trust
- Where did it come from?
- Transitive trust
- Who is vouching for it?
Kernel keyrings
-
.builtin_trusted keys
- built-in trust
- Keys fixed at build time
- Stored in the kernel image
- Added to reserved memory in the kernel, then the kernel is signed
-
.platform and .machine
- Imputed trust
- User-provided machine owner keys (MOK) impute trust to keys in the machine keyring
-
.secondary_trusted_keys
- Transitive
- Any key signed by a key that's already trusted is automatically trusted
- If a CAs key is trusted, then all the keys signed by that CA are trusted
- CAs are here imputed trust
Usage
-
.builtin_trusted
- Built-in trust by being compiled or inserted into the kernel
- Used to verify:
- keys
- kernel modules
- kexec'd kernel images
-
.secondary_trusted_keys
- Transitive trust from the root user(?)
- Used to verify:
- keys
- kernel modules
- kexec'd kernel images
-
.ima
- Transitive trust:
- Root user
- Signed by .built-intrusted_keys or .secondary_trusted_keys
- Used to verify:
- kexecd kernel images
- kernel modules
- files
- Disabled when .machine is configured (see below)
- Transitive trust:
-
.blacklist
- Built-in trust
- Imputed Trust:
- UEFI secure boot (dbx)
- MOK dbx
- Root user (? patch series)
- Blocks:
- File digests
- Certificate TBS(?)
-
.platform
- Imputed trust:
- UEFI secure boot firmware,
- Machine Owner Keys
- Used to verify:
- kexecd kernel images
- Imputed trust:
-
.machine
- With v5.18
- Imputed Trust:
- Management system
- Machine Owner Keys (MOK)
- (Conditionally on kernel config and UEFI variables)
- Linked to secondary_trusted_keys
Kernel
Kernel configs
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING
CONFIG_INTEGRITY_MACHINE_KEYRING
CONFIG_IMA_ARCH_POLICY
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING
Introduced: dm verity: Add support for signature verification with 2nd keyring
db-verity signatures can be verified against the secondary trusted keyring.
CONFIG_INTEGRITY_MACHINE_KEYRING
Introduced: integrity: Introduce a Linux keyring called machine
Load keys from MOK
and db
into the machine
keyring. Optionally able to
trust them in a later patch.
CONFIG_IMA_ARCH_POLICY
Introduced: x86/ima: require signed kernel modules
Enforce kernel module signatures when secure boot is enabled. This kernel overrides the lockdown LSM. (See another section)
Loading Secure Boot keys into something trusted
The goal is to have some use supplied keys we can use for validating kernel
modules. mokutils
can load a signature list into MokListRT
, and if
MokTrustedRT
is set with mokutil --trusted
then we append any keys from the
MOK List into the machine keyring.
The issue is that the shim
binary throws all Mok*
variables into an EFI
configuration table. See import_mok_state.
First the kernel attempts to read the MokListRT
variable from the EFI
configuration table. If this list is not found, it will attempt to read it from
efivarfs
. This is fine as we will end up reading this list into the platform
keyring by default. But the platform keyring is not the keyring we will be using
to validate kernel modules.
If we want the kernel to read the certificate list into the machine keyring, we
will query the MokListTrustedRT
from the EFI configuration table only. This
means we are bound to the shim loading the variable during early boot, and can't
trust this set of certificates without utilizing the shim.
Note: There are fallbacks to diglim and other LSM hooks, but not investigated stuff there yet.
Relevant code snippets
static int __init load_moklist_certs(void)
{
...
mokvar_entry = efi_mokvar_entry_find("MokListRT");
if (mokvar_entry) {
rc = parse_efi_signature_list("UEFI:MokListRT (MOKvar table)",
mokvar_entry->data,
mokvar_entry->data_size,
get_handler_for_mok);
...
}
mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
if (mok) {
rc = parse_efi_signature_list("UEFI:MokListRT",
mok, moksize, get_handler_for_mok);
....
}
}
__init efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type)
{
if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) {
if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) && trust_moklist())
return add_to_machine_keyring;
else
return add_to_platform_keyring;
}
return NULL;
}
security/integrity/platform_certs/load_uefi.c:load_moklist_certs
security/integrity/platform_certs/keyring_handler.c:get_handler_for_mok
security/integrity/platform_certs/machine_keyring.c:trust_moklist
security/integrity/platform_certs/machine_keyring.c:uefi_check_trust_mok_keys
Kernel module validation
is_module_sig_enforced (enforced by ARCH_POLICY)
if false
call LSM hook into lockdown: security_locked_down(LOCKDOWN_MODULE_SIGNATURE)
-
kernel/module/signing.c:module_sig_check
-
lockdown_mode=integrity -> deny module loading
-
Is there others?
Lockdown implementation
// TODO