[PATCH 20/20] evm: read EVM key from the kernel

From: Dmitry Kasatkin
Date: Wed Apr 23 2014 - 09:35:55 EST


Currently EVM key needs to be added from the user space
and it has to be done before mounting filesystems.
It requires initramfs.
Many systems often does not want to use initramfs.

This patch provide support for loading EVM key from the kernel.

It supports both 'trusted' and 'user' master keys.
However, it is recommended to use 'trusted' master key,
because 'user' master key is in non-encrypted form.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@xxxxxxxxxxx>
---
security/integrity/evm/Kconfig | 8 ++++
security/integrity/evm/evm.h | 9 ++++
security/integrity/evm/evm_crypto.c | 96 +++++++++++++++++++++++++++++++++++++
security/integrity/evm/evm_main.c | 1 +
4 files changed, 114 insertions(+)

diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index 70d12f7..953ef05 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -60,3 +60,11 @@ config EVM_LOAD_X509
help
This option enables X509 certificate loading from the kernel
to the '_evm' trusted keyring.
+
+config EVM_LOAD_KEY
+ bool "Load EVM HMAC key from the kernel"
+ depends on EVM
+ default n
+ help
+ This option enables EVM HMAC key loading from the kernel.
+ It enables EVM.
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index 1db78b8..1890eac 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -40,6 +40,15 @@ extern struct crypto_shash *hash_tfm;
/* List of EVM protected security xattrs */
extern char *evm_config_xattrnames[];

+#ifdef CONFIG_EVM_LOAD_KEY
+int evm_load_key(const char *key, const char *kmk);
+#else
+static inline int evm_load_key(const char *key, const char *kmk)
+{
+ return 0;
+}
+#endif
+
int evm_init_key(void);
int evm_update_evmxattr(struct dentry *dentry,
const char *req_xattr_name,
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index f79ebf5..c45b71b 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -18,6 +18,8 @@
#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/xattr.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
#include <keys/encrypted-type.h>
#include <crypto/hash.h>
#include "evm.h"
@@ -265,3 +267,97 @@ out:
pr_err("initialization failed\n");
return rc;
}
+
+#ifdef CONFIG_EVM_LOAD_KEY
+int evm_load_key(const char *key, const char *kmk)
+{
+ key_ref_t key_ref, keyring_ref;
+ char *data, *tdata = NULL, *cmd, *type, ch = '\0';
+ int rc, len;
+ bool trusted = false;
+
+ keyring_ref = make_key_ref(current_cred()->user->uid_keyring, 1);
+
+ len = integrity_read_file(key, &data);
+ if (len < 0)
+ return len;
+
+ swap(data[len - 1], ch);
+ if (strstr(data, "trusted"))
+ trusted = true;
+ swap(data[len - 1], ch);
+
+ rc = integrity_read_file(kmk, &tdata);
+ if (rc < 0)
+ goto out;
+
+ /* padd does not like \n - remove it*/
+ if (strchr(tdata, '\n'))
+ rc--;
+
+ if (trusted) {
+ /* we need 'load' keyword */
+ cmd = kmalloc(rc + 5, GFP_KERNEL);
+ if (!cmd)
+ goto out;
+
+ memcpy(cmd, "load ", 5);
+ memcpy(cmd + 5, tdata, rc);
+ rc += 5;
+ } else {
+ cmd = tdata;
+ }
+
+ key_ref = key_create_or_update(keyring_ref,
+ trusted ? "trusted" : "user", "kmk",
+ cmd, rc,
+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ),
+ KEY_ALLOC_NOT_IN_QUOTA);
+ if (trusted)
+ kfree(cmd);
+ type = trusted ? "trusted" : "user";
+ if (IS_ERR(key_ref)) {
+ rc = PTR_ERR(key_ref);
+ pr_err("problem loading EVM kmk (%s) (%d): %s\n",
+ type, rc, kmk);
+ goto out;
+ } else {
+ pr_notice("loaded EVM kmk (%s) %d': %s\n",
+ type, key_ref_to_ptr(key_ref)->serial, kmk);
+ key_ref_put(key_ref);
+ }
+
+ /* padd does not like \n - remove it*/
+ if (strchr(data, '\n'))
+ len--;
+
+ /* we need 'load' keyword */
+ cmd = kmalloc(len + 5, GFP_KERNEL);
+ if (!cmd)
+ goto out;
+
+ memcpy(cmd, "load ", 5);
+ memcpy(cmd + 5, data, len);
+
+ key_ref = key_create_or_update(keyring_ref,
+ "encrypted", EVMKEY, cmd, len + 5,
+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ),
+ KEY_ALLOC_NOT_IN_QUOTA);
+ kfree(cmd);
+ if (IS_ERR(key_ref)) {
+ rc = PTR_ERR(key_ref);
+ pr_err("problem loading EVM key (%d): %s\n", rc, key);
+ } else {
+ pr_notice("loaded EVM key %d': %s\n",
+ key_ref_to_ptr(key_ref)->serial, key);
+ key_ref_put(key_ref);
+ }
+
+out:
+ kfree(tdata);
+ kfree(data);
+ return rc;
+}
+#endif
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index d2c06d3..4808596 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -463,6 +463,7 @@ static int __init init_evm(void)
goto err;
}

+ evm_load_key("/etc/keys/evm-key", "/etc/keys/kmk");
evm_init_key();

return 0;
--
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/