From: Roberto Sassu roberto.sassu@huawei.com
euleros inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I7QZ2M CVE: NA
-------------------------------------------------
IMA reads the hash algorithm from security.ima, if exists, so that a signature can be verified with the correct file digest.
This patch moves ima_read_xattr() and ima_get_hash_algo() to ima_main.c, so that the file digest in the measurement list or in the audit logs can be compared with a reference value calculated with a specific hash algorithm.
In addition, this patch also allows the usage of security.ima with type EVM_IMA_XATTR_DIGSIG and signature length zero, so that the xattr can be used just to specify the hash algorithm.
Signed-off-by: Roberto Sassu roberto.sassu@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/ima/ima.h | 4 ++ security/integrity/ima/ima_appraise.c | 7 ++++ security/integrity/ima/ima_main.c | 60 +++++++++++++++++++++++++++ 3 files changed, 71 insertions(+)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c29db699c..c47055661 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -324,10 +324,12 @@ int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode, void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, enum ima_hooks func); +#ifndef CONFIG_IMA_DIGEST_LIST enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value, int xattr_len); int ima_read_xattr(struct dentry *dentry, struct evm_ima_xattr_data **xattr_value, int xattr_len); +#endif /* CONFIG_IMA_DIGEST_LIST */
#else static inline int ima_check_blacklist(struct integrity_iint_cache *iint, @@ -366,6 +368,7 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c return INTEGRITY_UNKNOWN; }
+#ifndef CONFIG_IMA_DIGEST_LIST static inline enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len) { @@ -378,6 +381,7 @@ static inline int ima_read_xattr(struct dentry *dentry, { return 0; } +#endif
#endif /* CONFIG_IMA_APPRAISE */
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index bd54ff20f..d133c13ef 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -231,6 +231,7 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value, return ima_hash_algo; }
+#ifdef CONFIG_IMA_DIGEST_LIST int ima_read_xattr(struct dentry *dentry, struct evm_ima_xattr_data **xattr_value, int xattr_len) { @@ -242,6 +243,7 @@ int ima_read_xattr(struct dentry *dentry, ret = 0; return ret; } +#endif
/* * calc_file_id_hash - calculate the hash of the ima_file_id struct data @@ -501,6 +503,11 @@ int ima_appraise_measurement(enum ima_hooks func, if (!(inode->i_opflags & IOP_XATTR) && !try_modsig) return INTEGRITY_UNKNOWN;
+#ifdef CONFIG_IMA_DIGEST_LIST + if (xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG && + xattr_len == sizeof(struct signature_v2_hdr)) + rc = -ENODATA; +#endif /* If reading the xattr failed and there's no modsig, error out. */ if (rc <= 0 && !try_modsig) { if (rc && rc != -ENODATA) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index d66a0a364..1a1475077 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -153,6 +153,66 @@ static void ima_rdwr_violation_check(struct file *file, "invalid_pcr", "open_writers"); }
+#ifdef CONFIG_IMA_DIGEST_LIST +static enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value, + int xattr_len) +{ + struct signature_v2_hdr *sig; + enum hash_algo ret; + + if (!xattr_value || xattr_len < 2) + /* return default hash algo */ + return ima_hash_algo; + + switch (xattr_value->type) { + case IMA_VERITY_DIGSIG: + sig = (typeof(sig))xattr_value; + if (sig->version != 3 || xattr_len < sizeof(*sig) || + sig->hash_algo >= HASH_ALGO__LAST) + return ima_hash_algo; + return sig->hash_algo; + case EVM_IMA_XATTR_DIGSIG: + sig = (typeof(sig))xattr_value; + if (sig->version != 2 || xattr_len <= sizeof(*sig) + || sig->hash_algo >= HASH_ALGO__LAST) + return ima_hash_algo; + return sig->hash_algo; + case IMA_XATTR_DIGEST_NG: + /* first byte contains algorithm id */ + ret = xattr_value->data[0]; + if (ret < HASH_ALGO__LAST) + return ret; + break; + case IMA_XATTR_DIGEST: + /* this is for backward compatibility */ + if (xattr_len == 21) { + unsigned int zero = 0; + + if (!memcmp(&xattr_value->data[16], &zero, 4)) + return HASH_ALGO_MD5; + else + return HASH_ALGO_SHA1; + } else if (xattr_len == 17) + return HASH_ALGO_MD5; + break; + } + + /* return default hash algo */ + return ima_hash_algo; +} + +static int ima_read_xattr(struct dentry *dentry, + struct evm_ima_xattr_data **xattr_value, int xattr_len) +{ + int ret; + + ret = vfs_getxattr_alloc(&nop_mnt_idmap, dentry, XATTR_NAME_IMA, + (char **)xattr_value, xattr_len, GFP_NOFS); + if (ret == -EOPNOTSUPP) + ret = 0; + return ret; +} +#endif static void ima_check_last_writer(struct integrity_iint_cache *iint, struct inode *inode, struct file *file) {