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)
  • .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
  • .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

Discussions