diff options
author | Matthew Garrett <matthewgarrett@google.com> | 2019-08-19 20:18:01 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2019-08-20 00:54:16 -0400 |
commit | 29d3c1c8dfe752c01b7115ecd5a3142b232a38e1 (patch) | |
tree | 9a42db9e64c08db645dcf9689344d4f718b4d518 | |
parent | b0c8fdc7fdb77586c3d1937050925b960743306e (diff) |
kexec: Allow kexec_file() with appropriate IMA policy when locked down
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>
-rw-r--r-- | include/linux/ima.h | 9 | ||||
-rw-r--r-- | kernel/kexec_file.c | 10 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 50 |
5 files changed, 71 insertions, 2 deletions
diff --git a/include/linux/ima.h b/include/linux/ima.h index 00036d2f57c3..8e2f324fb901 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h | |||
@@ -129,4 +129,13 @@ static inline int ima_inode_removexattr(struct dentry *dentry, | |||
129 | return 0; | 129 | return 0; |
130 | } | 130 | } |
131 | #endif /* CONFIG_IMA_APPRAISE */ | 131 | #endif /* CONFIG_IMA_APPRAISE */ |
132 | |||
133 | #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) | ||
134 | extern bool ima_appraise_signature(enum kernel_read_file_id func); | ||
135 | #else | ||
136 | static inline bool ima_appraise_signature(enum kernel_read_file_id func) | ||
137 | { | ||
138 | return false; | ||
139 | } | ||
140 | #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */ | ||
132 | #endif /* _LINUX_IMA_H */ | 141 | #endif /* _LINUX_IMA_H */ |
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 43109ef4d6bf..7f4a618fc8c1 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c | |||
@@ -208,7 +208,15 @@ kimage_validate_signature(struct kimage *image) | |||
208 | return ret; | 208 | return ret; |
209 | } | 209 | } |
210 | 210 | ||
211 | return security_locked_down(LOCKDOWN_KEXEC); | 211 | /* If IMA is guaranteed to appraise a signature on the kexec |
212 | * image, permit it even if the kernel is otherwise locked | ||
213 | * down. | ||
214 | */ | ||
215 | if (!ima_appraise_signature(READING_KEXEC_IMAGE) && | ||
216 | security_locked_down(LOCKDOWN_KEXEC)) | ||
217 | return -EPERM; | ||
218 | |||
219 | return 0; | ||
212 | 220 | ||
213 | /* All other errors are fatal, including nomem, unparseable | 221 | /* All other errors are fatal, including nomem, unparseable |
214 | * signatures and signature check failures - even if signatures | 222 | * signatures and signature check failures - even if signatures |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index ca10917b5f89..874bd77d3b91 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -111,6 +111,8 @@ struct ima_kexec_hdr { | |||
111 | u64 count; | 111 | u64 count; |
112 | }; | 112 | }; |
113 | 113 | ||
114 | extern const int read_idmap[]; | ||
115 | |||
114 | #ifdef CONFIG_HAVE_IMA_KEXEC | 116 | #ifdef CONFIG_HAVE_IMA_KEXEC |
115 | void ima_load_kexec_buffer(void); | 117 | void ima_load_kexec_buffer(void); |
116 | #else | 118 | #else |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 1cffda4412b7..1747bc7bcb60 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -469,7 +469,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id) | |||
469 | return 0; | 469 | return 0; |
470 | } | 470 | } |
471 | 471 | ||
472 | static const int read_idmap[READING_MAX_ID] = { | 472 | const int read_idmap[READING_MAX_ID] = { |
473 | [READING_FIRMWARE] = FIRMWARE_CHECK, | 473 | [READING_FIRMWARE] = FIRMWARE_CHECK, |
474 | [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, | 474 | [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, |
475 | [READING_MODULE] = MODULE_CHECK, | 475 | [READING_MODULE] = MODULE_CHECK, |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 7b53f2ca58e2..b8773f05f9da 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -1339,3 +1339,53 @@ int ima_policy_show(struct seq_file *m, void *v) | |||
1339 | return 0; | 1339 | return 0; |
1340 | } | 1340 | } |
1341 | #endif /* CONFIG_IMA_READ_POLICY */ | 1341 | #endif /* CONFIG_IMA_READ_POLICY */ |
1342 | |||
1343 | #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) | ||
1344 | /* | ||
1345 | * ima_appraise_signature: whether IMA will appraise a given function using | ||
1346 | * an IMA digital signature. This is restricted to cases where the kernel | ||
1347 | * has a set of built-in trusted keys in order to avoid an attacker simply | ||
1348 | * loading additional keys. | ||
1349 | */ | ||
1350 | bool ima_appraise_signature(enum kernel_read_file_id id) | ||
1351 | { | ||
1352 | struct ima_rule_entry *entry; | ||
1353 | bool found = false; | ||
1354 | enum ima_hooks func; | ||
1355 | |||
1356 | if (id >= READING_MAX_ID) | ||
1357 | return false; | ||
1358 | |||
1359 | func = read_idmap[id] ?: FILE_CHECK; | ||
1360 | |||
1361 | rcu_read_lock(); | ||
1362 | list_for_each_entry_rcu(entry, ima_rules, list) { | ||
1363 | if (entry->action != APPRAISE) | ||
1364 | continue; | ||
1365 | |||
1366 | /* | ||
1367 | * A generic entry will match, but otherwise require that it | ||
1368 | * match the func we're looking for | ||
1369 | */ | ||
1370 | if (entry->func && entry->func != func) | ||
1371 | continue; | ||
1372 | |||
1373 | /* | ||
1374 | * We require this to be a digital signature, not a raw IMA | ||
1375 | * hash. | ||
1376 | */ | ||
1377 | if (entry->flags & IMA_DIGSIG_REQUIRED) | ||
1378 | found = true; | ||
1379 | |||
1380 | /* | ||
1381 | * We've found a rule that matches, so break now even if it | ||
1382 | * didn't require a digital signature - a later rule that does | ||
1383 | * won't override it, so would be a false positive. | ||
1384 | */ | ||
1385 | break; | ||
1386 | } | ||
1387 | |||
1388 | rcu_read_unlock(); | ||
1389 | return found; | ||
1390 | } | ||
1391 | #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */ | ||