From: Roberto Sassu roberto.sassu@huawei.com
hulk inclusion category: feature feature: IMA Digest Lists extension bugzilla: 46797
-------------------------------------------------
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: Zhou Shuiqingzhoushuiqing2@huawei.com --- security/integrity/ima/ima.h | 17 -------- security/integrity/ima/ima_appraise.c | 16 ++------ security/integrity/ima/ima_main.c | 57 +++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 29 deletions(-)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c29db699c996..8b869e2951d8 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -324,10 +324,6 @@ 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); -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);
#else static inline int ima_check_blacklist(struct integrity_iint_cache *iint, @@ -366,19 +362,6 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c return INTEGRITY_UNKNOWN; }
-static inline enum hash_algo -ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len) -{ - return ima_hash_algo; -} - -static inline int ima_read_xattr(struct dentry *dentry, - struct evm_ima_xattr_data **xattr_value, - int xattr_len) -{ - return 0; -} - #endif /* CONFIG_IMA_APPRAISE */
#ifdef CONFIG_IMA_APPRAISE_MODSIG diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 08ae5d7faa1d..274a0fec59f5 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -228,18 +228,6 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value, return ima_hash_algo; }
-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; -} - /* * calc_file_id_hash - calculate the hash of the ima_file_id struct data * @type: xattr type [enum evm_ima_xattr_type] @@ -498,6 +486,10 @@ int ima_appraise_measurement(enum ima_hooks func, if (!(inode->i_opflags & IOP_XATTR) && !try_modsig) return INTEGRITY_UNKNOWN;
+ if (xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG && + xattr_len == sizeof(struct signature_v2_hdr)) + rc = -ENODATA; + /* 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 d66a0a36415e..847be55912eb 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -153,6 +153,63 @@ static void ima_rdwr_violation_check(struct file *file, "invalid_pcr", "open_writers"); }
+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; +} static void ima_check_last_writer(struct integrity_iint_cache *iint, struct inode *inode, struct file *file) {