summaryrefslogtreecommitdiff
path: root/security/integrity/evm/evm_crypto.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-16 08:54:12 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-16 08:54:12 +0300
commitf91e654474d413201ae578820fb63f8a811f6c4e (patch)
tree7f32d5757381b3371dbf095510622472c7d3aa43 /security/integrity/evm/evm_crypto.c
parentc715ebeb0303b196f17376f189ae4e168d98b563 (diff)
parent3dd0f18c70d94ca2432c78c5735744429f071b0b (diff)
downloadlinux-f91e654474d413201ae578820fb63f8a811f6c4e.tar.xz
Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull integrity updates from James Morris: "This adds support for EVM signatures based on larger digests, contains a new audit record AUDIT_INTEGRITY_POLICY_RULE to differentiate the IMA policy rules from the IMA-audit messages, addresses two deadlocks due to either loading or searching for crypto algorithms, and cleans up the audit messages" * 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: EVM: fix return value check in evm_write_xattrs() integrity: prevent deadlock during digsig verification. evm: Allow non-SHA1 digital signatures evm: Don't deadlock if a crypto algorithm is unavailable integrity: silence warning when CONFIG_SECURITYFS is not enabled ima: Differentiate auditing policy rules from "audit" actions ima: Do not audit if CONFIG_INTEGRITY_AUDIT is not set ima: Use audit_log_format() rather than audit_log_string() ima: Call audit_log_string() rather than logging it untrusted
Diffstat (limited to 'security/integrity/evm/evm_crypto.c')
-rw-r--r--security/integrity/evm/evm_crypto.c50
1 files changed, 27 insertions, 23 deletions
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index b60524310855..8a3905bb02c7 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -21,6 +21,7 @@
#include <linux/evm.h>
#include <keys/encrypted-type.h>
#include <crypto/hash.h>
+#include <crypto/hash_info.h>
#include "evm.h"
#define EVMKEY "evm-key"
@@ -29,7 +30,7 @@ static unsigned char evmkey[MAX_KEY_SIZE];
static int evmkey_len = MAX_KEY_SIZE;
struct crypto_shash *hmac_tfm;
-struct crypto_shash *hash_tfm;
+static struct crypto_shash *evm_tfm[HASH_ALGO__LAST];
static DEFINE_MUTEX(mutex);
@@ -38,7 +39,6 @@ static DEFINE_MUTEX(mutex);
static unsigned long evm_set_key_flags;
static char * const evm_hmac = "hmac(sha1)";
-static char * const evm_hash = "sha1";
/**
* evm_set_key() - set EVM HMAC key from the kernel
@@ -74,10 +74,10 @@ busy:
}
EXPORT_SYMBOL_GPL(evm_set_key);
-static struct shash_desc *init_desc(char type)
+static struct shash_desc *init_desc(char type, uint8_t hash_algo)
{
long rc;
- char *algo;
+ const char *algo;
struct crypto_shash **tfm;
struct shash_desc *desc;
@@ -89,15 +89,16 @@ static struct shash_desc *init_desc(char type)
tfm = &hmac_tfm;
algo = evm_hmac;
} else {
- tfm = &hash_tfm;
- algo = evm_hash;
+ tfm = &evm_tfm[hash_algo];
+ algo = hash_algo_name[hash_algo];
}
if (*tfm == NULL) {
mutex_lock(&mutex);
if (*tfm)
goto out;
- *tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC);
+ *tfm = crypto_alloc_shash(algo, 0,
+ CRYPTO_ALG_ASYNC | CRYPTO_NOLOAD);
if (IS_ERR(*tfm)) {
rc = PTR_ERR(*tfm);
pr_err("Can not allocate %s (reason: %ld)\n", algo, rc);
@@ -186,10 +187,10 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
* each xattr, but attempt to re-use the previously allocated memory.
*/
static int evm_calc_hmac_or_hash(struct dentry *dentry,
- const char *req_xattr_name,
- const char *req_xattr_value,
- size_t req_xattr_value_len,
- char type, char *digest)
+ const char *req_xattr_name,
+ const char *req_xattr_value,
+ size_t req_xattr_value_len,
+ uint8_t type, struct evm_digest *data)
{
struct inode *inode = d_backing_inode(dentry);
struct xattr_list *xattr;
@@ -204,10 +205,12 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
inode->i_sb->s_user_ns != &init_user_ns)
return -EOPNOTSUPP;
- desc = init_desc(type);
+ desc = init_desc(type, data->hdr.algo);
if (IS_ERR(desc))
return PTR_ERR(desc);
+ data->hdr.length = crypto_shash_digestsize(desc->tfm);
+
error = -ENODATA;
list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) {
bool is_ima = false;
@@ -239,7 +242,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
if (is_ima)
ima_present = true;
}
- hmac_add_misc(desc, inode, type, digest);
+ hmac_add_misc(desc, inode, type, data->digest);
/* Portable EVM signatures must include an IMA hash */
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
@@ -252,18 +255,18 @@ out:
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value, size_t req_xattr_value_len,
- char *digest)
+ struct evm_digest *data)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
- req_xattr_value_len, EVM_XATTR_HMAC, digest);
+ req_xattr_value_len, EVM_XATTR_HMAC, data);
}
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value, size_t req_xattr_value_len,
- char type, char *digest)
+ char type, struct evm_digest *data)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
- req_xattr_value_len, type, digest);
+ req_xattr_value_len, type, data);
}
static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
@@ -303,7 +306,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len)
{
struct inode *inode = d_backing_inode(dentry);
- struct evm_ima_xattr_data xattr_data;
+ struct evm_digest data;
int rc = 0;
/*
@@ -316,13 +319,14 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
if (rc)
return -EPERM;
+ data.hdr.algo = HASH_ALGO_SHA1;
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
- xattr_value_len, xattr_data.digest);
+ xattr_value_len, &data);
if (rc == 0) {
- xattr_data.type = EVM_XATTR_HMAC;
+ data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
- &xattr_data,
- sizeof(xattr_data), 0);
+ &data.hdr.xattr.data[1],
+ SHA1_DIGEST_SIZE + 1, 0);
} else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) {
rc = __vfs_removexattr(dentry, XATTR_NAME_EVM);
}
@@ -334,7 +338,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
{
struct shash_desc *desc;
- desc = init_desc(EVM_XATTR_HMAC);
+ desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1);
if (IS_ERR(desc)) {
pr_info("init_desc failed\n");
return PTR_ERR(desc);