Re: [RFC] kexec: Allow kexec_file() with appropriate IMA policy when locked down

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2019-03-12 at 12:57 -0700, Matthew Garrett wrote:
> 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 instead, either with native IMA digital
> signatures or EVM-protected IMA hashes. Add a function to determine
> whether IMA will verify signatures on kexec files, 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.

Thank you for working on this!  With the changes suggested below, it
might work.  :)

> 
> Signed-off-by: Matthew Garrett <mjg59@xxxxxxxxxx>
> ---
>  include/linux/evm.h                 |  6 +++++
>  include/linux/ima.h                 |  9 ++++++++
>  kernel/kexec_file.c                 |  9 ++++++--
>  security/integrity/evm/evm_main.c   |  2 +-
>  security/integrity/ima/ima_policy.c | 35 +++++++++++++++++++++++++++++
>  5 files changed, 58 insertions(+), 3 deletions(-)
> 
> diff --git a/include/linux/evm.h b/include/linux/evm.h
> index 8302bc29bb35..6e89d046b716 100644
> --- a/include/linux/evm.h
> +++ b/include/linux/evm.h
> @@ -15,6 +15,7 @@
>  struct integrity_iint_cache;
>  
>  #ifdef CONFIG_EVM
> +extern bool evm_key_loaded(void);
>  extern int evm_set_key(void *key, size_t keylen);
>  extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
>  					     const char *xattr_name,
> @@ -45,6 +46,11 @@ static inline int posix_xattr_acl(const char *xattrname)
>  #endif
>  #else
>  
> +static inline bool evm_key_loaded(void)
> +{
> +	return false;
> +}
> +
>  static inline int evm_set_key(void *key, size_t keylen)
>  {
>  	return -EOPNOTSUPP;
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index dc12fbcf484c..2ec593537c9b 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -132,4 +132,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_kexec_signature(void);
> +#else
> +static inline bool ima_appraise_kexec_signature(void)
> +{
> +	return false;
> +}
> +#endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */
>  #endif /* _LINUX_IMA_H */
> diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
> index 0cfe4f6f7f85..8ca607f1b515 100644
> --- a/kernel/kexec_file.c
> +++ b/kernel/kexec_file.c
> @@ -20,11 +20,11 @@
>  #include <linux/mutex.h>
>  #include <linux/list.h>
>  #include <linux/fs.h>
> -#include <linux/ima.h>
>  #include <crypto/hash.h>
>  #include <crypto/sha.h>
>  #include <linux/elf.h>
>  #include <linux/elfcore.h>
> +#include <linux/ima.h>
>  #include <linux/kernel.h>
>  #include <linux/syscalls.h>
>  #include <linux/vmalloc.h>
> @@ -240,7 +240,12 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
>  
>  		ret = 0;
>  
> -		if (kernel_is_locked_down(reason)) {
> +		/* 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_kexec_signature() &&
> +		    kernel_is_locked_down(reason)) {
>  			ret = -EPERM;
>  			goto out;
>  		}
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index b6d9f14bc234..aad61bc0f774 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -87,7 +87,7 @@ static void __init evm_init_config(void)
>  	pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs);
>  }
>  
> -static bool evm_key_loaded(void)
> +bool evm_key_loaded(void)
>  {
>  	return (bool)(evm_initialized & EVM_KEY_MASK);
>  }

This might be sufficient for your environment, but in general it
isn't.


> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index 8bc8a1c8cb3f..c06b1a6b3528 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -21,6 +21,7 @@
>  #include <linux/genhd.h>
>  #include <linux/seq_file.h>
>  #include <linux/ima.h>
> +#include <linux/evm.h>
>  
>  #include "ima.h"
>  
> @@ -1336,4 +1337,38 @@ int ima_policy_show(struct seq_file *m, void *v)
>  	seq_puts(m, "\n");
>  	return 0;
>  }
> +
>  #endif	/* CONFIG_IMA_READ_POLICY */
> +
> +#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)

With these defines, the function isn't limited to just "lockdown".
 Either fix the defines or the patch description.

> +/*
> + * ima_appraise_kexec: whether IMA will appraise a kexec image, either via
> + * IMA digital signatures or with a hash and EVM validation
> + */
> +bool ima_appraise_kexec_signature(void)

Instead of making this specific to kexec, how about naming the
function something like ima_require_appraise_signature() and pass the
kernel_read_file_id (eg. READING_KEXEC_IMAGE, READING_MODULE).

> +{
> +	struct ima_rule_entry *entry;
> +	bool found = false;
> +
> +	rcu_read_lock();
> +	list_for_each_entry_rcu(entry, ima_rules, list) {
> +		if (entry->func != KEXEC_KERNEL_CHECK ||
> +		    entry->action != APPRAISE)
> +			continue;
> +
> +		/*
> +		 * We require this to be a digital signature, not a raw IMA
> +		 * hash. An IMA hash is acceptable as long as it's covered
> +		 * by an EVM signature.
> +		 */
> +		if (entry->flags & IMA_DIGSIG_REQUIRED ||
> +		    evm_key_loaded()) {

evm_key_loaded() is a problem.

> +			found = true;
> +			break;
> +		}

The first matching rule dictates the policy.  Move the "break" here.

Walking the list looking for a specific rule might not be a true
indication of the policy.  For example, with a generic rule prior to a
specific rule, the generic rule might take precedence.

As long as the generic rules require a signature, there isn't a
problem.  I would stop walking the policy rules after the first
"appraise" rule that doesn't require a signature.  This will prevent
returning a false positive.

The builtin and arch policy rules are by design forced to be first.

Mimi


> +	}
> +
> +	rcu_read_unlock();
> +	return found;
> +}
> +#endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux