Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Matthew Garrett and committed by
James Morris
29d3c1c8 b0c8fdc7

+71 -2
+9
include/linux/ima.h
··· 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 */
+9 -1
kernel/kexec_file.c
··· 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
+2
security/integrity/ima/ima.h
··· 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
+1 -1
security/integrity/ima/ima_main.c
··· 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,
+50
security/integrity/ima/ima_policy.c
··· 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 */