]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
kexec: Allow kexec_file() with appropriate IMA policy when locked down
authorMatthew Garrett <matthewgarrett@google.com>
Tue, 20 Aug 2019 00:18:01 +0000 (17:18 -0700)
committerJames Morris <jmorris@namei.org>
Tue, 20 Aug 2019 04:54:16 +0000 (21:54 -0700)
Systems in lockdown mode should block the kexec of untrusted kernels.
For x86 and ARM we can ensure that a kernel is trustworthy by validating
a PE signature, but this isn't possible on other architectures. On those
platforms we can use IMA digital signatures instead. Add a function to
determine whether IMA has or will verify signatures for a given event type,
and if so permit kexec_file() even if the kernel is otherwise locked down.
This is restricted to cases where CONFIG_INTEGRITY_TRUSTED_KEYRING is set
in order to prevent an attacker from loading additional keys at runtime.

Signed-off-by: Matthew Garrett <mjg59@google.com>
Acked-by: Mimi Zohar <zohar@linux.ibm.com>
Cc: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
Cc: linux-integrity@vger.kernel.org
Signed-off-by: James Morris <jmorris@namei.org>
include/linux/ima.h
kernel/kexec_file.c
security/integrity/ima/ima.h
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c

index 00036d2f57c30824aad747469f4d640dfd0d6857..8e2f324fb9013eba98cde469b75f20f17635419e 100644 (file)
@@ -129,4 +129,13 @@ static inline int ima_inode_removexattr(struct dentry *dentry,
        return 0;
 }
 #endif /* CONFIG_IMA_APPRAISE */
+
+#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
+extern bool ima_appraise_signature(enum kernel_read_file_id func);
+#else
+static inline bool ima_appraise_signature(enum kernel_read_file_id func)
+{
+       return false;
+}
+#endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */
 #endif /* _LINUX_IMA_H */
index 43109ef4d6bf3686dfe6ba1a6a4dfe9f93fb0e38..7f4a618fc8c1d43737fd22d090ef6223cb000919 100644 (file)
@@ -208,7 +208,15 @@ kimage_validate_signature(struct kimage *image)
                        return ret;
                }
 
-               return security_locked_down(LOCKDOWN_KEXEC);
+               /* If IMA is guaranteed to appraise a signature on the kexec
+                * image, permit it even if the kernel is otherwise locked
+                * down.
+                */
+               if (!ima_appraise_signature(READING_KEXEC_IMAGE) &&
+                   security_locked_down(LOCKDOWN_KEXEC))
+                       return -EPERM;
+
+               return 0;
 
                /* All other errors are fatal, including nomem, unparseable
                 * signatures and signature check failures - even if signatures
index ca10917b5f89ac2b322ea99c98f411a775ee8959..874bd77d3b91845f1b1e3296aa7329843bf4cd9c 100644 (file)
@@ -111,6 +111,8 @@ struct ima_kexec_hdr {
        u64 count;
 };
 
+extern const int read_idmap[];
+
 #ifdef CONFIG_HAVE_IMA_KEXEC
 void ima_load_kexec_buffer(void);
 #else
index 1cffda4412b72166e98ff9954e37ecac4146b7d5..1747bc7bcb604b8e9b3beb8f39b1355d8d9f52d8 100644 (file)
@@ -469,7 +469,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
        return 0;
 }
 
-static const int read_idmap[READING_MAX_ID] = {
+const int read_idmap[READING_MAX_ID] = {
        [READING_FIRMWARE] = FIRMWARE_CHECK,
        [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK,
        [READING_MODULE] = MODULE_CHECK,
index 7b53f2ca58e285f75c21286e7e405f118117fe7b..b8773f05f9dae7d0367dc97bae41004efa289ef0 100644 (file)
@@ -1339,3 +1339,53 @@ int ima_policy_show(struct seq_file *m, void *v)
        return 0;
 }
 #endif /* CONFIG_IMA_READ_POLICY */
+
+#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
+/*
+ * ima_appraise_signature: whether IMA will appraise a given function using
+ * an IMA digital signature. This is restricted to cases where the kernel
+ * has a set of built-in trusted keys in order to avoid an attacker simply
+ * loading additional keys.
+ */
+bool ima_appraise_signature(enum kernel_read_file_id id)
+{
+       struct ima_rule_entry *entry;
+       bool found = false;
+       enum ima_hooks func;
+
+       if (id >= READING_MAX_ID)
+               return false;
+
+       func = read_idmap[id] ?: FILE_CHECK;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(entry, ima_rules, list) {
+               if (entry->action != APPRAISE)
+                       continue;
+
+               /*
+                * A generic entry will match, but otherwise require that it
+                * match the func we're looking for
+                */
+               if (entry->func && entry->func != func)
+                       continue;
+
+               /*
+                * We require this to be a digital signature, not a raw IMA
+                * hash.
+                */
+               if (entry->flags & IMA_DIGSIG_REQUIRED)
+                       found = true;
+
+               /*
+                * We've found a rule that matches, so break now even if it
+                * didn't require a digital signature - a later rule that does
+                * won't override it, so would be a false positive.
+                */
+               break;
+       }
+
+       rcu_read_unlock();
+       return found;
+}
+#endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */