From: Roberto Sassu roberto.sassu@huawei.com
euleros inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I7QZ2M CVE: NA
-------------------------------------------------
Commit 5feeb61183dd ("evm: Allow non-SHA1 digital signatures") introduced the possibility to use different hash algorithm for signatures, but kept the algorithm for the HMAC hard-coded (SHA1). Switching to a different algorithm for HMAC would require to change the code in different places.
This patch introduces a new global variable called evm_hash_algo, and consistently uses it whenever EVM perform HMAC-related operations. It also introduces a new kernel configuration option called CONFIG_EVM_DEFAULT_HASH so that evm_hash_algo can be defined at kernel compilation time.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com Acked-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Tianxing Zhang zhangtianxing3@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Signed-off-by: zhoushuiqing zhoushuiqing2@huawei.com --- security/integrity/evm/Kconfig | 32 +++++++++++++++++++++++++++++ security/integrity/evm/evm.h | 3 +++ security/integrity/evm/evm_crypto.c | 31 +++++++++++++++++++++++++++- security/integrity/evm/evm_main.c | 26 +++++++++++++++++++++++ security/integrity/integrity.h | 4 ++++ 5 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index a6e19d23e..844f2686c 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -13,6 +13,38 @@ config EVM
If you are unsure how to answer this question, answer N.
+choice + prompt "Default EVM hash algorithm" + default EVM_DEFAULT_HASH_SHA256 + depends on EVM + help + Select the default hash algorithm used for the HMAC. + + config EVM_DEFAULT_HASH_SHA1 + bool "SHA1 (default)" + depends on CRYPTO_SHA1=y + + config EVM_DEFAULT_HASH_SHA256 + bool "SHA256" + depends on CRYPTO_SHA256=y + + config EVM_DEFAULT_HASH_SHA512 + bool "SHA512" + depends on CRYPTO_SHA512=y + + config EVM_DEFAULT_HASH_WP512 + bool "WP512" + depends on CRYPTO_WP512=y +endchoice + +config EVM_DEFAULT_HASH + string + depends on EVM + default "sha1" if EVM_DEFAULT_HASH_SHA1 + default "sha256" if EVM_DEFAULT_HASH_SHA256 + default "sha512" if EVM_DEFAULT_HASH_SHA512 + default "wp512" if EVM_DEFAULT_HASH_WP512 + config EVM_ATTR_FSUUID bool "FSUUID (version 2)" default y diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index f8b8c5004..48bfc7d18 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -33,6 +33,9 @@ struct xattr_list { };
extern int evm_initialized; +#ifdef CONFIG_IMA_DIGEST_LIST +extern enum hash_algo evm_hash_algo; +#endif
#define EVM_ATTR_FSUUID 0x0001
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index f3835b477..3831d9dc4 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -35,7 +35,11 @@ static DEFINE_MUTEX(mutex);
static unsigned long evm_set_key_flags;
+#ifdef CONFIG_IMA_DIGEST_LIST +enum hash_algo evm_hash_algo __ro_after_init = HASH_ALGO_SHA1; +#else static const char evm_hmac[] = "hmac(sha1)"; +#endif
/** * evm_set_key() - set EVM HMAC key from the kernel @@ -76,7 +80,14 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo) long rc; const char *algo; struct crypto_shash **tfm, *tmp_tfm; +#ifdef CONFIG_IMA_DIGEST_LIST + char evm_hmac[CRYPTO_MAX_ALG_NAME]; +#endif struct shash_desc *desc; +#ifdef CONFIG_IMA_DIGEST_LIST + snprintf(evm_hmac, sizeof(evm_hmac), "hmac(%s)", + CONFIG_EVM_DEFAULT_HASH); +#endif
if (type == EVM_XATTR_HMAC) { if (!(evm_initialized & EVM_INIT_HMAC)) { @@ -384,8 +395,11 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, return rc; if (rc) return -EPERM; - +#ifdef CONFIG_IMA_DIGEST_LIST + data.hdr.algo = evm_hash_algo; +#else data.hdr.algo = HASH_ALGO_SHA1; +#endif rc = evm_calc_hmac(dentry, xattr_name, xattr_value, xattr_value_len, &data); if (rc == 0) { @@ -393,7 +407,12 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry, XATTR_NAME_EVM, &data.hdr.xattr.data[1], +#ifdef CONFIG_IMA_DIGEST_LIST + hash_digest_size[evm_hash_algo] + 1, + 0); +#else SHA1_DIGEST_SIZE + 1, 0); +#endif } else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) { rc = __vfs_removexattr(&nop_mnt_idmap, dentry, XATTR_NAME_EVM); } @@ -405,7 +424,11 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, { struct shash_desc *desc;
+#ifdef CONFIG_IMA_DIGEST_LIST + desc = init_desc(EVM_XATTR_HMAC, evm_hash_algo); +#else desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1); +#endif if (IS_ERR(desc)) { pr_info("init_desc failed\n"); return PTR_ERR(desc); @@ -417,9 +440,15 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, return 0; }
+#ifdef CONFIG_IMA_DIGEST_LIST +/* + * Get the key from the TPM for the HMAC + */ +#else /* * Get the key from the TPM for the SHA1-HMAC */ +#endif int evm_init_key(void) { struct key *evm_key; diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 404858623..60545c6c5 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -260,18 +260,30 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, /* check value type */ switch (xattr_data->type) { case EVM_XATTR_HMAC: +#ifdef CONFIG_IMA_DIGEST_LIST + if (xattr_len != hash_digest_size[evm_hash_algo] + 1) { +#else if (xattr_len != sizeof(struct evm_xattr)) { +#endif evm_status = INTEGRITY_FAIL; goto out; }
+#ifdef CONFIG_IMA_DIGEST_LIST + digest.hdr.algo = evm_hash_algo; +#else digest.hdr.algo = HASH_ALGO_SHA1; +#endif rc = evm_calc_hmac(dentry, xattr_name, xattr_value, xattr_value_len, &digest); if (rc) break; rc = crypto_memneq(xattr_data->data, digest.digest, +#ifdef CONFIG_IMA_DIGEST_LIST + hash_digest_size[evm_hash_algo]); +#else SHA1_DIGEST_SIZE); +#endif if (rc) rc = -EINVAL; break; @@ -996,7 +1008,11 @@ int evm_inode_init_security(struct inode *inode, goto out;
evm_xattr->value = xattr_data; +#ifdef CONFIG_IMA_DIGEST_LIST + evm_xattr->value_len = hash_digest_size[evm_hash_algo] + 1; +#else evm_xattr->value_len = sizeof(*xattr_data); +#endif evm_xattr->name = XATTR_EVM_SUFFIX; return 0; out: @@ -1018,9 +1034,19 @@ void __init evm_load_x509(void)
static int __init init_evm(void) { +#ifdef CONFIG_IMA_DIGEST_LIST + int error, i; +#else int error; +#endif struct list_head *pos, *q;
+#ifdef CONFIG_IMA_DIGEST_LIST + i = match_string(hash_algo_name, HASH_ALGO__LAST, + CONFIG_EVM_DEFAULT_HASH); + if (i >= 0) + evm_hash_algo = i; +#endif evm_init_config();
error = integrity_init_keyring(INTEGRITY_KEYRING_EVM); diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 54f75738f..98ae8f9e7 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -104,7 +104,11 @@ struct evm_ima_xattr_data { /* Only used in the EVM HMAC code. */ struct evm_xattr { struct evm_ima_xattr_data data; +#ifdef CONFIG_IMA_DIGEST_LIST + u8 digest[SHA512_DIGEST_SIZE]; +#else u8 digest[SHA1_DIGEST_SIZE]; +#endif } __packed;
#define IMA_MAX_DIGEST_SIZE HASH_MAX_DIGESTSIZE