Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorri...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 2 Jan 2019 17:43:14 +0000 (09:43 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 2 Jan 2019 17:43:14 +0000 (09:43 -0800)
Pull integrity updates from James Morris:
 "In Linux 4.19, a new LSM hook named security_kernel_load_data was
  upstreamed, allowing LSMs and IMA to prevent the kexec_load syscall.
  Different signature verification methods exist for verifying the
  kexec'ed kernel image. This adds additional support in IMA to prevent
  loading unsigned kernel images via the kexec_load syscall,
  independently of the IMA policy rules, based on the runtime "secure
  boot" flag. An initial IMA kselftest is included.

  In addition, this pull request defines a new, separate keyring named
  ".platform" for storing the preboot/firmware keys needed for verifying
  the kexec'ed kernel image's signature and includes the associated IMA
  kexec usage of the ".platform" keyring.

  (David Howell's and Josh Boyer's patches for reading the
  preboot/firmware keys, which were previously posted for a different
  use case scenario, are included here)"

* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  integrity: Remove references to module keyring
  ima: Use inode_is_open_for_write
  ima: Support platform keyring for kernel appraisal
  efi: Allow the "db" UEFI variable to be suppressed
  efi: Import certificates from UEFI Secure Boot
  efi: Add an EFI signature blob parser
  efi: Add EFI signature data types
  integrity: Load certs to the platform keyring
  integrity: Define a trusted platform keyring
  selftests/ima: kexec_load syscall test
  ima: don't measure/appraise files on efivarfs
  x86/ima: retry detecting secure boot mode
  docs: Extend trusted keys documentation for TPM 2.0
  x86/ima: define arch_get_ima_policy() for x86
  ima: add support for arch specific policies
  ima: refactor ima_init_policy()
  ima: prevent kexec_load syscall based on runtime secureboot flag
  x86/ima: define arch_ima_get_secureboot
  integrity: support new struct public_key_signature encoding field

20 files changed:
Documentation/security/keys/trusted-encrypted.rst
arch/x86/kernel/Makefile
arch/x86/kernel/ima_arch.c [new file with mode: 0644]
include/linux/efi.h
include/linux/ima.h
security/integrity/Kconfig
security/integrity/Makefile
security/integrity/digsig.c
security/integrity/ima/Kconfig
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/integrity.h
security/integrity/platform_certs/efi_parser.c [new file with mode: 0644]
security/integrity/platform_certs/load_uefi.c [new file with mode: 0644]
security/integrity/platform_certs/platform_keyring.c [new file with mode: 0644]
tools/testing/selftests/Makefile
tools/testing/selftests/ima/Makefile [new file with mode: 0644]
tools/testing/selftests/ima/config [new file with mode: 0644]
tools/testing/selftests/ima/test_kexec_load.sh [new file with mode: 0755]

index e8a1c35cd277a7a7276366a4c4dc7b36961a70ed..7b35fcb589335eb1cc62ee20a00fca4092a20ea2 100644 (file)
@@ -18,10 +18,33 @@ integrity verifications match.  A loaded Trusted Key can be updated with new
 when the kernel and initramfs are updated.  The same key can have many saved
 blobs under different PCR values, so multiple boots are easily supported.
 
+TPM 1.2
+-------
+
 By default, trusted keys are sealed under the SRK, which has the default
 authorization value (20 zeros).  This can be set at takeownership time with the
 trouser's utility: "tpm_takeownership -u -z".
 
+TPM 2.0
+-------
+
+The user must first create a storage key and make it persistent, so the key is
+available after reboot. This can be done using the following commands.
+
+With the IBM TSS 2 stack::
+
+  #> tsscreateprimary -hi o -st
+  Handle 80000000
+  #> tssevictcontrol -hi o -ho 80000000 -hp 81000001
+
+Or with the Intel TSS 2 stack::
+
+  #> tpm2_createprimary --hierarchy o -G rsa2048 -o key.ctxt
+  [...]
+  handle: 0x800000FF
+  #> tpm2_evictcontrol -c key.ctxt -p 0x81000001
+  persistentHandle: 0x81000001
+
 Usage::
 
     keyctl add trusted name "new keylen [options]" ring
@@ -30,7 +53,9 @@ Usage::
     keyctl print keyid
 
     options:
-       keyhandle=    ascii hex value of sealing key default 0x40000000 (SRK)
+       keyhandle=    ascii hex value of sealing key
+                       TPM 1.2: default 0x40000000 (SRK)
+                       TPM 2.0: no default; must be passed every time
        keyauth=             ascii hex auth for sealing key default 0x00...i
                      (40 ascii zeros)
        blobauth=     ascii hex auth for sealed data default 0x00...
@@ -84,6 +109,10 @@ Examples of trusted and encrypted key usage:
 
 Create and save a trusted key named "kmk" of length 32 bytes::
 
+Note: When using a TPM 2.0 with a persistent key with handle 0x81000001,
+append 'keyhandle=0x81000001' to statements between quotes, such as
+"new 32 keyhandle=0x81000001".
+
     $ keyctl add trusted kmk "new 32" @u
     440502848
 
index 8824d01c0c352d6dbd2c12e228bd0de9ca335166..eb51b0e1189c13ed921846c0abfc46480a2425b1 100644 (file)
@@ -150,3 +150,7 @@ ifeq ($(CONFIG_X86_64),y)
        obj-$(CONFIG_MMCONF_FAM10H)     += mmconf-fam10h_64.o
        obj-y                           += vsmp_64.o
 endif
+
+ifdef CONFIG_EFI
+obj-$(CONFIG_IMA)                      += ima_arch.o
+endif
diff --git a/arch/x86/kernel/ima_arch.c b/arch/x86/kernel/ima_arch.c
new file mode 100644 (file)
index 0000000..e47cd93
--- /dev/null
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 IBM Corporation
+ */
+#include <linux/efi.h>
+#include <linux/ima.h>
+
+extern struct boot_params boot_params;
+
+static enum efi_secureboot_mode get_sb_mode(void)
+{
+       efi_char16_t efi_SecureBoot_name[] = L"SecureBoot";
+       efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
+       efi_status_t status;
+       unsigned long size;
+       u8 secboot;
+
+       size = sizeof(secboot);
+
+       /* Get variable contents into buffer */
+       status = efi.get_variable(efi_SecureBoot_name, &efi_variable_guid,
+                                 NULL, &size, &secboot);
+       if (status == EFI_NOT_FOUND) {
+               pr_info("ima: secureboot mode disabled\n");
+               return efi_secureboot_mode_disabled;
+       }
+
+       if (status != EFI_SUCCESS) {
+               pr_info("ima: secureboot mode unknown\n");
+               return efi_secureboot_mode_unknown;
+       }
+
+       if (secboot == 0) {
+               pr_info("ima: secureboot mode disabled\n");
+               return efi_secureboot_mode_disabled;
+       }
+
+       pr_info("ima: secureboot mode enabled\n");
+       return efi_secureboot_mode_enabled;
+}
+
+bool arch_ima_get_secureboot(void)
+{
+       static enum efi_secureboot_mode sb_mode;
+       static bool initialized;
+
+       if (!initialized && efi_enabled(EFI_BOOT)) {
+               sb_mode = boot_params.secure_boot;
+
+               if (sb_mode == efi_secureboot_mode_unset)
+                       sb_mode = get_sb_mode();
+               initialized = true;
+       }
+
+       if (sb_mode == efi_secureboot_mode_enabled)
+               return true;
+       else
+               return false;
+}
+
+/* secureboot arch rules */
+static const char * const sb_arch_rules[] = {
+#if !IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG)
+       "appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
+#endif /* CONFIG_KEXEC_VERIFY_SIG */
+       "measure func=KEXEC_KERNEL_CHECK",
+       NULL
+};
+
+const char * const *arch_get_ima_policy(void)
+{
+       if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot())
+               return sb_arch_rules;
+       return NULL;
+}
index becd5d76a207407373a360224435599119996c45..45ff763fba76ddad0e0141fca2a5efb2c912b8fa 100644 (file)
@@ -663,6 +663,10 @@ void efi_native_runtime_setup(void);
 #define EFI_IMAGE_SECURITY_DATABASE_GUID       EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596,  0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
 #define EFI_SHIM_LOCK_GUID                     EFI_GUID(0x605dab50, 0xe046, 0x4300,  0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
 
+#define EFI_CERT_SHA256_GUID                   EFI_GUID(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28)
+#define EFI_CERT_X509_GUID                     EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
+#define EFI_CERT_X509_SHA256_GUID              EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed)
+
 /*
  * This GUID is used to pass to the kernel proper the struct screen_info
  * structure that was populated by the stub based on the GOP protocol instance
@@ -934,6 +938,27 @@ typedef struct {
        efi_memory_desc_t entry[0];
 } efi_memory_attributes_table_t;
 
+typedef struct {
+       efi_guid_t signature_owner;
+       u8 signature_data[];
+} efi_signature_data_t;
+
+typedef struct {
+       efi_guid_t signature_type;
+       u32 signature_list_size;
+       u32 signature_header_size;
+       u32 signature_size;
+       u8 signature_header[];
+       /* efi_signature_data_t signatures[][] */
+} efi_signature_list_t;
+
+typedef u8 efi_sha256_hash_t[32];
+
+typedef struct {
+       efi_sha256_hash_t to_be_signed_hash;
+       efi_time_t time_of_revocation;
+} efi_cert_x509_sha256_t;
+
 /*
  * All runtime access to EFI goes through this structure:
  */
@@ -1113,6 +1138,15 @@ extern int efi_memattr_apply_permissions(struct mm_struct *mm,
 char * __init efi_md_typeattr_format(char *buf, size_t size,
                                     const efi_memory_desc_t *md);
 
+
+typedef void (*efi_element_handler_t)(const char *source,
+                                     const void *element_data,
+                                     size_t element_size);
+extern int __init parse_efi_signature_list(
+       const char *source,
+       const void *data, size_t size,
+       efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *));
+
 /**
  * efi_range_is_wc - check the WC bit on an address range
  * @start: starting kvirt address
index 97914a2833d10ad566edf474918e2afed39f73fc..b5e16b8c50b7c1681983ad95ee5f583c2d28d4c5 100644 (file)
@@ -30,6 +30,21 @@ extern void ima_post_path_mknod(struct dentry *dentry);
 extern void ima_add_kexec_buffer(struct kimage *image);
 #endif
 
+#if defined(CONFIG_X86) && defined(CONFIG_EFI)
+extern bool arch_ima_get_secureboot(void);
+extern const char * const *arch_get_ima_policy(void);
+#else
+static inline bool arch_ima_get_secureboot(void)
+{
+       return false;
+}
+
+static inline const char * const *arch_get_ima_policy(void)
+{
+       return NULL;
+}
+#endif
+
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
 {
index 877af1f2d9045814f02c7691f2226734438e3449..2ea4ec9991d516c8d9850e0dc091afd648143af9 100644 (file)
@@ -51,6 +51,17 @@ config INTEGRITY_TRUSTED_KEYRING
           .evm keyrings be signed by a key on the system trusted
           keyring.
 
+config INTEGRITY_PLATFORM_KEYRING
+        bool "Provide keyring for platform/firmware trusted keys"
+        depends on INTEGRITY_ASYMMETRIC_KEYS
+        depends on SYSTEM_BLACKLIST_KEYRING
+        depends on EFI
+        help
+         Provide a separate, distinct keyring for platform trusted keys, which
+         the kernel automatically populates during initialization from values
+         provided by the platform for verifying the kexec'ed kerned image
+         and, possibly, the initramfs signature.
+
 config INTEGRITY_AUDIT
        bool "Enables integrity auditing support "
        depends on AUDIT
index 04d6e462b079f0ccb5ba671fd0131679b2f5e106..86df9aba8c0fe88ac1f1ef462a1a2495151b0951 100644 (file)
@@ -9,6 +9,11 @@ integrity-y := iint.o
 integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
 integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
 integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
+integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o \
+                                                 platform_certs/efi_parser.o \
+                                                 platform_certs/load_uefi.o
+obj-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/load_uefi.o
+$(obj)/load_uefi.o: KBUILD_CFLAGS += -fshort-wchar
 
 subdir-$(CONFIG_IMA)                   += ima
 obj-$(CONFIG_IMA)                      += ima/
index 5eacba858e4be266f9828b6c17dce46691025fd0..f45d6edecf99a187c0e251f4a135b084945b2cfc 100644 (file)
@@ -34,7 +34,7 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
        ".evm",
        ".ima",
 #endif
-       "_module",
+       ".platform",
 };
 
 #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
@@ -73,12 +73,38 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
        return -EOPNOTSUPP;
 }
 
-int __init integrity_init_keyring(const unsigned int id)
+static int __integrity_init_keyring(const unsigned int id, key_perm_t perm,
+                                   struct key_restriction *restriction)
 {
        const struct cred *cred = current_cred();
-       struct key_restriction *restriction;
        int err = 0;
 
+       keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
+                                   KGIDT_INIT(0), cred, perm,
+                                   KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL);
+       if (IS_ERR(keyring[id])) {
+               err = PTR_ERR(keyring[id]);
+               pr_info("Can't allocate %s keyring (%d)\n",
+                       keyring_name[id], err);
+               keyring[id] = NULL;
+       }
+
+       return err;
+}
+
+int __init integrity_init_keyring(const unsigned int id)
+{
+       struct key_restriction *restriction;
+       key_perm_t perm;
+
+       perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW
+               | KEY_USR_READ | KEY_USR_SEARCH;
+
+       if (id == INTEGRITY_KEYRING_PLATFORM) {
+               restriction = NULL;
+               goto out;
+       }
+
        if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING))
                return 0;
 
@@ -87,32 +113,43 @@ int __init integrity_init_keyring(const unsigned int id)
                return -ENOMEM;
 
        restriction->check = restrict_link_to_ima;
+       perm |= KEY_USR_WRITE;
 
-       keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
-                                   KGIDT_INIT(0), cred,
-                                   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
-                                    KEY_USR_VIEW | KEY_USR_READ |
-                                    KEY_USR_WRITE | KEY_USR_SEARCH),
-                                   KEY_ALLOC_NOT_IN_QUOTA,
-                                   restriction, NULL);
-       if (IS_ERR(keyring[id])) {
-               err = PTR_ERR(keyring[id]);
-               pr_info("Can't allocate %s keyring (%d)\n",
-                       keyring_name[id], err);
-               keyring[id] = NULL;
+out:
+       return __integrity_init_keyring(id, perm, restriction);
+}
+
+int __init integrity_add_key(const unsigned int id, const void *data,
+                            off_t size, key_perm_t perm)
+{
+       key_ref_t key;
+       int rc = 0;
+
+       if (!keyring[id])
+               return -EINVAL;
+
+       key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric",
+                                  NULL, data, size, perm,
+                                  KEY_ALLOC_NOT_IN_QUOTA);
+       if (IS_ERR(key)) {
+               rc = PTR_ERR(key);
+               pr_err("Problem loading X.509 certificate %d\n", rc);
+       } else {
+               pr_notice("Loaded X.509 cert '%s'\n",
+                         key_ref_to_ptr(key)->description);
+               key_ref_put(key);
        }
-       return err;
+
+       return rc;
+
 }
 
 int __init integrity_load_x509(const unsigned int id, const char *path)
 {
-       key_ref_t key;
        void *data;
        loff_t size;
        int rc;
-
-       if (!keyring[id])
-               return -EINVAL;
+       key_perm_t perm;
 
        rc = kernel_read_file_from_path(path, &data, &size, 0,
                                        READING_X509_CERTIFICATE);
@@ -121,23 +158,21 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
                return rc;
        }
 
-       key = key_create_or_update(make_key_ref(keyring[id], 1),
-                                  "asymmetric",
-                                  NULL,
-                                  data,
-                                  size,
-                                  ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
-                                   KEY_USR_VIEW | KEY_USR_READ),
-                                  KEY_ALLOC_NOT_IN_QUOTA);
-       if (IS_ERR(key)) {
-               rc = PTR_ERR(key);
-               pr_err("Problem loading X.509 certificate (%d): %s\n",
-                      rc, path);
-       } else {
-               pr_notice("Loaded X.509 cert '%s': %s\n",
-                         key_ref_to_ptr(key)->description, path);
-               key_ref_put(key);
-       }
+       perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ;
+
+       pr_info("Loading X.509 certificate: %s\n", path);
+       rc = integrity_add_key(id, (const void *)data, size, perm);
+
        vfree(data);
-       return 0;
+       return rc;
+}
+
+int __init integrity_load_cert(const unsigned int id, const char *source,
+                              const void *data, size_t len, key_perm_t perm)
+{
+       if (!data)
+               return -EINVAL;
+
+       pr_info("Loading X.509 certificate: %s\n", source);
+       return integrity_add_key(id, data, len, perm);
 }
index 13b446328dda043f536f6c0155a2e9a0e4200e7d..a18f8c6d13b516f249ac35309630391221f60c19 100644 (file)
@@ -157,6 +157,14 @@ config IMA_APPRAISE
          <http://linux-ima.sourceforge.net>
          If unsure, say N.
 
+config IMA_ARCH_POLICY
+        bool "Enable loading an IMA architecture specific policy"
+        depends on KEXEC_VERIFY_SIG || IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS
+        default n
+        help
+          This option enables loading an IMA architecture specific policy
+          based on run time secure boot flags.
+
 config IMA_APPRAISE_BUILD_POLICY
        bool "IMA build time configured policy rules"
        depends on IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS
@@ -217,7 +225,7 @@ config IMA_APPRAISE_REQUIRE_POLICY_SIGS
 
 config IMA_APPRAISE_BOOTPARAM
        bool "ima_appraise boot parameter"
-       depends on IMA_APPRAISE
+       depends on IMA_APPRAISE && !IMA_ARCH_POLICY
        default y
        help
          This option enables the different "ima_appraise=" modes
index 2e11e750a06724c41185d169d8f9e8ee74f1af15..a2baa85ea2f57d8a72d8bc872716e0ca987c3550 100644 (file)
@@ -289,12 +289,22 @@ int ima_appraise_measurement(enum ima_hooks func,
        case EVM_IMA_XATTR_DIGSIG:
                set_bit(IMA_DIGSIG, &iint->atomic_flags);
                rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
-                                            (const char *)xattr_value, rc,
+                                            (const char *)xattr_value,
+                                            xattr_len,
                                             iint->ima_hash->digest,
                                             iint->ima_hash->length);
                if (rc == -EOPNOTSUPP) {
                        status = INTEGRITY_UNKNOWN;
-               } else if (rc) {
+                       break;
+               }
+               if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
+                   func == KEXEC_KERNEL_CHECK)
+                       rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
+                                                    (const char *)xattr_value,
+                                                    xattr_len,
+                                                    iint->ima_hash->digest,
+                                                    iint->ima_hash->length);
+               if (rc) {
                        cause = "invalid-signature";
                        status = INTEGRITY_FAIL;
                } else {
index 616a88f95b9288489414c2a9e4e8596e3a9e6e22..4ffac4f5c647eb9e68c5938501890917d52ad940 100644 (file)
@@ -105,7 +105,7 @@ static void ima_rdwr_violation_check(struct file *file,
        } else {
                if (must_measure)
                        set_bit(IMA_MUST_MEASURE, &iint->atomic_flags);
-               if ((atomic_read(&inode->i_writecount) > 0) && must_measure)
+               if (inode_is_open_for_write(inode) && must_measure)
                        send_writers = true;
        }
 
@@ -507,20 +507,26 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
  */
 int ima_load_data(enum kernel_load_data_id id)
 {
-       bool sig_enforce;
+       bool ima_enforce, sig_enforce;
 
-       if ((ima_appraise & IMA_APPRAISE_ENFORCE) != IMA_APPRAISE_ENFORCE)
-               return 0;
+       ima_enforce =
+               (ima_appraise & IMA_APPRAISE_ENFORCE) == IMA_APPRAISE_ENFORCE;
 
        switch (id) {
        case LOADING_KEXEC_IMAGE:
-               if (ima_appraise & IMA_APPRAISE_KEXEC) {
+               if (IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG)
+                   && arch_ima_get_secureboot()) {
+                       pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n");
+                       return -EACCES;
+               }
+
+               if (ima_enforce && (ima_appraise & IMA_APPRAISE_KEXEC)) {
                        pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n");
                        return -EACCES; /* INTEGRITY_UNKNOWN */
                }
                break;
        case LOADING_FIRMWARE:
-               if (ima_appraise & IMA_APPRAISE_FIRMWARE) {
+               if (ima_enforce && (ima_appraise & IMA_APPRAISE_FIRMWARE)) {
                        pr_err("Prevent firmware sysfs fallback loading.\n");
                        return -EACCES; /* INTEGRITY_UNKNOWN */
                }
@@ -528,7 +534,8 @@ int ima_load_data(enum kernel_load_data_id id)
        case LOADING_MODULE:
                sig_enforce = is_module_sig_enforced();
 
-               if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES)) {
+               if (ima_enforce && (!sig_enforce
+                                   && (ima_appraise & IMA_APPRAISE_MODULES))) {
                        pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n");
                        return -EACCES; /* INTEGRITY_UNKNOWN */
                }
index fcf5b27290630f5b7d981915e9ee226ee0071817..8bc8a1c8cb3f8cc3cf03fc3255d568438baa580f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/rculist.h>
 #include <linux/genhd.h>
 #include <linux/seq_file.h>
+#include <linux/ima.h>
 
 #include "ima.h"
 
@@ -58,6 +59,8 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
 
 enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB };
 
+enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY };
+
 struct ima_rule_entry {
        struct list_head list;
        int action;
@@ -104,7 +107,8 @@ static struct ima_rule_entry dont_measure_rules[] __ro_after_init = {
         .flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC,
         .flags = IMA_FSMAGIC},
-       {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}
+       {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC}
 };
 
 static struct ima_rule_entry original_measurement_rules[] __ro_after_init = {
@@ -147,6 +151,7 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
        {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
+       {.action = DONT_APPRAISE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC},
 #ifdef CONFIG_IMA_WRITE_POLICY
@@ -193,6 +198,9 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
         .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
 };
 
+/* An array of architecture specific rules */
+struct ima_rule_entry *arch_policy_entry __ro_after_init;
+
 static LIST_HEAD(ima_default_rules);
 static LIST_HEAD(ima_policy_rules);
 static LIST_HEAD(ima_temp_rules);
@@ -473,6 +481,75 @@ static int ima_appraise_flag(enum ima_hooks func)
        return 0;
 }
 
+static void add_rules(struct ima_rule_entry *entries, int count,
+                     enum policy_rule_list policy_rule)
+{
+       int i = 0;
+
+       for (i = 0; i < count; i++) {
+               struct ima_rule_entry *entry;
+
+               if (policy_rule & IMA_DEFAULT_POLICY)
+                       list_add_tail(&entries[i].list, &ima_default_rules);
+
+               if (policy_rule & IMA_CUSTOM_POLICY) {
+                       entry = kmemdup(&entries[i], sizeof(*entry),
+                                       GFP_KERNEL);
+                       if (!entry)
+                               continue;
+
+                       list_add_tail(&entry->list, &ima_policy_rules);
+               }
+               if (entries[i].action == APPRAISE)
+                       temp_ima_appraise |= ima_appraise_flag(entries[i].func);
+               if (entries[i].func == POLICY_CHECK)
+                       temp_ima_appraise |= IMA_APPRAISE_POLICY;
+       }
+}
+
+static int ima_parse_rule(char *rule, struct ima_rule_entry *entry);
+
+static int __init ima_init_arch_policy(void)
+{
+       const char * const *arch_rules;
+       const char * const *rules;
+       int arch_entries = 0;
+       int i = 0;
+
+       arch_rules = arch_get_ima_policy();
+       if (!arch_rules)
+               return arch_entries;
+
+       /* Get number of rules */
+       for (rules = arch_rules; *rules != NULL; rules++)
+               arch_entries++;
+
+       arch_policy_entry = kcalloc(arch_entries + 1,
+                                   sizeof(*arch_policy_entry), GFP_KERNEL);
+       if (!arch_policy_entry)
+               return 0;
+
+       /* Convert each policy string rules to struct ima_rule_entry format */
+       for (rules = arch_rules, i = 0; *rules != NULL; rules++) {
+               char rule[255];
+               int result;
+
+               result = strlcpy(rule, *rules, sizeof(rule));
+
+               INIT_LIST_HEAD(&arch_policy_entry[i].list);
+               result = ima_parse_rule(rule, &arch_policy_entry[i]);
+               if (result) {
+                       pr_warn("Skipping unknown architecture policy rule: %s\n",
+                               rule);
+                       memset(&arch_policy_entry[i], 0,
+                              sizeof(*arch_policy_entry));
+                       continue;
+               }
+               i++;
+       }
+       return i;
+}
+
 /**
  * ima_init_policy - initialize the default measure rules.
  *
@@ -481,68 +558,68 @@ static int ima_appraise_flag(enum ima_hooks func)
  */
 void __init ima_init_policy(void)
 {
-       int i, measure_entries, appraise_entries, secure_boot_entries;
+       int build_appraise_entries, arch_entries;
 
-       /* if !ima_policy set entries = 0 so we load NO default rules */
-       measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0;
-       appraise_entries = ima_use_appraise_tcb ?
-                        ARRAY_SIZE(default_appraise_rules) : 0;
-       secure_boot_entries = ima_use_secure_boot ?
-                       ARRAY_SIZE(secure_boot_rules) : 0;
-
-       for (i = 0; i < measure_entries; i++)
-               list_add_tail(&dont_measure_rules[i].list, &ima_default_rules);
+       /* if !ima_policy, we load NO default rules */
+       if (ima_policy)
+               add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules),
+                         IMA_DEFAULT_POLICY);
 
        switch (ima_policy) {
        case ORIGINAL_TCB:
-               for (i = 0; i < ARRAY_SIZE(original_measurement_rules); i++)
-                       list_add_tail(&original_measurement_rules[i].list,
-                                     &ima_default_rules);
+               add_rules(original_measurement_rules,
+                         ARRAY_SIZE(original_measurement_rules),
+                         IMA_DEFAULT_POLICY);
                break;
        case DEFAULT_TCB:
-               for (i = 0; i < ARRAY_SIZE(default_measurement_rules); i++)
-                       list_add_tail(&default_measurement_rules[i].list,
-                                     &ima_default_rules);
+               add_rules(default_measurement_rules,
+                         ARRAY_SIZE(default_measurement_rules),
+                         IMA_DEFAULT_POLICY);
        default:
                break;
        }
 
+       /*
+        * Based on runtime secure boot flags, insert arch specific measurement
+        * and appraise rules requiring file signatures for both the initial
+        * and custom policies, prior to other appraise rules.
+        * (Highest priority)
+        */
+       arch_entries = ima_init_arch_policy();
+       if (!arch_entries)
+               pr_info("No architecture policies found\n");
+       else
+               add_rules(arch_policy_entry, arch_entries,
+                         IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY);
+
        /*
         * Insert the builtin "secure_boot" policy rules requiring file
-        * signatures, prior to any other appraise rules.
+        * signatures, prior to other appraise rules.
         */
-       for (i = 0; i < secure_boot_entries; i++) {
-               list_add_tail(&secure_boot_rules[i].list, &ima_default_rules);
-               temp_ima_appraise |=
-                   ima_appraise_flag(secure_boot_rules[i].func);
-       }
+       if (ima_use_secure_boot)
+               add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules),
+                         IMA_DEFAULT_POLICY);
 
        /*
         * Insert the build time appraise rules requiring file signatures
         * for both the initial and custom policies, prior to other appraise
-        * rules.
+        * rules. As the secure boot rules includes all of the build time
+        * rules, include either one or the other set of rules, but not both.
         */
-       for (i = 0; i < ARRAY_SIZE(build_appraise_rules); i++) {
-               struct ima_rule_entry *entry;
-
-               if (!secure_boot_entries)
-                       list_add_tail(&build_appraise_rules[i].list,
-                                     &ima_default_rules);
-
-               entry = kmemdup(&build_appraise_rules[i], sizeof(*entry),
-                               GFP_KERNEL);
-               if (entry)
-                       list_add_tail(&entry->list, &ima_policy_rules);
-               build_ima_appraise |=
-                       ima_appraise_flag(build_appraise_rules[i].func);
+       build_appraise_entries = ARRAY_SIZE(build_appraise_rules);
+       if (build_appraise_entries) {
+               if (ima_use_secure_boot)
+                       add_rules(build_appraise_rules, build_appraise_entries,
+                                 IMA_CUSTOM_POLICY);
+               else
+                       add_rules(build_appraise_rules, build_appraise_entries,
+                                 IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY);
        }
 
-       for (i = 0; i < appraise_entries; i++) {
-               list_add_tail(&default_appraise_rules[i].list,
-                             &ima_default_rules);
-               if (default_appraise_rules[i].func == POLICY_CHECK)
-                       temp_ima_appraise |= IMA_APPRAISE_POLICY;
-       }
+       if (ima_use_appraise_tcb)
+               add_rules(default_appraise_rules,
+                         ARRAY_SIZE(default_appraise_rules),
+                         IMA_DEFAULT_POLICY);
 
        ima_rules = &ima_default_rules;
        ima_update_policy_flag();
@@ -576,6 +653,14 @@ void ima_update_policy(void)
        if (ima_rules != policy) {
                ima_policy_flag = 0;
                ima_rules = policy;
+
+               /*
+                * IMA architecture specific policy rules are specified
+                * as strings and converted to an array of ima_entry_rules
+                * on boot.  After loading a custom policy, free the
+                * architecture specific rules stored as an array.
+                */
+               kfree(arch_policy_entry);
        }
        ima_update_policy_flag();
 }
index e60473b13a8d200ebc31f915b3e6c98e160caaa1..7de59f44cba3b3f9d32d15d864c1b5e8fe0861ac 100644 (file)
@@ -141,7 +141,7 @@ int integrity_kernel_read(struct file *file, loff_t offset,
 
 #define INTEGRITY_KEYRING_EVM          0
 #define INTEGRITY_KEYRING_IMA          1
-#define INTEGRITY_KEYRING_MODULE       2
+#define INTEGRITY_KEYRING_PLATFORM     2
 #define INTEGRITY_KEYRING_MAX          3
 
 extern struct dentry *integrity_dir;
@@ -153,6 +153,8 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 
 int __init integrity_init_keyring(const unsigned int id);
 int __init integrity_load_x509(const unsigned int id, const char *path);
+int __init integrity_load_cert(const unsigned int id, const char *source,
+                              const void *data, size_t len, key_perm_t perm);
 #else
 
 static inline int integrity_digsig_verify(const unsigned int id,
@@ -166,6 +168,14 @@ static inline int integrity_init_keyring(const unsigned int id)
 {
        return 0;
 }
+
+static inline int __init integrity_load_cert(const unsigned int id,
+                                            const char *source,
+                                            const void *data, size_t len,
+                                            key_perm_t perm)
+{
+       return 0;
+}
 #endif /* CONFIG_INTEGRITY_SIGNATURE */
 
 #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
@@ -222,3 +232,13 @@ integrity_audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type)
 }
 
 #endif
+
+#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
+void __init add_to_platform_keyring(const char *source, const void *data,
+                                   size_t len);
+#else
+static inline void __init add_to_platform_keyring(const char *source,
+                                                 const void *data, size_t len)
+{
+}
+#endif
diff --git a/security/integrity/platform_certs/efi_parser.c b/security/integrity/platform_certs/efi_parser.c
new file mode 100644 (file)
index 0000000..18f01f3
--- /dev/null
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* EFI signature/key/certificate list parser
+ *
+ * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#define pr_fmt(fmt) "EFI: "fmt
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/err.h>
+#include <linux/efi.h>
+
+/**
+ * parse_efi_signature_list - Parse an EFI signature list for certificates
+ * @source: The source of the key
+ * @data: The data blob to parse
+ * @size: The size of the data blob
+ * @get_handler_for_guid: Get the handler func for the sig type (or NULL)
+ *
+ * Parse an EFI signature list looking for elements of interest.  A list is
+ * made up of a series of sublists, where all the elements in a sublist are of
+ * the same type, but sublists can be of different types.
+ *
+ * For each sublist encountered, the @get_handler_for_guid function is called
+ * with the type specifier GUID and returns either a pointer to a function to
+ * handle elements of that type or NULL if the type is not of interest.
+ *
+ * If the sublist is of interest, each element is passed to the handler
+ * function in turn.
+ *
+ * Error EBADMSG is returned if the list doesn't parse correctly and 0 is
+ * returned if the list was parsed correctly.  No error can be returned from
+ * the @get_handler_for_guid function or the element handler function it
+ * returns.
+ */
+int __init parse_efi_signature_list(
+       const char *source,
+       const void *data, size_t size,
+       efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *))
+{
+       efi_element_handler_t handler;
+       unsigned int offs = 0;
+
+       pr_devel("-->%s(,%zu)\n", __func__, size);
+
+       while (size > 0) {
+               const efi_signature_data_t *elem;
+               efi_signature_list_t list;
+               size_t lsize, esize, hsize, elsize;
+
+               if (size < sizeof(list))
+                       return -EBADMSG;
+
+               memcpy(&list, data, sizeof(list));
+               pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
+                        offs,
+                        list.signature_type.b, list.signature_list_size,
+                        list.signature_header_size, list.signature_size);
+
+               lsize = list.signature_list_size;
+               hsize = list.signature_header_size;
+               esize = list.signature_size;
+               elsize = lsize - sizeof(list) - hsize;
+
+               if (lsize > size) {
+                       pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
+                                __func__, offs);
+                       return -EBADMSG;
+               }
+
+               if (lsize < sizeof(list) ||
+                   lsize - sizeof(list) < hsize ||
+                   esize < sizeof(*elem) ||
+                   elsize < esize ||
+                   elsize % esize != 0) {
+                       pr_devel("- bad size combo @%x\n", offs);
+                       return -EBADMSG;
+               }
+
+               handler = get_handler_for_guid(&list.signature_type);
+               if (!handler) {
+                       data += lsize;
+                       size -= lsize;
+                       offs += lsize;
+                       continue;
+               }
+
+               data += sizeof(list) + hsize;
+               size -= sizeof(list) + hsize;
+               offs += sizeof(list) + hsize;
+
+               for (; elsize > 0; elsize -= esize) {
+                       elem = data;
+
+                       pr_devel("ELEM[%04x]\n", offs);
+                       handler(source,
+                               &elem->signature_data,
+                               esize - sizeof(*elem));
+
+                       data += esize;
+                       size -= esize;
+                       offs += esize;
+               }
+       }
+
+       return 0;
+}
diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
new file mode 100644 (file)
index 0000000..81b19c5
--- /dev/null
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/err.h>
+#include <linux/efi.h>
+#include <linux/slab.h>
+#include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
+#include "../integrity.h"
+
+static efi_guid_t efi_cert_x509_guid __initdata = EFI_CERT_X509_GUID;
+static efi_guid_t efi_cert_x509_sha256_guid __initdata =
+       EFI_CERT_X509_SHA256_GUID;
+static efi_guid_t efi_cert_sha256_guid __initdata = EFI_CERT_SHA256_GUID;
+
+/*
+ * Look to see if a UEFI variable called MokIgnoreDB exists and return true if
+ * it does.
+ *
+ * This UEFI variable is set by the shim if a user tells the shim to not use
+ * the certs/hashes in the UEFI db variable for verification purposes.  If it
+ * is set, we should ignore the db variable also and the true return indicates
+ * this.
+ */
+static __init bool uefi_check_ignore_db(void)
+{
+       efi_status_t status;
+       unsigned int db = 0;
+       unsigned long size = sizeof(db);
+       efi_guid_t guid = EFI_SHIM_LOCK_GUID;
+
+       status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db);
+       return status == EFI_SUCCESS;
+}
+
+/*
+ * Get a certificate list blob from the named EFI variable.
+ */
+static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
+                                 unsigned long *size)
+{
+       efi_status_t status;
+       unsigned long lsize = 4;
+       unsigned long tmpdb[4];
+       void *db;
+
+       status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
+       if (status != EFI_BUFFER_TOO_SMALL) {
+               pr_err("Couldn't get size: 0x%lx\n", status);
+               return NULL;
+       }
+
+       db = kmalloc(lsize, GFP_KERNEL);
+       if (!db)
+               return NULL;
+
+       status = efi.get_variable(name, guid, NULL, &lsize, db);
+       if (status != EFI_SUCCESS) {
+               kfree(db);
+               pr_err("Error reading db var: 0x%lx\n", status);
+               return NULL;
+       }
+
+       *size = lsize;
+       return db;
+}
+
+/*
+ * Blacklist a hash.
+ */
+static __init void uefi_blacklist_hash(const char *source, const void *data,
+                                      size_t len, const char *type,
+                                      size_t type_len)
+{
+       char *hash, *p;
+
+       hash = kmalloc(type_len + len * 2 + 1, GFP_KERNEL);
+       if (!hash)
+               return;
+       p = memcpy(hash, type, type_len);
+       p += type_len;
+       bin2hex(p, data, len);
+       p += len * 2;
+       *p = 0;
+
+       mark_hash_blacklisted(hash);
+       kfree(hash);
+}
+
+/*
+ * Blacklist an X509 TBS hash.
+ */
+static __init void uefi_blacklist_x509_tbs(const char *source,
+                                          const void *data, size_t len)
+{
+       uefi_blacklist_hash(source, data, len, "tbs:", 4);
+}
+
+/*
+ * Blacklist the hash of an executable.
+ */
+static __init void uefi_blacklist_binary(const char *source,
+                                        const void *data, size_t len)
+{
+       uefi_blacklist_hash(source, data, len, "bin:", 4);
+}
+
+/*
+ * Return the appropriate handler for particular signature list types found in
+ * the UEFI db and MokListRT tables.
+ */
+static __init efi_element_handler_t get_handler_for_db(const efi_guid_t *
+                                                      sig_type)
+{
+       if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
+               return add_to_platform_keyring;
+       return 0;
+}
+
+/*
+ * Return the appropriate handler for particular signature list types found in
+ * the UEFI dbx and MokListXRT tables.
+ */
+static __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *
+                                                       sig_type)
+{
+       if (efi_guidcmp(*sig_type, efi_cert_x509_sha256_guid) == 0)
+               return uefi_blacklist_x509_tbs;
+       if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0)
+               return uefi_blacklist_binary;
+       return 0;
+}
+
+/*
+ * Load the certs contained in the UEFI databases into the platform trusted
+ * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
+ * keyring.
+ */
+static int __init load_uefi_certs(void)
+{
+       efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
+       efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
+       void *db = NULL, *dbx = NULL, *mok = NULL;
+       unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
+       int rc = 0;
+
+       if (!efi.get_variable)
+               return false;
+
+       /* Get db, MokListRT, and dbx.  They might not exist, so it isn't
+        * an error if we can't get them.
+        */
+       if (!uefi_check_ignore_db()) {
+               db = get_cert_list(L"db", &secure_var, &dbsize);
+               if (!db) {
+                       pr_err("MODSIGN: Couldn't get UEFI db list\n");
+               } else {
+                       rc = parse_efi_signature_list("UEFI:db",
+                                       db, dbsize, get_handler_for_db);
+                       if (rc)
+                               pr_err("Couldn't parse db signatures: %d\n",
+                                      rc);
+                       kfree(db);
+               }
+       }
+
+       mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
+       if (!mok) {
+               pr_info("Couldn't get UEFI MokListRT\n");
+       } else {
+               rc = parse_efi_signature_list("UEFI:MokListRT",
+                                             mok, moksize, get_handler_for_db);
+               if (rc)
+                       pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
+               kfree(mok);
+       }
+
+       dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
+       if (!dbx) {
+               pr_info("Couldn't get UEFI dbx list\n");
+       } else {
+               rc = parse_efi_signature_list("UEFI:dbx",
+                                             dbx, dbxsize,
+                                             get_handler_for_dbx);
+               if (rc)
+                       pr_err("Couldn't parse dbx signatures: %d\n", rc);
+               kfree(dbx);
+       }
+
+       return rc;
+}
+late_initcall(load_uefi_certs);
diff --git a/security/integrity/platform_certs/platform_keyring.c b/security/integrity/platform_certs/platform_keyring.c
new file mode 100644 (file)
index 0000000..bcafd73
--- /dev/null
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Platform keyring for firmware/platform keys
+ *
+ * Copyright IBM Corporation, 2018
+ * Author(s): Nayna Jain <nayna@linux.ibm.com>
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include "../integrity.h"
+
+/**
+ * add_to_platform_keyring - Add to platform keyring without validation.
+ * @source: Source of key
+ * @data: The blob holding the key
+ * @len: The length of the data blob
+ *
+ * Add a key to the platform keyring without checking its trust chain.  This
+ * is available only during kernel initialisation.
+ */
+void __init add_to_platform_keyring(const char *source, const void *data,
+                                   size_t len)
+{
+       key_perm_t perm;
+       int rc;
+
+       perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW;
+
+       rc = integrity_load_cert(INTEGRITY_KEYRING_PLATFORM, source, data, len,
+                                perm);
+       if (rc)
+               pr_info("Error adding keys to platform keyring %s\n", source);
+}
+
+/*
+ * Create the trusted keyrings.
+ */
+static __init int platform_keyring_init(void)
+{
+       int rc;
+
+       rc = integrity_init_keyring(INTEGRITY_KEYRING_PLATFORM);
+       if (rc)
+               return rc;
+
+       pr_notice("Platform Keyring initialized\n");
+       return 0;
+}
+
+/*
+ * Must be initialised before we try and load the keys into the keyring.
+ */
+device_initcall(platform_keyring_init);
index eb54df682d5622a69744a61f3f29242555172f01..1a2bd15c5b6e53be68ac9f37ee6b6cf2de582424 100644 (file)
@@ -14,6 +14,7 @@ TARGETS += firmware
 TARGETS += ftrace
 TARGETS += futex
 TARGETS += gpio
+TARGETS += ima
 TARGETS += intel_pstate
 TARGETS += ipc
 TARGETS += ir
diff --git a/tools/testing/selftests/ima/Makefile b/tools/testing/selftests/ima/Makefile
new file mode 100644 (file)
index 0000000..0b3adf5
--- /dev/null
@@ -0,0 +1,11 @@
+# Makefile for kexec_load
+
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
+
+ifeq ($(ARCH),x86)
+TEST_PROGS := test_kexec_load.sh
+
+include ../lib.mk
+
+endif
diff --git a/tools/testing/selftests/ima/config b/tools/testing/selftests/ima/config
new file mode 100644 (file)
index 0000000..6bc86d4
--- /dev/null
@@ -0,0 +1,4 @@
+CONFIG_IMA_APPRAISE
+CONFIG_IMA_ARCH_POLICY
+CONFIG_SECURITYFS
+CONFIG_KEXEC_VERIFY_SIG
diff --git a/tools/testing/selftests/ima/test_kexec_load.sh b/tools/testing/selftests/ima/test_kexec_load.sh
new file mode 100755 (executable)
index 0000000..1c10093
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0+
+# Loading a kernel image via the kexec_load syscall should fail
+# when the kerne is CONFIG_KEXEC_VERIFY_SIG enabled and the system
+# is booted in secureboot mode.
+
+TEST="$0"
+EFIVARFS="/sys/firmware/efi/efivars"
+rc=0
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+
+# kexec requires root privileges
+if [ $UID != 0 ]; then
+       echo "$TEST: must be run as root" >&2
+       exit $ksft_skip
+fi
+
+# Make sure that efivars is mounted in the normal location
+if ! grep -q "^\S\+ $EFIVARFS efivarfs" /proc/mounts; then
+       echo "$TEST: efivars is not mounted on $EFIVARFS" >&2
+       exit $ksft_skip
+fi
+
+# Get secureboot mode
+file="$EFIVARFS/SecureBoot-*"
+if [ ! -e $file ]; then
+       echo "$TEST: unknown secureboot mode" >&2
+       exit $ksft_skip
+fi
+secureboot=`hexdump $file | awk '{print substr($4,length($4),1)}'`
+
+# kexec_load should fail in secure boot mode
+KERNEL_IMAGE="/boot/vmlinuz-`uname -r`"
+kexec -l $KERNEL_IMAGE &>> /dev/null
+if [ $? == 0 ]; then
+       kexec -u
+       if [ "$secureboot" == "1" ]; then
+               echo "$TEST: kexec_load succeeded [FAIL]"
+               rc=1
+       else
+               echo "$TEST: kexec_load succeeded [PASS]"
+       fi
+else
+       if [ "$secureboot" == "1" ]; then
+               echo "$TEST: kexec_load failed [PASS]"
+       else
+               echo "$TEST: kexec_load failed [FAIL]"
+               rc=1
+       fi
+fi
+
+exit $rc