Skip to content

Commit

Permalink
kexec: Allow kexec_file() with appropriate IMA policy when locked down
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matthew Garrett authored and James Morris committed Aug 20, 2019
1 parent b0c8fdc commit 29d3c1c
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 2 deletions.
9 changes: 9 additions & 0 deletions include/linux/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
10 changes: 9 additions & 1 deletion kernel/kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions security/integrity/ima/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
50 changes: 50 additions & 0 deletions security/integrity/ima/ima_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 29d3c1c

Please sign in to comment.