提交 f51e0ce9 编写于 作者: R Roberto Sassu 提交者: Zheng Zengkai

evm: Add support for digest lists of metadata

hulk inclusion
category: feature
feature: IMA Digest Lists extension
bugzilla: 46797

-------------------------------------------------

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 the found digest is marked as immutable, content and xattr/attr updates
are not allowed. Otherwise, after verification, the existing security.evm
with the new type will be replaced with an HMAC, similarly to non-portable
signatures.
Signed-off-by: NRoberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: NTianxing Zhang <zhangtianxing3@huawei.com>
Reviewed-by: NJason Yan <yanaijie@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 a44c2ae6
...@@ -155,7 +155,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, ...@@ -155,7 +155,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
/* Don't include the inode or generation number in portable /* Don't include the inode or generation number in portable
* signatures * 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.ino = inode->i_ino;
hmac_misc.generation = inode->i_generation; hmac_misc.generation = inode->i_generation;
} }
...@@ -172,7 +173,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, ...@@ -172,7 +173,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
hmac_misc.mode = inode->i_mode; hmac_misc.mode = inode->i_mode;
crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
if ((evm_hmac_attrs & EVM_ATTR_FSUUID) && 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, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE); crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
crypto_shash_final(desc, digest); crypto_shash_final(desc, digest);
} }
...@@ -285,7 +287,8 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode) ...@@ -285,7 +287,8 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
return 0; return 0;
return rc; 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; rc = 1;
else else
rc = 0; rc = 0;
......
...@@ -110,7 +110,7 @@ static bool evm_ignore_error_safe(enum integrity_status evm_status) ...@@ -110,7 +110,7 @@ static bool evm_ignore_error_safe(enum integrity_status evm_status)
return true; return true;
} }
static int evm_find_protected_xattrs(struct dentry *dentry) static int evm_find_protected_xattrs(struct dentry *dentry, int *ima_present)
{ {
struct inode *inode = d_backing_inode(dentry); struct inode *inode = d_backing_inode(dentry);
struct xattr_list *xattr; struct xattr_list *xattr;
...@@ -127,6 +127,8 @@ static int evm_find_protected_xattrs(struct dentry *dentry) ...@@ -127,6 +127,8 @@ static int evm_find_protected_xattrs(struct dentry *dentry)
continue; continue;
return error; return error;
} }
if (!strcmp(xattr->name, XATTR_NAME_IMA))
*ima_present = 1;
count++; count++;
} }
...@@ -155,9 +157,14 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -155,9 +157,14 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
struct evm_ima_xattr_data *xattr_data = NULL; struct evm_ima_xattr_data *xattr_data = NULL;
struct signature_v2_hdr *hdr; struct signature_v2_hdr *hdr;
enum integrity_status evm_status = INTEGRITY_PASS; enum integrity_status evm_status = INTEGRITY_PASS;
enum integrity_status saved_evm_status = INTEGRITY_UNKNOWN;
struct evm_digest digest; struct evm_digest digest;
struct ima_digest *found_digest;
struct inode *inode; struct inode *inode;
int rc, xattr_len, evm_immutable = 0; struct signature_v2_hdr evm_fake_xattr = {
.type = EVM_IMA_XATTR_DIGEST_LIST,
.version = 2, .hash_algo = HASH_ALGO_SHA256 };
int rc, xattr_len, evm_immutable = 0, ima_present = 0;
if (iint && (iint->evm_status == INTEGRITY_PASS || if (iint && (iint->evm_status == INTEGRITY_PASS ||
iint->evm_status == INTEGRITY_PASS_IMMUTABLE)) iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
...@@ -171,7 +178,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -171,7 +178,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
if (rc <= 0) { if (rc <= 0) {
evm_status = INTEGRITY_FAIL; evm_status = INTEGRITY_FAIL;
if (rc == -ENODATA) { if (rc == -ENODATA) {
rc = evm_find_protected_xattrs(dentry); rc = evm_find_protected_xattrs(dentry, &ima_present);
if (rc > 0) if (rc > 0)
evm_status = INTEGRITY_NOLABEL; evm_status = INTEGRITY_NOLABEL;
else if (rc == 0) else if (rc == 0)
...@@ -179,7 +186,20 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -179,7 +186,20 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
} else if (rc == -EOPNOTSUPP) { } else if (rc == -EOPNOTSUPP) {
evm_status = INTEGRITY_UNKNOWN; evm_status = INTEGRITY_UNKNOWN;
} }
goto out; /* IMA added a fake xattr, set also EVM fake xattr */
if (!ima_present && xattr_name &&
!strcmp(xattr_name, XATTR_NAME_IMA) &&
xattr_value_len > 2) {
evm_fake_xattr.hash_algo =
((struct evm_ima_xattr_data *)xattr_value)->data[0];
xattr_data =
(struct evm_ima_xattr_data *)&evm_fake_xattr;
rc = sizeof(evm_fake_xattr);
}
if (xattr_data != (struct evm_ima_xattr_data *)&evm_fake_xattr)
goto out;
saved_evm_status = evm_status;
} }
xattr_len = rc; xattr_len = rc;
...@@ -237,12 +257,54 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -237,12 +257,54 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
} }
} }
break; break;
case EVM_IMA_XATTR_DIGEST_LIST:
/* At this point, we cannot determine whether metadata are
* immutable or not. However, it is safe to return the
* fail_immutable error, as HMAC will not be created for this
* security.evm type.
*/
evm_immutable = 1;
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)) {
if (iint)
iint->flags |= EVM_IMMUTABLE_DIGSIG;
evm_status = INTEGRITY_PASS_IMMUTABLE;
} else {
evm_status = INTEGRITY_PASS;
}
break;
default: default:
rc = -EINVAL; rc = -EINVAL;
break; break;
} }
if (rc) { if (rc && xattr_data == (struct evm_ima_xattr_data *)&evm_fake_xattr) {
evm_status = saved_evm_status;
} else if (rc) {
evm_status = INTEGRITY_NOXATTRS; evm_status = INTEGRITY_NOXATTRS;
if (rc != -ENODATA) if (rc != -ENODATA)
evm_status = evm_immutable ? evm_status = evm_immutable ?
...@@ -251,7 +313,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -251,7 +313,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
out: out:
if (iint) if (iint)
iint->evm_status = evm_status; iint->evm_status = evm_status;
kfree(xattr_data); if (xattr_data != (struct evm_ima_xattr_data *)&evm_fake_xattr)
kfree(xattr_data);
return evm_status; return evm_status;
} }
...@@ -501,7 +564,8 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, ...@@ -501,7 +564,8 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
if (!xattr_value_len) if (!xattr_value_len)
return -EINVAL; return -EINVAL;
if (xattr_data->type != EVM_IMA_XATTR_DIGSIG && 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 -EPERM;
} }
return evm_protect_xattr(dentry, xattr_name, xattr_value, return evm_protect_xattr(dentry, xattr_name, xattr_value,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册