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.
Unified · Split
| @@ -129,4 +129,13 @@ static inline int ima_inode_removexattr(struct dentry *dentry, · 128 unmodified lines | ||
| 129 | 129 | return 0; |
| 130 | 130 | } |
| 131 | 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 | 141 | #endif /* _LINUX_IMA_H */ |
| @@ -208,7 +208,15 @@ kimage_validate_signature(struct kimage *image) · 207 unmodified lines | ||
| 208 | 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 | 221 | /* All other errors are fatal, including nomem, unparseable |
| 214 | 222 | * signatures and signature check failures - even if signatures |
| @@ -111,6 +111,8 @@ struct ima_kexec_hdr { · 110 unmodified lines | ||
| 111 | 111 | u64 count; |
| 112 | 112 | }; |
| 113 | 113 | |
| 114 | +extern const int read_idmap[]; | |
| 115 | + | |
| 114 | 116 | #ifdef CONFIG_HAVE_IMA_KEXEC |
| 115 | 117 | void ima_load_kexec_buffer(void); |
| 116 | 118 | #else |
| @@ -469,7 +469,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id) · 468 unmodified lines | ||
| 469 | 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 | 473 | [READING_FIRMWARE] = FIRMWARE_CHECK, |
| 474 | 474 | [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, |
| 475 | 475 | [READING_MODULE] = MODULE_CHECK, |
| @@ -1339,3 +1339,53 @@ int ima_policy_show(struct seq_file *m, void *v) · 1338 unmodified lines | ||
| 1339 | 1339 | return 0; |
| 1340 | 1340 | } |
| 1341 | 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 */ | |