hulk inclusion category: feature feature: digest-lists
---------------------------
This patch adds support in EVM to verify file metadata digest with digest lists. Metadata digest, calculated in the same way as for portable signatures, is searched in the digest lists only if the file has the security.evm xattr with type EVM_IMA_XATTR_DIGEST_LIST.
If found digest is marked as immutable, content and xattr/attr updates are not allowed. Otherwise, after update, an HMAC will be written to security.evm.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- security/integrity/evm/evm_crypto.c | 9 ++++-- security/integrity/evm/evm_main.c | 48 ++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 157efcc3ad6e..61082bff1645 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -158,7 +158,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, /* Don't include the inode or generation number in portable * signatures */ - if (type != EVM_XATTR_PORTABLE_DIGSIG) { + if (type != EVM_XATTR_PORTABLE_DIGSIG && + type != EVM_IMA_XATTR_DIGEST_LIST) { hmac_misc.ino = inode->i_ino; hmac_misc.generation = inode->i_generation; } @@ -175,7 +176,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, hmac_misc.mode = inode->i_mode; crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); if ((evm_hmac_attrs & EVM_ATTR_FSUUID) && - type != EVM_XATTR_PORTABLE_DIGSIG) + type != EVM_XATTR_PORTABLE_DIGSIG && + type != EVM_IMA_XATTR_DIGEST_LIST) crypto_shash_update(desc, &inode->i_sb->s_uuid.b[0], sizeof(inode->i_sb->s_uuid)); crypto_shash_final(desc, digest); @@ -289,7 +291,8 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode) return 0; return rc; } - if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) + if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG || + xattr_data->type == EVM_IMA_XATTR_DIGEST_LIST) rc = 1; else rc = 0; diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 2b55286edc49..ece39b80ca9c 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -140,6 +140,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, struct signature_v2_hdr *hdr; enum integrity_status evm_status = INTEGRITY_PASS; struct evm_digest digest; + struct ima_digest *found_digest; struct inode *inode; int rc, xattr_len, evm_immutable = 0;
@@ -225,6 +226,50 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, } } break; + case EVM_IMA_XATTR_DIGEST_LIST: + if (xattr_len < offsetof(struct signature_v2_hdr, keyid)) { + evm_status = INTEGRITY_FAIL; + goto out; + } + + hdr = (struct signature_v2_hdr *)xattr_data; + digest.hdr.algo = hdr->hash_algo; + rc = evm_calc_hash(dentry, xattr_name, xattr_value, + xattr_value_len, xattr_data->type, &digest); + if (rc) + break; + + found_digest = ima_lookup_digest(digest.digest, hdr->hash_algo, + COMPACT_METADATA); + if (!found_digest) { + rc = -ENOENT; + break; + } + + if (!ima_digest_allow(found_digest, IMA_APPRAISE)) { + rc = -EACCES; + break; + } + + if (ima_digest_is_immutable(found_digest)) { + evm_immutable = 1; + + if (iint) + iint->flags |= EVM_IMMUTABLE_DIGSIG; + evm_status = INTEGRITY_PASS_IMMUTABLE; + } else { + inode = d_backing_inode(dentry); + if (!IS_RDONLY(inode) && + !(inode->i_sb->s_readonly_remount) && + !IS_IMMUTABLE(inode)) { + rc = __vfs_removexattr(dentry, XATTR_NAME_EVM); + if (!rc) + evm_update_evmxattr(dentry, xattr_name, + xattr_value, + xattr_value_len); + } + } + break; default: rc = -EINVAL; break; @@ -461,7 +506,8 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, if (!xattr_value_len) return -EINVAL; if (xattr_data->type != EVM_IMA_XATTR_DIGSIG && - xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) + xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG && + xattr_data->type != EVM_IMA_XATTR_DIGEST_LIST) return -EPERM; } return evm_protect_xattr(dentry, xattr_name, xattr_value,